Bug 844196 - Register a JitExceptionHandler for breakpad (r=bsmedberg)
authorDavid Major <dmajor@mozilla.com>
Wed, 08 Oct 2014 14:25:20 -0500
changeset 209485 eabbf84195071b3e2aa6035c3f972841bc451fbe
parent 209484 f920a1e7d15a1b43b3c2d08e28e454fc2d3c0f04
child 209486 34b96e14238c44c132a83dea78b5d70d61ee84df
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersbsmedberg
bugs844196
milestone35.0a1
Bug 844196 - Register a JitExceptionHandler for breakpad (r=bsmedberg)
toolkit/crashreporter/nsExceptionHandler.cpp
--- a/toolkit/crashreporter/nsExceptionHandler.cpp
+++ b/toolkit/crashreporter/nsExceptionHandler.cpp
@@ -9,16 +9,17 @@
 #include "mozilla/dom/CrashReporterChild.h"
 #include "mozilla/Services.h"
 #include "nsIObserverService.h"
 #include "mozilla/unused.h"
 #include "mozilla/SyncRunnable.h"
 
 #include "nsThreadUtils.h"
 #include "nsXULAppAPI.h"
+#include "jsfriendapi.h"
 
 #if defined(XP_WIN32)
 #ifdef WIN32_LEAN_AND_MEAN
 #undef WIN32_LEAN_AND_MEAN
 #endif
 
 #include "nsXULAppAPI.h"
 #include "nsIXULAppInfo.h"
@@ -353,21 +354,22 @@ nsTArray<nsAutoPtr<DelayedNote> >* gDela
 // reporter is loaded instead (in case it became unloaded somehow)
 typedef LPTOP_LEVEL_EXCEPTION_FILTER (WINAPI *SetUnhandledExceptionFilter_func)
   (LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter);
 static SetUnhandledExceptionFilter_func stub_SetUnhandledExceptionFilter = 0;
 static LPTOP_LEVEL_EXCEPTION_FILTER previousUnhandledExceptionFilter = nullptr;
 static WindowsDllInterceptor gKernel32Intercept;
 static bool gBlockUnhandledExceptionFilter = true;
 
-static void NotePreviousUnhandledExceptionFilter()
+static LPTOP_LEVEL_EXCEPTION_FILTER GetUnhandledExceptionFilter()
 {
-  // Set a dummy value to get the previous filter, then restore
-  previousUnhandledExceptionFilter = SetUnhandledExceptionFilter(nullptr);
-  SetUnhandledExceptionFilter(previousUnhandledExceptionFilter);
+  // Set a dummy value to get the current filter, then restore
+  LPTOP_LEVEL_EXCEPTION_FILTER current = SetUnhandledExceptionFilter(nullptr);
+  SetUnhandledExceptionFilter(current);
+  return current;
 }
 
 static LPTOP_LEVEL_EXCEPTION_FILTER WINAPI
 patched_SetUnhandledExceptionFilter (LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter)
 {
   if (!gBlockUnhandledExceptionFilter) {
     // don't intercept
     return stub_SetUnhandledExceptionFilter(lpTopLevelExceptionFilter);
@@ -379,16 +381,28 @@ patched_SetUnhandledExceptionFilter (LPT
       stub_SetUnhandledExceptionFilter(lpTopLevelExceptionFilter);
     return previousUnhandledExceptionFilter;
   }
 
   // intercept attempts to change the filter
   return nullptr;
 }
 
+static LPTOP_LEVEL_EXCEPTION_FILTER sUnhandledExceptionFilter = nullptr;
+
+static long
+JitExceptionHandler(void *exceptionRecord, void *context)
+{
+    EXCEPTION_POINTERS pointers = {
+        (PEXCEPTION_RECORD)exceptionRecord,
+        (PCONTEXT)context
+    };
+    return sUnhandledExceptionFilter(&pointers);
+}
+
 /**
  * Reserve some VM space. In the event that we crash because VM space is
  * being leaked without leaking memory, freeing this space before taking
  * the minidump will allow us to collect a minidump.
  *
  * This size is bigger than xul.dll plus some extra for MinidumpWriteDump
  * allocations.
  */
@@ -802,16 +816,17 @@ bool MinidumpCallback(
         WriteFile(hFile, kMemoryReportParameter,
                   kMemoryReportParameterLen, &nBytes, nullptr);
       }
       CloseHandle(hFile);
     }
   }
 
   if (!doReport) {
+    TerminateProcess(GetCurrentProcess(), 1);
     return returnValue;
   }
 
   XP_CHAR cmdLine[CMDLINE_SIZE];
   size = CMDLINE_SIZE;
   p = Concat(cmdLine, L"\"", &size);
   p = Concat(p, crashReporterPath, &size);
   p = Concat(p, L"\" \"", &size);
@@ -1221,17 +1236,17 @@ nsresult SetExceptionHandler(nsIFile* aX
   isSafeToDump = true;
 
   // now set the exception handler
 #ifdef XP_LINUX
   MinidumpDescriptor descriptor(tempPath.get());
 #endif
 
 #ifdef XP_WIN
-  NotePreviousUnhandledExceptionFilter();
+  previousUnhandledExceptionFilter = GetUnhandledExceptionFilter();
 #endif
 
   gExceptionHandler = new google_breakpad::
     ExceptionHandler(
 #ifdef XP_LINUX
                      descriptor,
 #else
                      tempPath.get(),
@@ -1261,16 +1276,23 @@ nsresult SetExceptionHandler(nsIFile* aX
 #endif // XP_WIN32
 
   if (!gExceptionHandler)
     return NS_ERROR_OUT_OF_MEMORY;
 
 #ifdef XP_WIN
   gExceptionHandler->set_handle_debug_exceptions(true);
   
+#ifdef _WIN64
+  // Tell JS about the new filter before we disable SetUnhandledExceptionFilter
+  sUnhandledExceptionFilter = GetUnhandledExceptionFilter();
+  if (sUnhandledExceptionFilter)
+      js::SetJitExceptionHandler(JitExceptionHandler);
+#endif
+
   // protect the crash reporter from being unloaded
   gBlockUnhandledExceptionFilter = true;
   gKernel32Intercept.Init("kernel32.dll");
   bool ok = gKernel32Intercept.AddHook("SetUnhandledExceptionFilter",
           reinterpret_cast<intptr_t>(patched_SetUnhandledExceptionFilter),
           (void**) &stub_SetUnhandledExceptionFilter);
 
 #ifdef DEBUG