Bug 637367 - Stop DrawPlugin from accessing deleted nsObjectFrame. r=roc a=beltzner
authorSteven Michaud <smichaud@pobox.com>
Fri, 18 Mar 2011 14:35:14 -0500
changeset 63443 4da037fe27b0
parent 63442 9c3ef79b8eba
child 63444 59f8f339653f
push id1
push userroot
push dateTue, 10 Dec 2013 15:46:25 +0000
reviewersroc, beltzner
bugs637367
milestone2.0b13pre
Bug 637367 - Stop DrawPlugin from accessing deleted nsObjectFrame. r=roc a=beltzner
gfx/layers/ImageLayers.h
gfx/layers/opengl/MacIOSurfaceImageOGL.h
gfx/layers/opengl/MacIOSurfaceImageOGL.mm
layout/generic/nsObjectFrame.cpp
--- a/gfx/layers/ImageLayers.h
+++ b/gfx/layers/ImageLayers.h
@@ -362,17 +362,19 @@ public:
   virtual void SetData(const Data& aData) = 0;
 
   /**
    * Temporary hacks to force plugin drawing during an empty transaction.
    * This should not be used for anything else, and will be removed
    * when async plugin rendering is complete.
    */
   typedef void (*UpdateSurfaceCallback)(ImageContainer* aContainer, void* aInstanceOwner);
-  virtual void SetCallback(UpdateSurfaceCallback aCallback, void* aInstanceOwner) =0;
+  virtual void SetUpdateCallback(UpdateSurfaceCallback aCallback, void* aInstanceOwner) = 0;
+  typedef void (*DestroyCallback)(void* aInstanceOwner);
+  virtual void SetDestroyCallback(DestroyCallback aCallback) = 0;
 
 protected:
   MacIOSurfaceImage(void* aImplData) : Image(aImplData, MAC_IO_SURFACE) {}
 };
 #endif
 
 }
 }
--- a/gfx/layers/opengl/MacIOSurfaceImageOGL.h
+++ b/gfx/layers/opengl/MacIOSurfaceImageOGL.h
@@ -45,25 +45,28 @@ namespace mozilla {
 namespace layers {
 
 class THEBES_API MacIOSurfaceImageOGL : public MacIOSurfaceImage
 {
   typedef mozilla::gl::GLContext GLContext;
 
 public:
   MacIOSurfaceImageOGL(LayerManagerOGL *aManager);
+  virtual ~MacIOSurfaceImageOGL();
 
-  void SetCallback(UpdateSurfaceCallback aCallback, void* aObjectFrame);
+  void SetUpdateCallback(UpdateSurfaceCallback aCallback, void* aPluginInstanceOwner);
+  void SetDestroyCallback(DestroyCallback aCallback);
   void Update(ImageContainer* aContainer);
 
   void SetData(const Data &aData);
 
   GLTexture mTexture;
   gfxIntSize mSize;
   nsAutoPtr<nsIOSurface> mIOSurface;
-  void* mObjectFrame;
-  UpdateSurfaceCallback mCallback;
+  void* mPluginInstanceOwner;
+  UpdateSurfaceCallback mUpdateCallback;
+  DestroyCallback mDestroyCallback;
 };
 
 } /* layers */
 } /* mozilla */
 #endif /* XP_MACOSX */
 #endif /* GFX_MACIOSURFACEIMAGEOGL_H */
--- a/gfx/layers/opengl/MacIOSurfaceImageOGL.mm
+++ b/gfx/layers/opengl/MacIOSurfaceImageOGL.mm
@@ -41,17 +41,18 @@
 #include "OpenGL/OpenGL.h"
 
 using namespace mozilla::gl;
 
 namespace mozilla {
 namespace layers {
 
 MacIOSurfaceImageOGL::MacIOSurfaceImageOGL(LayerManagerOGL *aManager)
-  : MacIOSurfaceImage(nsnull), mSize(0, 0)
+  : MacIOSurfaceImage(nsnull), mSize(0, 0), mPluginInstanceOwner(nsnull),
+    mUpdateCallback(nsnull), mDestroyCallback(nsnull)
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread to create a cairo image");
 
   if (aManager) {
     // Allocate texture now to grab a reference to the GLContext
     GLContext *gl = aManager->glForResources();
     mTexture.Allocate(gl);
     gl->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, mTexture.GetTextureID());
@@ -60,16 +61,23 @@ MacIOSurfaceImageOGL::MacIOSurfaceImageO
                        LOCAL_GL_NEAREST);
     gl->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 
                        LOCAL_GL_TEXTURE_MAG_FILTER, 
                        LOCAL_GL_NEAREST);
     gl->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
   }
 }
 
+MacIOSurfaceImageOGL::~MacIOSurfaceImageOGL()
+{
+  if (mDestroyCallback) {
+    mDestroyCallback(mPluginInstanceOwner);
+  }
+}
+
 void
 MacIOSurfaceImageOGL::SetData(const MacIOSurfaceImage::Data &aData)
 {
   mIOSurface = nsIOSurface::LookupSurface(aData.mIOSurface->GetIOSurfaceID());
   mSize = gfxIntSize(mIOSurface->GetWidth(), mIOSurface->GetHeight());
   
   GLContext *gl = mTexture.GetGLContext();
   gl->MakeCurrent();
@@ -83,24 +91,30 @@ MacIOSurfaceImageOGL::SetData(const MacI
   mIOSurface->CGLTexImageIOSurface2D((CGLContextObj)[nsCtx CGLContextObj],
                                      LOCAL_GL_RGBA, LOCAL_GL_BGRA,
                                      LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV, 0);
   
   gl->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
 }
 
 void
-MacIOSurfaceImageOGL::SetCallback(UpdateSurfaceCallback aCallback, void* aObjectFrame)
+MacIOSurfaceImageOGL::SetUpdateCallback(UpdateSurfaceCallback aCallback, void* aPluginInstanceOwner)
 {
-  mCallback = aCallback;
-  mObjectFrame = aObjectFrame;
+  mUpdateCallback = aCallback;
+  mPluginInstanceOwner = aPluginInstanceOwner;
+}
+
+void
+MacIOSurfaceImageOGL::SetDestroyCallback(DestroyCallback aCallback)
+{
+  mDestroyCallback = aCallback;
 }
 
 void 
 MacIOSurfaceImageOGL::Update(ImageContainer* aContainer)
 {
-  if (mCallback) {
-    mCallback(aContainer, mObjectFrame);
+  if (mUpdateCallback) {
+    mUpdateCallback(aContainer, mPluginInstanceOwner);
   }
 }
 
 } /* layers */
-} /* mozilla */
\ No newline at end of file
+} /* mozilla */
--- a/layout/generic/nsObjectFrame.cpp
+++ b/layout/generic/nsObjectFrame.cpp
@@ -400,16 +400,19 @@ public:
   void CallSetWindow();
   void UpdateWindowVisibility(PRBool aVisible);
 #endif // XP_MACOSX
 
   void SetOwner(nsObjectFrame *aOwner)
   {
     mObjectFrame = aOwner;
   }
+  nsObjectFrame* GetOwner() {
+    return mObjectFrame;
+  }
 
   PRUint32 GetLastEventloopNestingLevel() const {
     return mLastEventloopNestingLevel; 
   }
 
   static PRUint32 GetEventloopNestingLevel();
       
   void ConsiderNewEventloopNestingLevel() {
@@ -1967,19 +1970,27 @@ nsPluginInstanceOwner::NotifyPaintWaiter
   if (!mWaitingForPaint && !IsUpToDate() && aBuilder->ShouldSyncDecodeImages()) {
     nsCOMPtr<nsIRunnable> event = new AsyncPaintWaitEvent(mContent, PR_FALSE);
     // Run this event as soon as it's safe to do so, since listeners need to
     // receive it immediately
     mWaitingForPaint = nsContentUtils::AddScriptRunner(event);
   }
 }
 
-static void DrawPlugin(ImageContainer* aContainer, void* aObjectFrame)
-{
-  static_cast<nsObjectFrame*>(aObjectFrame)->UpdateImageLayer(aContainer, gfxRect(0,0,0,0));
+static void DrawPlugin(ImageContainer* aContainer, void* aPluginInstanceOwner)
+{
+  nsObjectFrame* frame = static_cast<nsPluginInstanceOwner*>(aPluginInstanceOwner)->GetOwner();
+  if (frame) {
+    frame->UpdateImageLayer(aContainer, gfxRect(0,0,0,0));
+  }
+}
+
+static void OnDestroyImage(void* aPluginInstanceOwner)
+{
+  NS_RELEASE(static_cast<nsPluginInstanceOwner*>(aPluginInstanceOwner));
 }
 
 void
 nsObjectFrame::UpdateImageLayer(ImageContainer* aContainer, const gfxRect& aRect)
 {
   if (!mInstanceOwner) {
     return;
   }
@@ -1992,22 +2003,26 @@ nsObjectFrame::UpdateImageLayer(ImageCon
 }
 
 PRBool
 nsPluginInstanceOwner::SetCurrentImage(ImageContainer* aContainer)
 {
   nsCOMPtr<nsIPluginInstance_MOZILLA_2_0_BRANCH> inst = do_QueryInterface(mInstance);
   if (inst) {
     nsRefPtr<Image> image;
+    // Every call to nsIPluginInstance_MOZILLA_2_0_BRANCH::GetImage() creates
+    // a new image.  See nsIPluginInstance.idl.
     inst->GetImage(aContainer, getter_AddRefs(image));
     if (image) {
 #ifdef XP_MACOSX
       if (image->GetFormat() == Image::MAC_IO_SURFACE && mObjectFrame) {
         MacIOSurfaceImage *oglImage = static_cast<MacIOSurfaceImage*>(image.get());
-        oglImage->SetCallback(&DrawPlugin, mObjectFrame);
+        NS_ADDREF_THIS();
+        oglImage->SetUpdateCallback(&DrawPlugin, this);
+        oglImage->SetDestroyCallback(&OnDestroyImage);
       }
 #endif
       aContainer->SetCurrentImage(image);
       return PR_TRUE;
     }
   }
   aContainer->SetCurrentImage(nsnull);
   return PR_FALSE;
@@ -5790,16 +5805,29 @@ nsPluginInstanceOwner::Destroy()
  * Prepare to stop 
  */
 void
 nsPluginInstanceOwner::PrepareToStop(PRBool aDelayedStop)
 {
   // Drop image reference because the child may destroy the surface after we return.
   nsRefPtr<ImageContainer> container = mObjectFrame->GetImageContainer();
   if (container) {
+#ifdef XP_MACOSX
+    nsRefPtr<Image> image = container->GetCurrentImage();
+    if (image && (image->GetFormat() == Image::MAC_IO_SURFACE) && mObjectFrame) {
+      // Undo what we did to the current image in SetCurrentImage().
+      MacIOSurfaceImage *oglImage = static_cast<MacIOSurfaceImage*>(image.get());
+      oglImage->SetUpdateCallback(nsnull, nsnull);
+      oglImage->SetDestroyCallback(nsnull);
+      // If we have a current image here, its destructor hasn't yet been
+      // called, so OnDestroyImage() can't yet have been called.  So we need
+      // to do ourselves what OnDestroyImage() would have done.
+      NS_RELEASE_THIS();
+    }
+#endif
     container->SetCurrentImage(nsnull);
   }
 
 #if defined(XP_WIN) || defined(MOZ_X11)
   if (aDelayedStop && mWidget) {
     // To delay stopping a plugin we need to reparent the plugin
     // so that we can safely tear down the
     // plugin after its frame (and view) is gone.