Bug 829557. Part 2: Allow plugin code to reenter Gecko safely while while the plugin is processing an input event. r=bsmedberg
☠☠ backed out by f4760e97c080 ☠ ☠
authorRobert O'Callahan <robert@ocallahan.org>
Thu, 28 Feb 2013 00:50:28 +1300
changeset 123142 622b744e5df9387fa352791b415b85fa9b1d0ef5
parent 123141 f73b7b8d1a2dc58c8892b551cd427f135efb6337
child 123143 05c35dc73323764e05fc366cc8d2fd5274bdd598
push id24372
push useremorley@mozilla.com
push dateWed, 27 Feb 2013 13:22:59 +0000
treeherdermozilla-central@0a91da5f5eab [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbsmedberg
bugs829557
milestone22.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 829557. Part 2: Allow plugin code to reenter Gecko safely while while the plugin is processing an input event. r=bsmedberg When nsPluginInstanceOwner passes input events to the plugin instance, it's safe to reenter Gecko from plugin code and do anything, even arbitrary script execution.
dom/plugins/base/nsNPAPIPluginInstance.cpp
dom/plugins/base/nsNPAPIPluginInstance.h
dom/plugins/base/nsPluginInstanceOwner.cpp
--- a/dom/plugins/base/nsNPAPIPluginInstance.cpp
+++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp
@@ -666,17 +666,18 @@ nsresult nsNPAPIPluginInstance::Print(NP
   platformPrint->print.embedPrint.window.clipRect.top,
   platformPrint->print.embedPrint.window.clipRect.bottom,
   platformPrint->print.embedPrint.window.clipRect.left,
   platformPrint->print.embedPrint.window.clipRect.right));
 
   return NS_OK;
 }
 
-nsresult nsNPAPIPluginInstance::HandleEvent(void* event, int16_t* result)
+nsresult nsNPAPIPluginInstance::HandleEvent(void* event, int16_t* result,
+                                            NSPluginCallReentry aSafeToReenterGecko)
 {
   if (RUNNING != mRunning)
     return NS_OK;
 
   if (!event)
     return NS_ERROR_FAILURE;
 
   PluginDestructionGuard guard(this);
@@ -687,17 +688,17 @@ nsresult nsNPAPIPluginInstance::HandleEv
   NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs();
 
   int16_t tmpResult = kNPEventNotHandled;
 
   if (pluginFunctions->event) {
     mCurrentPluginEvent = event;
 #if defined(XP_WIN) || defined(XP_OS2)
     NS_TRY_SAFE_CALL_RETURN(tmpResult, (*pluginFunctions->event)(&mNPP, event), this,
-                            NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
+                            aSafeToReenterGecko);
 #else
     MAIN_THREAD_JNI_REF_GUARD;
     tmpResult = (*pluginFunctions->event)(&mNPP, event);
 #endif
     NPP_PLUGIN_LOG(PLUGIN_LOG_NOISY,
       ("NPP HandleEvent called: this=%p, npp=%p, event=%p, return=%d\n", 
       this, &mNPP, event, tmpResult));
 
--- a/dom/plugins/base/nsNPAPIPluginInstance.h
+++ b/dom/plugins/base/nsNPAPIPluginInstance.h
@@ -82,17 +82,18 @@ public:
   NS_DECL_ISUPPORTS
 
   nsresult Initialize(nsNPAPIPlugin *aPlugin, nsPluginInstanceOwner* aOwner, const char* aMIMEType);
   nsresult Start();
   nsresult Stop();
   nsresult SetWindow(NPWindow* window);
   nsresult NewStreamFromPlugin(const char* type, const char* target, nsIOutputStream* *result);
   nsresult Print(NPPrint* platformPrint);
-  nsresult HandleEvent(void* event, int16_t* result);
+  nsresult HandleEvent(void* event, int16_t* result,
+                       NSPluginCallReentry aSafeToReenterGecko = NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
   nsresult GetValueFromPlugin(NPPVariable variable, void* value);
   nsresult GetDrawingModel(int32_t* aModel);
   nsresult IsRemoteDrawingCoreAnimation(bool* aDrawing);
   nsresult ContentsScaleFactorChanged(double aContentsScaleFactor);
   nsresult GetJSObject(JSContext *cx, JSObject** outObject);
   bool ShouldCache();
   nsresult IsWindowless(bool* isWindowless);
   nsresult AsyncSetWindow(NPWindow* window);
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -2061,17 +2061,17 @@ nsEventStatus nsPluginInstanceOwner::Pro
       pluginWidget->EndDrawPlugin();
       return nsEventStatus_eIgnore;
     }
   }
 
   int16_t response = kNPEventNotHandled;
   void* window = FixUpPluginWindow(ePluginPaintEnable);
   if (window || (eventModel == NPEventModelCocoa)) {
-    mInstance->HandleEvent(event, &response);
+    mInstance->HandleEvent(event, &response, NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
   }
 
   if (eventModel == NPEventModelCocoa && response == kNPEventStartIME) {
     pluginWidget->StartComplexTextInputForCurrentEvent();
   }
 
   if ((response == kNPEventHandled || response == kNPEventStartIME) &&
       !(anEvent.eventStructType == NS_MOUSE_EVENT &&
@@ -2177,17 +2177,17 @@ nsEventStatus nsPluginInstanceOwner::Pro
   if (pPluginEvent && !pPluginEvent->event) {
     // Don't send null events to plugins.
     NS_WARNING("nsObjectFrame ProcessEvent: trying to send null event to plugin.");
     return rv;
   }
 
   if (pPluginEvent) {
     int16_t response = kNPEventNotHandled;
-    mInstance->HandleEvent(pPluginEvent, &response);
+    mInstance->HandleEvent(pPluginEvent, &response, NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
     if (response == kNPEventHandled)
       rv = nsEventStatus_eConsumeNoDefault;
   }
 #endif
 
 #ifdef MOZ_X11
   // this code supports windowless plugins
   nsIWidget* widget = anEvent.widget;
@@ -2435,17 +2435,17 @@ nsEventStatus nsPluginInstanceOwner::Pro
   event.display = widget ?
     static_cast<Display*>(widget->GetNativeData(NS_NATIVE_DISPLAY)) : nullptr;
   event.window = None; // not a real window
   // information lost:
   event.serial = 0;
   event.send_event = False;
 
   int16_t response = kNPEventNotHandled;
-  mInstance->HandleEvent(&pluginEvent, &response);
+  mInstance->HandleEvent(&pluginEvent, &response, NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
   if (response == kNPEventHandled)
     rv = nsEventStatus_eConsumeNoDefault;
 #endif
 
 #ifdef MOZ_WIDGET_ANDROID
   // this code supports windowless plugins
   {
     // The plugin needs focus to receive keyboard and touch events
@@ -2487,44 +2487,44 @@ nsEventStatus nsPluginInstanceOwner::Pro
           case NS_MOUSE_BUTTON_DOWN:
             {
               ANPEvent event;
               event.inSize = sizeof(ANPEvent);
               event.eventType = kMouse_ANPEventType;
               event.data.mouse.action = kDown_ANPMouseAction;
               event.data.mouse.x = pluginPoint.x;
               event.data.mouse.y = pluginPoint.y;
-              mInstance->HandleEvent(&event, nullptr);
+              mInstance->HandleEvent(&event, nullptr, NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
             }
             break;
           case NS_MOUSE_BUTTON_UP:
             {
               ANPEvent event;
               event.inSize = sizeof(ANPEvent);
               event.eventType = kMouse_ANPEventType;
               event.data.mouse.action = kUp_ANPMouseAction;
               event.data.mouse.x = pluginPoint.x;
               event.data.mouse.y = pluginPoint.y;
-              mInstance->HandleEvent(&event, nullptr);
+              mInstance->HandleEvent(&event, nullptr, NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
             }
             break;
           }
       }
       break;
 
     case NS_KEY_EVENT:
      {
        const nsKeyEvent& keyEvent = static_cast<const nsKeyEvent&>(anEvent);
        LOG("Firing NS_KEY_EVENT %d %d\n", keyEvent.keyCode, keyEvent.charCode);
        // pluginEvent is initialized by nsWindow::InitKeyEvent().
        ANPEvent* pluginEvent = reinterpret_cast<ANPEvent*>(keyEvent.pluginEvent);
        if (pluginEvent) {
          MOZ_ASSERT(pluginEvent->inSize == sizeof(ANPEvent));
          MOZ_ASSERT(pluginEvent->eventType == kKey_ANPEventType);
-         mInstance->HandleEvent(pluginEvent, nullptr);
+         mInstance->HandleEvent(pluginEvent, nullptr, NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
        }
      }
      break;
 
     default:
       break;
     }
     rv = nsEventStatus_eConsumeNoDefault;