Bug 449129 - abort a plugin process if a plugin attempts to spin an event loop while painting, r=jmathies
authorBenjamin Smedberg <benjamin@smedbergs.us>
Wed, 23 Jun 2010 10:18:00 -0400
changeset 44183 de4b3d642996f666f0b2131a4468c8a215c236bb
parent 44182 d5f400819ce6d75471abc17fce10c8c83993ffa4
child 44184 f6cf82daa5bd753f022aea8f756775371e55f863
child 44187 99d7167794ff2f007f2cf6730a422c7e28cf88bf
push idunknown
push userunknown
push dateunknown
reviewersjmathies
bugs449129
milestone1.9.3a6pre
Bug 449129 - abort a plugin process if a plugin attempts to spin an event loop while painting, r=jmathies
dom/plugins/PluginInstanceChild.cpp
dom/plugins/PluginInstanceChild.h
ipc/glue/WindowsMessageLoop.cpp
layout/base/Makefile.in
layout/base/PaintTracker.cpp
layout/base/PaintTracker.h
--- a/dom/plugins/PluginInstanceChild.cpp
+++ b/dom/plugins/PluginInstanceChild.cpp
@@ -610,16 +610,18 @@ bool
 PluginInstanceChild::AnswerNPP_HandleEvent_Shmem(const NPRemoteEvent& event,
                                                  Shmem& mem,
                                                  int16_t* handled,
                                                  Shmem* rtnmem)
 {
     PLUGIN_LOG_DEBUG_FUNCTION;
     AssertPluginThread();
 
+    PaintTracker pt;
+
     NPCocoaEvent evcopy = event.event;
 
     if (evcopy.type == NPCocoaEventDrawRect) {
         if (!mShColorSpace) {
             mShColorSpace = CreateSystemColorSpace();
             if (!mShColorSpace) {
                 PLUGIN_LOG_DEBUG(("Could not allocate ColorSpace."));
                 *handled = false;
@@ -681,16 +683,18 @@ PluginInstanceChild::AnswerNPP_HandleEve
 bool
 PluginInstanceChild::AnswerNPP_HandleEvent_IOSurface(const NPRemoteEvent& event,
                                                      const uint32_t &surfaceid,
                                                      int16_t* handled)
 {
     PLUGIN_LOG_DEBUG_FUNCTION;
     AssertPluginThread();
 
+    PaintTracker pt;
+
     NPCocoaEvent evcopy = event.event;
     nsIOSurface* surf = nsIOSurface::LookupSurface(surfaceid);
     if (!surf) {
         NS_ERROR("Invalid IOSurface.");
         *handled = false;
         return false;
     }
 
--- a/dom/plugins/PluginInstanceChild.h
+++ b/dom/plugins/PluginInstanceChild.h
@@ -51,16 +51,17 @@
 
 #include "npfunctions.h"
 #include "nsAutoPtr.h"
 #include "nsTArray.h"
 #include "ChildAsyncCall.h"
 #include "ChildTimer.h"
 #include "nsRect.h"
 #include "nsTHashtable.h"
+#include "mozilla/PaintTracker.h"
 
 namespace mozilla {
 namespace plugins {
 
 class PBrowserStreamChild;
 class BrowserStreamChild;
 class StreamNotifyChild;
 
@@ -95,16 +96,17 @@ protected:
     AnswerNPP_HandleEvent_Shmem(const NPRemoteEvent& event, Shmem& mem, int16_t* handled, Shmem* rtnmem);
     virtual bool
     AnswerNPP_HandleEvent_IOSurface(const NPRemoteEvent& event, const uint32_t& surface, int16_t* handled);
 
     NS_OVERRIDE
     virtual bool
     AnswerPaint(const NPRemoteEvent& event, int16_t* handled)
     {
+        PaintTracker pt;
         return AnswerNPP_HandleEvent(event, handled);
     }
 
     NS_OVERRIDE
     virtual bool
     RecvWindowPosChanged(const NPRemoteEvent& event);
 
     virtual bool
--- a/ipc/glue/WindowsMessageLoop.cpp
+++ b/ipc/glue/WindowsMessageLoop.cpp
@@ -42,16 +42,17 @@
 #include "RPCChannel.h"
 
 #include "nsAutoPtr.h"
 #include "nsServiceManagerUtils.h"
 #include "nsStringGlue.h"
 #include "nsIXULAppInfo.h"
 
 #include "mozilla/Mutex.h"
+#include "mozilla/PaintTracker.h"
 
 using mozilla::ipc::SyncChannel;
 using mozilla::ipc::RPCChannel;
 using mozilla::MutexAutoUnlock;
 
 using namespace mozilla::ipc::windows;
 
 /**
@@ -618,16 +619,20 @@ RPCChannel::ProcessNativeEventsInRPCCall
 // in a child. There are some intricacies in using it however. Spin loop is
 // enabled for a particular RPC frame by the client calling
 // RPCChannel::ProcessNativeEventsInRPCCall().
 // This call can be nested for multiple RPC frames in a single plugin or 
 // multiple unrelated plugins.
 void
 RPCChannel::SpinInternalEventLoop()
 {
+  if (mozilla::PaintTracker::IsPainting()) {
+    NS_RUNTIMEABORT("Don't spin an event loop while painting.");
+  }
+
   NS_ASSERTION(mTopFrame && mTopFrame->mSpinNestedEvents,
                "Spinning incorrectly");
 
   // Nested windows event loop we trigger when the child enters into modal
   // event loops.
   
   // Note, when we return, we always reset the notify worker event. So there's
   // no need to reset it on return here.
--- a/layout/base/Makefile.in
+++ b/layout/base/Makefile.in
@@ -53,16 +53,18 @@ LIBRARY_NAME	= gkbase_s
 LIBXUL_LIBRARY	= 1
 
 
 
 XPIDLSRCS	= \
 		nsIStyleSheetService.idl	\
 		$(NULL)
 
+EXPORTS_NAMESPACES = mozilla
+
 EXPORTS		= \
 		FrameLayerBuilder.h \
 		FramePropertyTable.h \
 		nsBidi.h \
 		nsBidiPresUtils.h \
 		nsCaret.h \
 		nsCSSFrameConstructor.h \
 		nsChangeHint.h \
@@ -83,16 +85,20 @@ EXPORTS		= \
 		nsLayoutUtils.h \
 		nsPresContext.h \
 		nsPresState.h \
 		nsRefreshDriver.h \
 		nsStyleChangeList.h \
 		nsStyleConsts.h \
 		$(NULL)
 
+EXPORTS_mozilla = \
+  PaintTracker.h \
+  $(NULL)
+
 CPPSRCS		= \
 		FrameLayerBuilder.cpp \
 		FramePropertyTable.cpp \
 		RestyleTracker.cpp \
 		nsCSSColorUtils.cpp \
 		nsCSSFrameConstructor.cpp \
 		nsCSSRendering.cpp \
 		nsCSSRenderingBorders.cpp \
@@ -110,16 +116,17 @@ CPPSRCS		= \
 		nsLayoutUtils.cpp \
 		nsPresArena.cpp \
 		nsPresContext.cpp \
 		nsPresShell.cpp \
 		nsQuoteList.cpp \
 		nsRefreshDriver.cpp \
 		nsStyleChangeList.cpp \
 		nsStyleSheetService.cpp \
+		PaintTracker.cpp \
 		$(NULL)
 
 ifndef MOZ_XUL
 XPIDLSRCS  += \
 		nsIBoxObject.idl \
 		$(NULL)
 EXPORTS    += \
 		nsPIBoxObject.h \
new file mode 100644
--- /dev/null
+++ b/layout/base/PaintTracker.cpp
@@ -0,0 +1,7 @@
+#include "mozilla/PaintTracker.h"
+
+namespace mozilla {
+
+int PaintTracker::gPaintTracker;
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/layout/base/PaintTracker.h
@@ -0,0 +1,29 @@
+#ifndef mozilla_PaintTracker_h
+#define mozilla_PaintTracker_h
+
+#include "nscore.h"
+#include "nsDebug.h"
+
+namespace mozilla {
+
+class NS_STACK_CLASS PaintTracker
+{
+public:
+  PaintTracker() {
+    ++gPaintTracker;
+  }
+  ~PaintTracker() {
+    NS_ASSERTION(gPaintTracker > 0, "Mismatched constructor/destructor");
+  }
+
+  static bool IsPainting() {
+    return !!gPaintTracker;
+  }
+
+private:
+  static int gPaintTracker;
+};
+
+} // namespace mozilla
+
+#endif // mozilla_PaintTracker_h