Bug 767338 - Increment the module's refcount and ensure the validity of its base address in the virtual address space before attempting to read its PDB info to make sure that it doesn't get unloaded too soon; r=vladan
authorEhsan Akhgari <ehsan@mozilla.com>
Sun, 01 Jul 2012 14:47:20 -0400
changeset 101273 885c843432e648ffb05dbdb8dd0e91b202834c36
parent 101272 edfbf1e2f6b72dafc211bd658cc63bbf3d79df68
child 101274 e146e44dbe50a3aef4eb0ae81f3e201d80a3d074
push idunknown
push userunknown
push dateunknown
reviewersvladan
bugs767338
milestone16.0a1
Bug 767338 - Increment the module's refcount and ensure the validity of its base address in the virtual address space before attempting to read its PDB info to make sure that it doesn't get unloaded too soon; r=vladan
tools/profiler/shared-libraries-win32.cc
--- a/tools/profiler/shared-libraries-win32.cc
+++ b/tools/profiler/shared-libraries-win32.cc
@@ -83,24 +83,42 @@ SharedLibraryInfo SharedLibraryInfo::Get
 
   MODULEENTRY32 module = {0};
   module.dwSize = sizeof(MODULEENTRY32);
   if (Module32First(snap, &module)) {
     do {
       nsID pdbSig;
       uint32_t pdbAge;
       char *pdbName = NULL;
-      if (GetPdbInfo((uintptr_t)module.modBaseAddr, pdbSig, pdbAge, &pdbName)) {
+
+      // Load the module again to make sure that its handle will remain remain
+      // valid as we attempt to read the PDB information from it.  We load the
+      // DLL as a datafile so that if the module actually gets unloaded between
+      // the call to Module32Next and the following LoadLibraryEx, we don't end
+      // up running the now newly loaded module's DllMain function.  If the
+      // module is already loaded, LoadLibraryEx just increments its refcount.
+      //
+      // Note that because of the race condition above, merely loading the DLL
+      // again is not safe enough, therefore we also need to make sure that we
+      // can read the memory mapped at the base address before we can safely
+      // proceed to actually access those pages.
+      HMODULE handleLock = LoadLibraryEx(module.szExePath, NULL, LOAD_LIBRARY_AS_DATAFILE);
+      MEMORY_BASIC_INFORMATION vmemInfo = {0};
+      if (handleLock &&
+          sizeof(vmemInfo) == VirtualQuery(module.modBaseAddr, &vmemInfo, sizeof(vmemInfo)) &&
+          vmemInfo.State == MEM_COMMIT &&
+          GetPdbInfo((uintptr_t)module.modBaseAddr, pdbSig, pdbAge, &pdbName)) {
         SharedLibrary shlib((uintptr_t)module.modBaseAddr,
                             (uintptr_t)module.modBaseAddr+module.modBaseSize,
                             0, // DLLs are always mapped at offset 0 on Windows
                             pdbSig,
                             pdbAge,
                             pdbName,
                             module.szModule);
         sharedLibraryInfo.AddSharedLibrary(shlib);
       }
+      FreeLibrary(handleLock); // ok to free null handles
     } while (Module32Next(snap, &module));
   }
 
   return sharedLibraryInfo;
 }