Bug 844196 - Register a JitExceptionHandler for breakpad (r=bsmedberg)
--- 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