Bug 1152395 - Ensure that NP_Shutdown respects async plugin init. r=jimm, a=lizzard
authorAaron Klotz <aklotz@mozilla.com>
Wed, 08 Apr 2015 11:31:18 -0600
changeset 266981 8d2d128ce671f8b977dc07d265e47ec43a01c02a
parent 266980 b852e95d2f6c1b7ad9e060f4ba1967164c90aefa
child 266982 40a427f948c9218710bac9ae2720cb56216e461d
push id830
push userraliiev@mozilla.com
push dateFri, 19 Jun 2015 19:24:37 +0000
treeherdermozilla-release@932614382a68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimm, lizzard
bugs1152395
milestone39.0a2
Bug 1152395 - Ensure that NP_Shutdown respects async plugin init. r=jimm, a=lizzard
dom/plugins/ipc/PluginModuleParent.cpp
dom/plugins/ipc/PluginModuleParent.h
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -605,16 +605,17 @@ PluginModuleParent::PluginModuleParent(b
     , mGetSitesWithDataSupported(false)
     , mNPNIface(nullptr)
     , mNPPIface(nullptr)
     , mPlugin(nullptr)
     , mTaskFactory(this)
     , mIsFlashPlugin(false)
     , mIsStartingAsync(false)
     , mNPInitialized(false)
+    , mIsNPShutdownPending(false)
     , mAsyncNewRv(NS_ERROR_NOT_INITIALIZED)
 {
 #if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK)
     mIsStartingAsync = Preferences::GetBool(kAsyncInitPref, false);
 #if defined(MOZ_CRASHREPORTER)
     CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AsyncPluginInit"),
                                        mIsStartingAsync ?
                                            NS_LITERAL_CSTRING("1") :
@@ -2239,16 +2240,23 @@ PluginModuleChromeParent::RecvNP_Initial
     return PluginModuleParent::RecvNP_InitializeResult(aError) && ok;
 }
 
 #endif
 
 void
 PluginModuleParent::InitAsyncSurrogates()
 {
+    if (MaybeRunDeferredShutdown()) {
+        // We've shut down, so the surrogates are no longer valid. Clear
+        // mSurrogateInstances to ensure that these aren't used.
+        mSurrogateInstances.Clear();
+        return;
+    }
+
     uint32_t len = mSurrogateInstances.Length();
     for (uint32_t i = 0; i < len; ++i) {
         NPError err;
         mAsyncNewRv = mSurrogateInstances[i]->NPP_New(&err);
         if (NS_FAILED(mAsyncNewRv)) {
             mSurrogateInstances[i]->NotifyAsyncInitFailed();
             continue;
         }
@@ -2258,38 +2266,75 @@ PluginModuleParent::InitAsyncSurrogates(
 
 bool
 PluginModuleParent::RemovePendingSurrogate(
                             const nsRefPtr<PluginAsyncSurrogate>& aSurrogate)
 {
     return mSurrogateInstances.RemoveElement(aSurrogate);
 }
 
+bool
+PluginModuleParent::MaybeRunDeferredShutdown()
+{
+    if (!mIsStartingAsync || !mIsNPShutdownPending) {
+        return false;
+    }
+    MOZ_ASSERT(!mShutdown);
+    NPError error;
+    if (!DoShutdown(&error)) {
+        return false;
+    }
+    mIsNPShutdownPending = false;
+    return true;
+}
+
 nsresult
 PluginModuleParent::NP_Shutdown(NPError* error)
 {
     PLUGIN_LOG_DEBUG_METHOD;
 
     if (mShutdown) {
         *error = NPERR_GENERIC_ERROR;
         return NS_ERROR_FAILURE;
     }
 
+    /* If we're still running an async NP_Initialize then we need to defer
+       shutdown until we've received the result of the NP_Initialize call. */
+    if (mIsStartingAsync && !mNPInitialized) {
+        mIsNPShutdownPending = true;
+        *error = NPERR_NO_ERROR;
+        return NS_OK;
+    }
+
+    if (!DoShutdown(error)) {
+        return NS_ERROR_FAILURE;
+    }
+
+    return NS_OK;
+}
+
+bool
+PluginModuleParent::DoShutdown(NPError* error)
+{
     bool ok = true;
     if (IsChrome()) {
         ok = CallNP_Shutdown(error);
     }
 
     // if NP_Shutdown() is nested within another interrupt call, this will
     // break things.  but lord help us if we're doing that anyway; the
     // plugin dso will have been unloaded on the other side by the
     // CallNP_Shutdown() message
     Close();
 
-    return ok ? NS_OK : NS_ERROR_FAILURE;
+    mShutdown = ok;
+    if (!ok) {
+        *error = NPERR_GENERIC_ERROR;
+    }
+    return ok;
 }
 
 nsresult
 PluginModuleParent::NP_GetMIMEDescription(const char** mimeDesc)
 {
     PLUGIN_LOG_DEBUG_METHOD;
 
     *mimeDesc = "application/x-foobar";
--- a/dom/plugins/ipc/PluginModuleParent.h
+++ b/dom/plugins/ipc/PluginModuleParent.h
@@ -263,16 +263,18 @@ protected:
 #endif
 
     void InitAsyncSurrogates();
 
 protected:
     void NotifyFlashHang();
     void NotifyPluginCrashed();
     void OnInitFailure();
+    bool MaybeRunDeferredShutdown();
+    bool DoShutdown(NPError* error);
 
     bool GetSetting(NPNVariable aVariable);
     void GetSettings(PluginSettings* aSettings);
 
     bool mIsChrome;
     bool mShutdown;
     bool mClearSiteDataSupported;
     bool mGetSitesWithDataSupported;
@@ -298,16 +300,17 @@ protected:
     bool
     GetPluginDetails();
 
     friend class mozilla::dom::CrashReporterParent;
     friend class mozilla::plugins::PluginAsyncSurrogate;
 
     bool              mIsStartingAsync;
     bool              mNPInitialized;
+    bool              mIsNPShutdownPending;
     nsTArray<nsRefPtr<PluginAsyncSurrogate>> mSurrogateInstances;
     nsresult          mAsyncNewRv;
 };
 
 class PluginModuleContentParent : public PluginModuleParent
 {
   public:
     explicit PluginModuleContentParent();