Bug 463289 - nsNativeModuleLoader doesn't protect its internal data structures, and is accessed on multiple threads (symptom is RECURSION_LEVEL assertions in pldhash.c). This patch is the simple-but-slow path: proxy all non-main-thread requests to the main thread. This is probably sufficient because asking for modules is a relatively rare activity: the component manager caches the factory objects after a lookup, r=brendan
authorBenjamin Smedberg <benjamin@smedbergs.us>
Wed, 26 Nov 2008 14:39:36 -0500
changeset 23472 54b5c634212eb738a1f90f25d90a0154a2b45d13
parent 23471 c227e9c0e2645762a85c8b8505a996b4fcf8c4ca
child 23473 c569a8f91c0ee93e0a1976903b9f7b17070d441e
push idunknown
push userunknown
push dateunknown
reviewersbrendan
bugs463289
milestone1.9.2a1pre
Bug 463289 - nsNativeModuleLoader doesn't protect its internal data structures, and is accessed on multiple threads (symptom is RECURSION_LEVEL assertions in pldhash.c). This patch is the simple-but-slow path: proxy all non-main-thread requests to the main thread. This is probably sufficient because asking for modules is a relatively rare activity: the component manager caches the factory objects after a lookup, r=brendan
xpcom/components/nsNativeComponentLoader.cpp
--- a/xpcom/components/nsNativeComponentLoader.cpp
+++ b/xpcom/components/nsNativeComponentLoader.cpp
@@ -55,20 +55,22 @@
 
 #include "prlog.h"
 #include "prinit.h"
 #include "prerror.h"
 
 #include "nsComponentManager.h"
 #include "nsCRTGlue.h"
 #include "nsModule.h"
+#include "nsThreadUtils.h"
 #include "nsTraceRefcntImpl.h"
 
 #include "nsILocalFile.h"
 #include "nsIModule.h"
+#include "nsIProxyObjectManager.h"
 
 #ifdef XP_WIN
 #include <windows.h>
 #endif
 
 #ifdef XP_MACOSX
 #include <signal.h>
 #endif
@@ -93,26 +95,45 @@ NS_IMPL_QUERY_INTERFACE1(nsNativeModuleL
 NS_IMPL_ADDREF_USING_AGGREGATOR(nsNativeModuleLoader,
                                 nsComponentManagerImpl::gComponentManager)
 NS_IMPL_RELEASE_USING_AGGREGATOR(nsNativeModuleLoader,
                                  nsComponentManagerImpl::gComponentManager)
 
 nsresult
 nsNativeModuleLoader::Init()
 {
+    NS_ASSERTION(NS_IsMainThread(), "Startup not on main thread?");
+
     LOG(PR_LOG_DEBUG, ("nsNativeModuleLoader::Init()"));
 
     return mLibraries.Init() ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
 }
 
 NS_IMETHODIMP
 nsNativeModuleLoader::LoadModule(nsILocalFile* aFile, nsIModule* *aResult)
 {
     nsresult rv;
 
+    if (!NS_IsMainThread()) {
+        // If this call is off the main thread, synchronously proxy it
+        // to the main thread.
+        
+        nsCOMPtr<nsIModuleLoader> proxythis;
+        rv = NS_GetProxyForObject(NS_PROXY_TO_MAIN_THREAD,
+                                  NS_GET_IID(nsIModuleLoader),
+                                  this, NS_PROXY_SYNC,
+                                  getter_AddRefs(proxythis));
+        if (NS_FAILED(rv))
+            return rv;
+
+        return proxythis->LoadModule(aFile, aResult);
+    }
+
+    NS_ASSERTION(NS_IsMainThread(), "LoadModule should always proxy to the main thread!");
+
     // Only load components that end in the proper dynamic library suffix
     nsCAutoString filePath;
     aFile->GetNativePath(filePath);
     if (!StringTail(filePath, sizeof(MOZ_DLL_SUFFIX) - 1).
         LowerCaseEqualsLiteral(MOZ_DLL_SUFFIX))
         return NS_ERROR_INVALID_ARG;
 
     nsCOMPtr<nsIHashable> hashedFile(do_QueryInterface(aFile));
@@ -250,11 +271,13 @@ nsNativeModuleLoader::UnloaderFunc(nsIHa
 #endif
 
     return PL_DHASH_REMOVE;
 }
 
 void
 nsNativeModuleLoader::UnloadLibraries()
 {
+    NS_ASSERTION(NS_IsMainThread(), "Shutdown not on main thread?");
+
     mLibraries.Enumerate(ReleaserFunc, nsnull);
     mLibraries.Enumerate(UnloaderFunc, nsnull);
 }