[Mesa-dev] [PATCH] mesa: fixes for DrawRangeElements[BaseVertex] index validation
Kenneth Graunke
kenneth at whitecape.org
Sat Feb 4 03:40:09 PST 2012
On 01/27/2012 06:00 PM, Roland Scheidegger wrote:
> in check_index_bounds the comparison needs to be "greater equal" since
> contrary to the name _MaxElement is the count of the array.
> In vbo_exec_DrawRangeElementsBaseVertex, take into account the basevertex.
> As far as I can tell it is completely ok (though maybe stupid) to have
> start/end of 100/199, with _MaxElement being 100, if the basevertex
> is -100 (since the start/end are prior to adding basevertex). The opposite
> is also true (0/99 is not ok if _MaxElement is 100 and and basevertex is 100).
> Previously we would have issued a warning in such cases and worse probably
> "fixed" end to a bogus value.
> Totally untested, found by code inspection when looking at bug 40361 (which
> seems unrelated after all).
> ---
> src/mesa/main/api_validate.c | 2 +-
> src/mesa/vbo/vbo_exec_array.c | 30 +++++++++++++++++++-----------
> 2 files changed, 20 insertions(+), 12 deletions(-)
>
> diff --git a/src/mesa/main/api_validate.c b/src/mesa/main/api_validate.c
> index b6871d0..1ae491f 100644
> --- a/src/mesa/main/api_validate.c
> +++ b/src/mesa/main/api_validate.c
> @@ -187,7 +187,7 @@ check_index_bounds(struct gl_context *ctx, GLsizei count, GLenum type,
> vbo_get_minmax_indices(ctx,&prim,&ib,&min,&max, 1);
>
> if ((int)(min + basevertex)< 0 ||
> - max + basevertex> ctx->Array.ArrayObj->_MaxElement) {
> + max + basevertex>= ctx->Array.ArrayObj->_MaxElement) {
> /* the max element is out of bounds of one or more enabled arrays */
> _mesa_warning(ctx, "glDrawElements() index=%u is out of bounds (max=%u)",
> max, ctx->Array.ArrayObj->_MaxElement);
I might split this hunk out into a separate patch. This hunk is:
Reviewed-by: Kenneth Graunke <kenneth at whitecape.org>
And yeah, _MaxElement does make me think "index of the last element"
(N-1), not "the total number of elements" (N). I'm not a fan of the name.
> diff --git a/src/mesa/vbo/vbo_exec_array.c b/src/mesa/vbo/vbo_exec_array.c
> index 9861b21..3e0fe20 100644
> --- a/src/mesa/vbo/vbo_exec_array.c
> +++ b/src/mesa/vbo/vbo_exec_array.c
> @@ -885,17 +885,18 @@ vbo_exec_DrawRangeElementsBaseVertex(GLenum mode,
> end = MIN2(end, 0xffff);
> }
>
> - if (end>= ctx->Array.ArrayObj->_MaxElement) {
> + if ((int)(start + basevertex)< 0 ||
> + end + basevertex>= ctx->Array.ArrayObj->_MaxElement) {
> /* the max element is out of bounds of one or more enabled arrays */
> warnCount++;
>
> if (warnCount< 10) {
> - _mesa_warning(ctx, "glDraw[Range]Elements(start %u, end %u, count %d, "
> - "type 0x%x, indices=%p)\n"
> + _mesa_warning(ctx, "glDrawRangeElements[BaseVertex](start %u, end %u, count %d, "
> + "type 0x%x, indices=%p, base %d)\n"
> "\tend is out of bounds (max=%u) "
> "Element Buffer %u (size %d)\n"
> "\tThis should probably be fixed in the application.",
> - start, end, count, type, indices,
> + start, end, count, type, indices, basevertex,
> ctx->Array.ArrayObj->_MaxElement - 1,
> ctx->Array.ArrayObj->ElementArrayBufferObj->Name,
> (int) ctx->Array.ArrayObj->ElementArrayBufferObj->Size);
> @@ -913,14 +914,14 @@ vbo_exec_DrawRangeElementsBaseVertex(GLenum mode,
> if (0) {
> GLuint max = _mesa_max_buffer_index(ctx, count, type, indices,
> ctx->Array.ArrayObj->ElementArrayBufferObj);
> - if (max>= ctx->Array.ArrayObj->_MaxElement) {
> + if (max + basevertex>= ctx->Array.ArrayObj->_MaxElement) {
> if (warnCount< 10) {
> - _mesa_warning(ctx, "glDraw[Range]Elements(start %u, end %u, "
> - "count %d, type 0x%x, indices=%p)\n"
> + _mesa_warning(ctx, "glDrawRangeElements[BaseVertex](start %u, end %u, "
> + "count %d, type 0x%x, indices=%p, base %d)\n"
> "\tindex=%u is out of bounds (max=%u) "
> "Element Buffer %u (size %d)\n"
> "\tSkipping the glDrawRangeElements() call",
> - start, end, count, type, indices, max,
> + start, end, count, type, indices, basevertex, max,
> ctx->Array.ArrayObj->_MaxElement - 1,
> ctx->Array.ArrayObj->ElementArrayBufferObj->Name,
> (int) ctx->Array.ArrayObj->ElementArrayBufferObj->Size);
> @@ -928,13 +929,20 @@ vbo_exec_DrawRangeElementsBaseVertex(GLenum mode,
> }
> /* XXX we could also find the min index and compare to 'start'
> * to see if start is correct. But it's more likely to get the
> - * upper bound wrong.
> + * upper bound wrong, at least for the non-BaseVertex variant...
> */
> }
Ugh, this is hard to think through...
If basevertex < 0, end + basevertex might actually be in the array while
'end' would not. We currently clamp in this case, and I think I agree
with you that we shouldn't.
If basevertex > 0, end might be within the array yet end + basevertex
might not. So, this would make us clamp in a case where we currently don't.
Page 33 of the OpenGL 3.2 Core spec mentions:
"For DrawRangeElementsBaseVertex, the index values must lie between
start and end inclusive, prior to adding the basevertex offset."
which seems relevant, but probably isn't. This is about clamping 'end'
itself to avoid array overflow, not the index values themselves.
Since we'll be adding basevertex later, end + basevertex would
indeed be outside of the array, which is bad.
So...I think this is correct...and worth fixing...
> /* Set 'end' to the max possible legal value */
> assert(ctx->Array.ArrayObj->_MaxElement>= 1);
> - end = ctx->Array.ArrayObj->_MaxElement - 1;
> + /* XXX Could have positive uint overflow for both start and end too. */
> + if ((int)(ctx->Array.ArrayObj->_MaxElement - 1 - basevertex)< 0) {
> + return;
> + }
> + end = ctx->Array.ArrayObj->_MaxElement - 1 - basevertex;
> + if ((int)(start + basevertex)< 0) {
> + start = -basevertex;
> + }
>
> if (end< start) {
> return;
I don't think we want to include basevertex when adjusting 'start' and
'end'. The final call to vbo_validated_drawrangeelements already passes
basevertex, so I'm pretty sure this will adjust it twice.
Also, I just sent out a patch (vbo: Ignore invalid element ranges if
fixing 'end' breaks 'start') and realized it'll conflict here.
I'm leaning toward dropping this code that clamps "end" altogether. It's
awfully dodgy already, and trying to correctly compensate for basevertex
is pretty much destroying any faith I had left in it working properly.
After all, glDrawRangeElementsBaseVertex is just an optimized version of
glDrawElementsBaseVertex, so it should be totally safe to just drop the
range entirely. Considering that we've already proven the range is
insane, that seems like the safest option. Plus...optimizing broken
calls? Really?
> @@ -942,7 +950,7 @@ vbo_exec_DrawRangeElementsBaseVertex(GLenum mode,
> }
>
> if (0) {
> - printf("glDraw[Range]Elements{,BaseVertex}"
> + printf("glDrawRangeElements{,BaseVertex}"
> "(start %u, end %u, type 0x%x, count %d) ElemBuf %u, "
> "base %d\n",
> start, end, type, count,
More information about the mesa-dev
mailing list