diff --git a/modules/plugin/base/src/nsPluginHost.cpp b/modules/plugin/base/src/nsPluginHost.cpp index cb77d269de4..c4f04d510c5 100644 --- a/modules/plugin/base/src/nsPluginHost.cpp +++ b/modules/plugin/base/src/nsPluginHost.cpp @@ -160,6 +160,17 @@ #include // for GDK_DISPLAY() #endif +// Null out a strong ref to a linked list iteratively to avoid +// exhausting the stack (bug 486349). +#define NS_ITERATIVE_UNREF_LIST(type_, list_, mNext_) \ + { \ + while (list_) { \ + type_ temp = list_->mNext_; \ + list_->mNext_ = nsnull; \ + list_ = temp; \ + } \ + } + // this is the name of the directory which will be created // to cache temporary files. #define kPluginTmpDirName NS_LITERAL_CSTRING("plugtmp") @@ -407,7 +418,6 @@ PRBool nsPluginInstanceTagList::remove(nsPluginInstanceTag * plugin) for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) { if (p == plugin) { PRBool lastInstance = IsLastInstance(p); - nsPluginTag *pluginTag = p->mPluginTag; if (p == mFirst) mFirst = p->mNext; @@ -417,18 +427,26 @@ PRBool nsPluginInstanceTagList::remove(nsPluginInstanceTag * plugin) if (prev && !prev->mNext) mLast = prev; - delete p; + if (lastInstance) { + nsRefPtr pluginTag = p->mPluginTag; - if (lastInstance && pluginTag) { - nsresult rv; - nsCOMPtr pref(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv)); - NS_ENSURE_SUCCESS(rv, rv); + delete p; - PRBool unloadPluginsASAP = PR_FALSE; - rv = pref->GetBoolPref("plugins.unloadASAP", &unloadPluginsASAP); - if (NS_SUCCEEDED(rv) && unloadPluginsASAP) - pluginTag->TryUnloadPlugin(); + if (pluginTag) { + nsresult rv; + nsCOMPtr pref(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv)); + NS_ENSURE_SUCCESS(rv, rv); + + PRBool unloadPluginsASAP = PR_FALSE; + rv = pref->GetBoolPref("plugins.unloadASAP", &unloadPluginsASAP); + if (NS_SUCCEEDED(rv) && unloadPluginsASAP) + pluginTag->TryUnloadPlugin(); + } + else + NS_ASSERTION(pluginTag, "pluginTag was not set, plugin not shutdown"); } + else + delete p; mCount--; return PR_TRUE; @@ -786,6 +804,8 @@ nsPluginTag::nsPluginTag(const char* aName, nsPluginTag::~nsPluginTag() { + NS_ASSERTION(!mNext, "Risk of exhausting the stack space, bug 486349"); + TryUnloadPlugin(); // Remove mime types added to the category manager @@ -2436,14 +2456,10 @@ nsPluginStreamListenerPeer::VisitHeader(const nsACString &header, const nsACStri } nsPluginHost::nsPluginHost() + // No need to initialize members to nsnull, PR_FALSE etc because this class + // has a zeroing operator new. + : mJavaEnabled(PR_TRUE) { - mPluginsLoaded = PR_FALSE; - mDontShowBadPluginMessage = PR_FALSE; - mIsDestroyed = PR_FALSE; - mOverrideInternalTypes = PR_FALSE; - mAllowAlienStarHandler = PR_FALSE; - mDefaultPluginDisabled = PR_FALSE; - mJavaEnabled = PR_TRUE; gActivePluginList = &mPluginInstanceTagList; @@ -2496,7 +2512,6 @@ nsPluginHost::nsPluginHost() PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("nsPluginHost::ctor\n")); PR_LogFlush(); #endif - mCachedPlugins = nsnull; } nsPluginHost::~nsPluginHost() @@ -2957,19 +2972,8 @@ NS_IMETHODIMP nsPluginHost::Destroy() mPluginPath = nsnull; } - while (mPlugins) { - nsRefPtr temp = mPlugins->mNext; - // while walking through the list of the plugins see if we still have anything - // to shutdown some plugins may have never created an instance but still expect - // the shutdown call see bugzilla bug 73071 - // with current logic, no need to do anything special as nsIPlugin::Shutdown - // will be performed in the destructor - mPlugins->mNext = nsnull; - mPlugins = temp; - } - - // Delete any remaining cached plugins list - mCachedPlugins = nsnull; + NS_ITERATIVE_UNREF_LIST(nsRefPtr, mPlugins, mNext); + NS_ITERATIVE_UNREF_LIST(nsRefPtr, mCachedPlugins, mNext); // Lets remove any of the temporary files that we created. if (sPluginTempDir) { @@ -3511,6 +3515,7 @@ NS_IMETHODIMP nsPluginHost::SetUpPluginInstance(const char *aMimeType, return rv; // other failure return codes may be not fatal, so we can still try + aOwner->SetInstance(nsnull); // avoid assert about setting it twice rv = TrySetUpPluginInstance(aMimeType, aURL, aOwner); } @@ -4449,7 +4454,6 @@ nsresult nsPluginHost::ScanPluginsDirectory(nsIFile * pluginsDir, // we cannot get here if the plugin has just been added // and thus |pluginTag| is not from cache, because otherwise // it would not be present in the list; - // so there is no need to delete |pluginTag| -- it _is_ from the cache info list. bAddIt = PR_FALSE; } } @@ -4463,12 +4467,6 @@ nsresult nsPluginHost::ScanPluginsDirectory(nsIFile * pluginsDir, if (pluginTag->IsEnabled()) pluginTag->RegisterWithCategoryManager(mOverrideInternalTypes); } - else if (!pluginTag->HasFlag(NS_PLUGIN_FLAG_UNWANTED)) { - // we don't need it, delete it; - // but don't delete unwanted plugins since they are cached - // in the cache info list and will be deleted later - pluginTag = nsnull; - } } return NS_OK; } @@ -4582,7 +4580,7 @@ nsresult nsPluginHost::FindPlugins(PRBool aCreatePluginList, PRBool * aPluginsCh // if we are just looking for possible changes, // no need to proceed if changes are detected if (!aCreatePluginList && *aPluginsChanged) { - mCachedPlugins = nsnull; + NS_ITERATIVE_UNREF_LIST(nsRefPtr, mCachedPlugins, mNext); return NS_OK; } } @@ -4608,7 +4606,7 @@ nsresult nsPluginHost::FindPlugins(PRBool aCreatePluginList, PRBool * aPluginsCh // if we are just looking for possible changes, // no need to proceed if changes are detected if (!aCreatePluginList && *aPluginsChanged) { - mCachedPlugins = nsnull; + NS_ITERATIVE_UNREF_LIST(nsRefPtr, mCachedPlugins, mNext); return NS_OK; } } @@ -4656,7 +4654,7 @@ nsresult nsPluginHost::FindPlugins(PRBool aCreatePluginList, PRBool * aPluginsCh // if we are just looking for possible changes, // no need to proceed if changes are detected if (!aCreatePluginList && *aPluginsChanged) { - mCachedPlugins = nsnull; + NS_ITERATIVE_UNREF_LIST(nsRefPtr, mCachedPlugins, mNext); return NS_OK; } } @@ -4683,7 +4681,7 @@ nsresult nsPluginHost::FindPlugins(PRBool aCreatePluginList, PRBool * aPluginsCh // if we are not creating the list, there is no need to proceed if (!aCreatePluginList) { - mCachedPlugins = nsnull; + NS_ITERATIVE_UNREF_LIST(nsRefPtr, mCachedPlugins, mNext); return NS_OK; } @@ -4693,7 +4691,7 @@ nsresult nsPluginHost::FindPlugins(PRBool aCreatePluginList, PRBool * aPluginsCh WritePluginInfo(); // No more need for cached plugins. Clear it up. - mCachedPlugins = nsnull; + NS_ITERATIVE_UNREF_LIST(nsRefPtr, mCachedPlugins, mNext); // reverse our list of plugins nsRefPtr next; @@ -4717,7 +4715,7 @@ nsPluginHost::UpdatePluginInfo(nsPluginTag* aPluginTag) { ReadPluginInfo(); WritePluginInfo(); - mCachedPlugins = nsnull; + NS_ITERATIVE_UNREF_LIST(nsRefPtr, mCachedPlugins, mNext); if (!aPluginTag || aPluginTag->IsEnabled()) return NS_OK;