[Mesa-dev] [PATCH] mesa: fixes for DrawRangeElements[BaseVertex] index validation

Jose Fonseca jfonseca at vmware.com
Sat Feb 4 05:14:37 PST 2012



----- Original Message -----
> 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?

I'm OK with passing the ranges unmodified to the drivers. And let them handle them. But the drivers (or the hardware) needs to be robust against fetching vertices beyond the vertex buffer's size. I'm not sure if they all do that.

Jose


More information about the mesa-dev mailing list