wgl: Unreference the current framebuffer after the make_current call.
authorJosé Fonseca <jfonseca@vmware.com>
Thu, 2 Dec 2010 16:28:36 +0000 (16:28 +0000)
committerJosé Fonseca <jfonseca@vmware.com>
Thu, 2 Dec 2010 16:28:36 +0000 (16:28 +0000)
To prevent a dangling pointer dereference.

src/gallium/state_trackers/wgl/stw_context.c

index 86c0a28e8da75122cfa59aa62d279872e8f02ce6..cd4f3c8b3e28a8ba4a701b65c770aadd32a7e6e1 100644 (file)
@@ -264,75 +264,82 @@ stw_make_current(
    struct stw_context *curctx = NULL;
    struct stw_context *ctx = NULL;
    struct stw_framebuffer *fb = NULL;
+   BOOL ret = FALSE;
 
    if (!stw_dev)
-      goto fail;
+      return FALSE;
 
    curctx = stw_current_context();
    if (curctx != NULL) {
-      if (curctx->dhglrc != dhglrc)
+      if (curctx->dhglrc == dhglrc) {
+         if (curctx->hdc == hdc) {
+            /* Return if already current. */
+            return TRUE;
+         }
+      } else {
          curctx->st->flush(curctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
-      
-      /* Return if already current. */
-      if (curctx->dhglrc == dhglrc && curctx->hdc == hdc) {
-         ctx = curctx;
-         fb = stw_framebuffer_from_hdc( hdc );
-         goto success;
       }
-
-      stw_framebuffer_reference(&curctx->current_framebuffer, NULL);
    }
 
-   if (hdc == NULL || dhglrc == 0) {
-      return stw_dev->stapi->make_current(stw_dev->stapi, NULL, NULL, NULL);
-   }
-
-   pipe_mutex_lock( stw_dev->ctx_mutex ); 
-   ctx = stw_lookup_context_locked( dhglrc );
-   pipe_mutex_unlock( stw_dev->ctx_mutex ); 
-   if(!ctx)
-      goto fail;
-
-   fb = stw_framebuffer_from_hdc( hdc );
-   if (fb) {
-      stw_framebuffer_update(fb);
-   }
-   else {
-      /* Applications should call SetPixelFormat before creating a context,
-       * but not all do, and the opengl32 runtime seems to use a default pixel
-       * format in some cases, so we must create a framebuffer for those here
-       */
-      int iPixelFormat = GetPixelFormat(hdc);
-      if(iPixelFormat)
-         fb = stw_framebuffer_create( hdc, iPixelFormat );
-      if(!fb) 
+   if (dhglrc) {
+      pipe_mutex_lock( stw_dev->ctx_mutex );
+      ctx = stw_lookup_context_locked( dhglrc );
+      pipe_mutex_unlock( stw_dev->ctx_mutex );
+      if (!ctx) {
          goto fail;
-   }
-   
-   if(fb->iPixelFormat != ctx->iPixelFormat)
-      goto fail;
+      }
 
-   /* Bind the new framebuffer */
-   ctx->hdc = hdc;
+      fb = stw_framebuffer_from_hdc( hdc );
+      if (fb) {
+         stw_framebuffer_update(fb);
+      }
+      else {
+         /* Applications should call SetPixelFormat before creating a context,
+          * but not all do, and the opengl32 runtime seems to use a default pixel
+          * format in some cases, so we must create a framebuffer for those here
+          */
+         int iPixelFormat = GetPixelFormat(hdc);
+         if (iPixelFormat)
+            fb = stw_framebuffer_create( hdc, iPixelFormat );
+         if (!fb)
+            goto fail;
+      }
    
-   if (!stw_dev->stapi->make_current(stw_dev->stapi, ctx->st, fb->stfb, fb->stfb))
-      goto fail;
+      if (fb->iPixelFormat != ctx->iPixelFormat) {
+         SetLastError(ERROR_INVALID_PIXEL_FORMAT);
+         goto fail;
+      }
 
-   stw_framebuffer_reference(&ctx->current_framebuffer, fb);
+      /* Bind the new framebuffer */
+      ctx->hdc = hdc;
 
-success:
-   assert(fb);
-   if(fb) {
-      stw_framebuffer_release(fb);
+      ret = stw_dev->stapi->make_current(stw_dev->stapi, ctx->st, fb->stfb, fb->stfb);
+      stw_framebuffer_reference(&ctx->current_framebuffer, fb);
+   } else {
+      ret = stw_dev->stapi->make_current(stw_dev->stapi, NULL, NULL, NULL);
    }
    
-   return TRUE;
-
 fail:
-   if(fb)
+
+   if (fb) {
       stw_framebuffer_release(fb);
-   stw_dev->stapi->make_current(stw_dev->stapi, NULL, NULL, NULL);
-   return FALSE;
+   }
+
+   /* On failure, make the thread's current rendering context not current
+    * before returning */
+   if (!ret) {
+      stw_dev->stapi->make_current(stw_dev->stapi, NULL, NULL, NULL);
+      ctx = NULL;
+   }
+
+   /* Unreference the previous framebuffer if any. It must be done after
+    * make_current, as it can be referenced inside.
+    */
+   if (curctx && curctx != ctx) {
+      stw_framebuffer_reference(&curctx->current_framebuffer, NULL);
+   }
+
+   return ret;
 }
 
 /**