[Mesa-dev] [PATCH 3/3] mesa: generate GL_INVALID_VALUE when bufSize < 0

nobled nobled at dreamwidth.org
Sun Apr 22 01:44:04 PDT 2012


Though not explicit in the GL_ARB_robustness extension,
the GL standard says:

  If a negative number is provided where an argument of type sizei or
  sizeiptr is specified, the error INVALID_VALUE is generated.

While the extension says that GL_INVALID_OPERATION is given
when the required space is "greater than <bufSize>", and this
would be technically true for all negative values, defer to the
above language. This error check seems to apply even when a PBO
is bound, while insufficient but non-negative values of bufSize
are ignored.

This also fixes a bug in _mesa_validate_pbo_access() where the
signed value clientMemSize was blindly cast to an unsigned value.
When bufSize/clientMemSize were negative, it would be cast to
a value greater than INT_MAX and no error would have been given,
not even the incorrect GL_INVALID_OPERATION. Oops.

NOTE: This is a candidate for the 8.0 branch.
---
 src/mesa/main/eval.c            |   18 ++++++++++++++++++
 src/mesa/main/pbo.c             |   15 +++++++++++++++
 src/mesa/main/pixel.c           |    6 ++++++
 src/mesa/main/readpix.c         |    6 ++++++
 src/mesa/main/texgetimage.c     |   16 +++++++++++++++-
 src/mesa/main/uniform_query.cpp |    9 ++++++++-
 6 files changed, 68 insertions(+), 2 deletions(-)

diff --git a/src/mesa/main/eval.c b/src/mesa/main/eval.c
index e651715..8c25295 100644
--- a/src/mesa/main/eval.c
+++ b/src/mesa/main/eval.c
@@ -563,6 +563,12 @@ _mesa_GetnMapdvARB( GLenum target, GLenum query,
GLsizei bufSize, GLdouble *v )
       return;
    }

+   if (bufSize < 0) {
+      _mesa_error( ctx, GL_INVALID_VALUE,
+                  "glGetnMapdvARB(bufSize = %d)", bufSize );
+      return;
+   }
+
    map1d = get_1d_map(ctx, target);
    map2d = get_2d_map(ctx, target);
    ASSERT(map1d || map2d);
@@ -655,6 +661,12 @@ _mesa_GetnMapfvARB( GLenum target, GLenum query,
GLsizei bufSize, GLfloat *v )
       return;
    }

+   if (bufSize < 0) {
+      _mesa_error( ctx, GL_INVALID_VALUE,
+                  "glGetnMapfvARB(bufSize = %d)", bufSize );
+      return;
+   }
+
    map1d = get_1d_map(ctx, target);
    map2d = get_2d_map(ctx, target);
    ASSERT(map1d || map2d);
@@ -749,6 +761,12 @@ _mesa_GetnMapivARB( GLenum target, GLenum query,
GLsizei bufSize, GLint *v )
       return;
    }

+   if (bufSize < 0) {
+      _mesa_error( ctx, GL_INVALID_VALUE,
+                  "glGetnMapivARB(bufSize = %d)", bufSize );
+      return;
+   }
+
    map1d = get_1d_map(ctx, target);
    map2d = get_2d_map(ctx, target);
    ASSERT(map1d || map2d);
diff --git a/src/mesa/main/pbo.c b/src/mesa/main/pbo.c
index d8fa919..0fe5394 100644
--- a/src/mesa/main/pbo.c
+++ b/src/mesa/main/pbo.c
@@ -71,6 +71,9 @@ _mesa_validate_pbo_access(GLuint dimensions,
    /* unsigned, to detect overflow/wrap-around */
    uintptr_t start, end, offset, size;

+   /* This should be error-checked by all callers beforehand. */
+   assert(clientMemSize >= 0);
+
    /* If no PBO is bound, 'ptr' is a pointer to client memory containing
       'clientMemSize' bytes.
       If a PBO is bound, 'ptr' is an offset into the bound PBO.
@@ -180,6 +183,12 @@ _mesa_map_validate_pbo_source(struct gl_context *ctx,
 {
    ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3);

+   if (clientMemSize < 0) {
+      _mesa_error( ctx, GL_INVALID_VALUE,
+                  "%s(bufSize = %d)", where, clientMemSize );
+      return NULL;
+   }
+
    if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
                                   format, type, clientMemSize, ptr)) {
       if (_mesa_is_bufferobj(unpack->BufferObj)) {
@@ -276,6 +285,12 @@ _mesa_map_validate_pbo_dest(struct gl_context *ctx,
 {
    ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3);

+   if (clientMemSize < 0) {
+      _mesa_error( ctx, GL_INVALID_VALUE,
+                  "%s(bufSize = %d)", where, clientMemSize );
+      return NULL;
+   }
+
    if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
                                   format, type, clientMemSize, ptr)) {
       if (_mesa_is_bufferobj(unpack->BufferObj)) {
diff --git a/src/mesa/main/pixel.c b/src/mesa/main/pixel.c
index 450c936..be6a19d 100644
--- a/src/mesa/main/pixel.c
+++ b/src/mesa/main/pixel.c
@@ -153,6 +153,12 @@ validate_pbo_access(struct gl_context *ctx,
 {
    GLboolean ok;

+   if (clientMemSize < 0) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "glGetnPixelMap*vARB(bufSize = %d)", clientMemSize);
+      return GL_FALSE;
+   }
+
    /* Note, need to use DefaultPacking and Unpack's buffer object */
    _mesa_reference_buffer_object(ctx,
                                  &ctx->DefaultPacking.BufferObj,
diff --git a/src/mesa/main/readpix.c b/src/mesa/main/readpix.c
index 31acfcb..d4fcc56 100644
--- a/src/mesa/main/readpix.c
+++ b/src/mesa/main/readpix.c
@@ -690,6 +690,12 @@ _mesa_ReadnPixelsARB( GLint x, GLint y, GLsizei
width, GLsizei height,
       return;
    }

+   if (bufSize < 0) {
+      _mesa_error( ctx, GL_INVALID_VALUE,
+                  "glReadnPixelsARB(bufSize = %d)", bufSize );
+      return;
+   }
+
    if (ctx->NewState)
       _mesa_update_state(ctx);

diff --git a/src/mesa/main/texgetimage.c b/src/mesa/main/texgetimage.c
index 05b052a..ff03d6d 100644
--- a/src/mesa/main/texgetimage.c
+++ b/src/mesa/main/texgetimage.c
@@ -659,6 +659,12 @@ getteximage_error_check(struct gl_context *ctx,
GLenum target, GLint level,
       return GL_TRUE;
    }

+   if (clientMemSize < 0) {
+      _mesa_error( ctx, GL_INVALID_VALUE,
+                  "glGetnTexImageARB(bufSize = %d)", clientMemSize );
+      return GL_TRUE;
+   }
+
    err = _mesa_error_check_format_and_type(ctx, format, type);
    if (err != GL_NO_ERROR) {
       _mesa_error(ctx, err, "glGetTexImage(format/type)");
@@ -717,6 +723,7 @@ getteximage_error_check(struct gl_context *ctx,
GLenum target, GLint level,
          _mesa_error(ctx, GL_INVALID_OPERATION,
                      "glGetTexImage(out of bounds PBO access)");
       } else {
+         assert(bufSize >= 0);
          _mesa_error(ctx, GL_INVALID_OPERATION,
                      "glGetnTexImageARB(out of bounds access:"
                      " bufSize (%d) is too small)", clientMemSize);
@@ -822,6 +829,12 @@ getcompressedteximage_error_check(struct
gl_context *ctx, GLenum target,
                   "glGetCompressedTexImageARB(bad level = %d)", level);
       return GL_TRUE;
    }
+   if (clientMemSize < 0) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "glGetnCompressedTexImageARB"
+                  "(bufSize = %d)", clientMemSize);
+      return GL_TRUE;
+   }

    if (_mesa_is_proxy_texture(target)) {
       _mesa_error(ctx, GL_INVALID_ENUM,
@@ -857,8 +870,9 @@ getcompressedteximage_error_check(struct
gl_context *ctx, GLenum target,
                                             texImage->Depth);

    if (!_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
+      assert(clientMemSize >= 0);
       /* do bounds checking on writing to client memory */
-      if (clientMemSize < compressedSize) {
+      if ((GLuint)clientMemSize < compressedSize) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
                      "glGetnCompressedTexImageARB(out of bounds access:"
                      " bufSize (%d) is too small)", clientMemSize);
diff --git a/src/mesa/main/uniform_query.cpp b/src/mesa/main/uniform_query.cpp
index da41ee8..96fe70b 100644
--- a/src/mesa/main/uniform_query.cpp
+++ b/src/mesa/main/uniform_query.cpp
@@ -187,6 +187,12 @@ _mesa_get_uniform(struct gl_context *ctx, GLuint
program, GLint location,
    struct gl_uniform_storage *uni;
    unsigned loc, offset;

+   if (bufSize < 0) {
+      _mesa_error( ctx, GL_INVALID_VALUE,
+                  "glGetnUniform*vARB(bufSize = %d)", bufSize );
+      return;
+   }
+
    if (!validate_uniform_parameters(ctx, shProg, location, 1,
 				    &loc, &offset, "glGetUniform", true))
       return;
@@ -210,7 +216,8 @@ _mesa_get_uniform(struct gl_context *ctx, GLuint
program, GLint location,
        * with glGetUniformdv()...
        */
       unsigned bytes = sizeof(src[0]) * elements;
-      if (bufSize < 0 || bytes > (unsigned) bufSize) {
+      assert(bufSize >= 0);
+      if (bytes > (unsigned) bufSize) {
 	 _mesa_error( ctx, GL_INVALID_OPERATION,
 	             "glGetnUniform*vARB(out of bounds: bufSize is %d,"
 	             " but %u bytes are required)", bufSize, bytes );
-- 
1.7.4.1


More information about the mesa-dev mailing list