vbo: fix possible use-after-free segfault after a VAO is deleted
authorMarek Olšák <maraeo@gmail.com>
Tue, 23 Apr 2013 23:29:26 +0000 (01:29 +0200)
committerMarek Olšák <maraeo@gmail.com>
Wed, 1 May 2013 18:08:53 +0000 (20:08 +0200)
This like the fifth attempt to fix the issue.

Also with the new "validating" flag, we can set recalculate_inputs to FALSE
earlier in vbo_bind_arrays, because _mesa_update_state won't change it.

NOTE: This is a candidate for the stable branches.

v2: fixed a typo

Reviewed-by: Brian Paul <brianp@vmware.com>
src/mesa/vbo/vbo_exec.c
src/mesa/vbo/vbo_exec.h
src/mesa/vbo/vbo_exec_array.c

index 0a8fbf8ede168e62afe031d0521861fa1e367c8a..926e7b46ddb7445671fa0bd6577bb4d0f4a319cd 100644 (file)
@@ -80,10 +80,26 @@ void vbo_exec_destroy( struct gl_context *ctx )
  */ 
 void vbo_exec_invalidate_state( struct gl_context *ctx, GLuint new_state )
 {
-   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+   struct vbo_context *vbo = vbo_context(ctx);
+   struct vbo_exec_context *exec = &vbo->exec;
 
-   if (new_state & (_NEW_PROGRAM|_NEW_ARRAY)) {
+   if (!exec->validating && new_state & (_NEW_PROGRAM|_NEW_ARRAY)) {
       exec->array.recalculate_inputs = GL_TRUE;
+
+      /* If we ended up here because a VAO was deleted, the _DrawArrays
+       * pointer which pointed to the VAO might be invalid now, so set it
+       * to NULL.  This prevents crashes in driver functions like Clear
+       * where driver state validation might occur, but the vbo module is
+       * still in an invalid state.
+       *
+       * Drivers should skip vertex array state validation if _DrawArrays
+       * is NULL.  It also has no effect on performance, because attrib
+       * bindings will be recalculated anyway.
+       */
+      if (vbo->last_draw_method == DRAW_ARRAYS) {
+         ctx->Array._DrawArrays = NULL;
+         vbo->last_draw_method = DRAW_NONE;
+      }
    }
 
    if (new_state & _NEW_EVAL)
index 9fc87917c59fa3002a51d4801a63f79078128283..bd3ab3ba6f388b33944cd95b93f478f4de762420 100644 (file)
@@ -81,6 +81,7 @@ struct vbo_exec_context
    struct gl_context *ctx;   
    GLvertexformat vtxfmt;
    GLvertexformat vtxfmt_noop;
+   GLboolean validating; /**< if we're in the middle of state validation */
 
    struct {
       struct gl_buffer_object *bufferobj;
index 7e61f7b31fdae5fbdbd5a878deb5221291d9c399..1bf3af47b8b3fd130e0b827de7acf47094bb8a38 100644 (file)
@@ -501,6 +501,7 @@ vbo_bind_arrays(struct gl_context *ctx)
 
    if (exec->array.recalculate_inputs) {
       recalculate_input_bindings(ctx);
+      exec->array.recalculate_inputs = GL_FALSE;
 
       /* Again... because we may have changed the bitmask of per-vertex varying
        * attributes.  If we regenerate the fixed-function vertex program now
@@ -508,10 +509,13 @@ vbo_bind_arrays(struct gl_context *ctx)
        * need in the shader.
        */
       if (ctx->NewState) {
+         /* Setting "validating" to TRUE prevents _mesa_update_state from
+          * invalidating what we just did.
+          */
+         exec->validating = GL_TRUE;
          _mesa_update_state(ctx);
+         exec->validating = GL_FALSE;
       }
-
-      exec->array.recalculate_inputs = GL_FALSE;
    }
 }