--- a/toolkit/crashreporter/nsExceptionHandler.cpp
+++ b/toolkit/crashreporter/nsExceptionHandler.cpp
@@ -1,15 +1,18 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsExceptionHandler.h"
+
+#include "nsAppDirectoryServiceDefs.h"
+#include "nsDirectoryServiceDefs.h"
#include "nsDataHashtable.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/dom/CrashReporterChild.h"
#include "mozilla/Services.h"
#include "nsIObserverService.h"
#include "mozilla/unused.h"
#include "mozilla/Snprintf.h"
#include "mozilla/SyncRunnable.h"
@@ -116,18 +119,17 @@ typedef wchar_t XP_CHAR;
typedef std::wstring xpstring;
#define XP_TEXT(x) L##x
#define CONVERT_XP_CHAR_TO_UTF16(x) x
#define XP_STRLEN(x) wcslen(x)
#define my_strlen strlen
#define CRASH_REPORTER_FILENAME "crashreporter.exe"
#define PATH_SEPARATOR "\\"
#define XP_PATH_SEPARATOR L"\\"
-// sort of arbitrary, but MAX_PATH is kinda small
-#define XP_PATH_MAX 4096
+#define XP_PATH_MAX (MAX_PATH + 1)
// "<reporter path>" "<minidump path>"
#define CMDLINE_SIZE ((XP_PATH_MAX * 2) + 6)
#ifdef _USE_32BIT_TIME_T
#define XP_TTOA(time, buffer, base) ltoa(time, buffer, base)
#else
#define XP_TTOA(time, buffer, base) _i64toa(time, buffer, base)
#endif
#define XP_STOA(size, buffer, base) _ui64toa(size, buffer, base)
@@ -152,20 +154,27 @@ typedef std::string xpstring;
#define sys_close close
#define sys_fork fork
#define sys_open open
#define sys_read read
#define sys_write write
#endif
#endif // XP_WIN32
+#if defined(__GNUC__)
+#define MAYBE_UNUSED __attribute__((unused))
+#else
+#define MAYBE_UNUSED
+#endif // defined(__GNUC__)
+
#ifndef XP_LINUX
static const XP_CHAR dumpFileExtension[] = XP_TEXT(".dmp");
#endif
+static const XP_CHAR childCrashAnnotationBaseName[] = XP_TEXT("GeckoChildCrash");
static const XP_CHAR extraFileExtension[] = XP_TEXT(".extra");
static const XP_CHAR memoryReportExtension[] = XP_TEXT(".memory.json.gz");
// A whitelist of crash annotations which do not contain sensitive data
// and are saved in the crash record and sent with Firefox Health Report.
static char const * const kCrashEventAnnotations[] = {
"AsyncShutdownTimeout",
"BuildID",
@@ -250,16 +259,21 @@ static uint32_t eventloopNestingLevel =
// Avoid a race during application termination.
static Mutex* dumpSafetyLock;
static bool isSafeToDump = false;
// OOP crash reporting
static CrashGenerationServer* crashServer; // chrome process has this
+#if (defined(XP_MACOSX) || defined(XP_WIN)) && defined(MOZ_CONTENT_SANDBOX)
+// This field is only valid in the chrome process, not content.
+static xpstring* contentProcessTmpDir = nullptr;
+#endif
+
# if defined(XP_WIN) || defined(XP_MACOSX)
// If crash reporting is disabled, we hand out this "null" pipe to the
// child process and don't attempt to connect to a parent server.
static const char kNullNotifyPipe[] = "-";
static char* childCrashNotifyPipe;
# elif defined(XP_LINUX)
static int serverSocketFd = -1;
@@ -481,22 +495,44 @@ CreateFileFromPath(const xpstring& path,
NS_NewLocalFile(nsDependentString(path.c_str()), false, file);
}
static void
CreateFileFromPath(const wchar_t* path, nsIFile** file)
{
CreateFileFromPath(std::wstring(path), file);
}
+
+static xpstring*
+CreatePathFromFile(nsIFile* file)
+{
+ nsAutoString path;
+ nsresult rv = file->GetPath(path);
+ if (NS_FAILED(rv)) {
+ return nullptr;
+ }
+ return new xpstring(path.get(), path.Length());
+}
#else
static void
CreateFileFromPath(const xpstring& path, nsIFile** file)
{
NS_NewNativeLocalFile(nsDependentCString(path.c_str()), false, file);
}
+
+MAYBE_UNUSED static xpstring*
+CreatePathFromFile(nsIFile* file)
+{
+ nsAutoCString path;
+ nsresult rv = file->GetNativePath(path);
+ if (NS_FAILED(rv)) {
+ return nullptr;
+ }
+ return new xpstring(path.get(), path.Length());
+}
#endif
static XP_CHAR*
Concat(XP_CHAR* str, const XP_CHAR* toAppend, int* size)
{
int appendLen = XP_STRLEN(toAppend);
if (appendLen >= *size) appendLen = *size - 1;
@@ -575,16 +611,17 @@ bool copy_file(const char* from, const c
sys_close(fdfrom);
sys_close(fdto);
return ok;
}
#endif
#ifdef XP_WIN
+
class PlatformWriter
{
public:
PlatformWriter()
: mHandle(INVALID_HANDLE_VALUE)
{ }
explicit PlatformWriter(const wchar_t* path)
@@ -693,16 +730,44 @@ static void
WriteAnnotation(PlatformWriter& pw, const char (&name)[N],
const char* value) {
WriteLiteral(pw, name);
WriteLiteral(pw, "=");
WriteString(pw, value);
WriteLiteral(pw, "\n");
};
+/**
+ * If minidump_id is null, we assume that dump_path contains the full
+ * dump file path.
+ */
+static void
+OpenAPIData(PlatformWriter& aWriter,
+ const XP_CHAR* dump_path, const XP_CHAR* minidump_id = nullptr
+ )
+{
+ static XP_CHAR extraDataPath[XP_PATH_MAX];
+ int size = XP_PATH_MAX;
+ XP_CHAR* p;
+ if (minidump_id) {
+ p = Concat(extraDataPath, dump_path, &size);
+ p = Concat(p, XP_PATH_SEPARATOR, &size);
+ p = Concat(p, minidump_id, &size);
+ } else {
+ p = Concat(extraDataPath, dump_path, &size);
+ // Skip back past the .dmp extension, if any.
+ if (*(p - 4) == XP_TEXT('.')) {
+ p -= 4;
+ size += 4;
+ }
+ }
+ Concat(p, extraFileExtension, &size);
+ aWriter.Open(extraDataPath);
+}
+
bool MinidumpCallback(
#ifdef XP_LINUX
const MinidumpDescriptor& descriptor,
#else
const XP_CHAR* dump_path,
const XP_CHAR* minidump_id,
#endif
void* context,
@@ -721,29 +786,16 @@ bool MinidumpCallback(
p = Concat(minidumpPath, dump_path, &size);
p = Concat(p, XP_PATH_SEPARATOR, &size);
p = Concat(p, minidump_id, &size);
Concat(p, dumpFileExtension, &size);
#else
Concat(minidumpPath, descriptor.path(), &size);
#endif
- static XP_CHAR extraDataPath[XP_PATH_MAX];
- size = XP_PATH_MAX;
-#ifndef XP_LINUX
- p = Concat(extraDataPath, dump_path, &size);
- p = Concat(p, XP_PATH_SEPARATOR, &size);
- p = Concat(p, minidump_id, &size);
-#else
- p = Concat(extraDataPath, descriptor.path(), &size);
- // Skip back past the .dmp extension.
- p -= 4;
-#endif
- Concat(p, extraFileExtension, &size);
-
static XP_CHAR memoryReportLocalPath[XP_PATH_MAX];
size = XP_PATH_MAX;
#ifndef XP_LINUX
p = Concat(memoryReportLocalPath, dump_path, &size);
p = Concat(p, XP_PATH_SEPARATOR, &size);
p = Concat(p, minidump_id, &size);
#else
p = Concat(memoryReportLocalPath, descriptor.path(), &size);
@@ -855,17 +907,21 @@ bool MinidumpCallback(
WriteLiteral(eventFile, "\n");
if (crashEventAPIData) {
eventFile.WriteBuffer(crashEventAPIData->get(), crashEventAPIData->Length());
}
}
if (!crashReporterAPIData->IsEmpty()) {
// write out API data
- apiData.Open(extraDataPath);
+#ifdef XP_LINUX
+ OpenAPIData(apiData, descriptor.path());
+#else
+ OpenAPIData(apiData, dump_path, minidump_id);
+#endif
apiData.WriteBuffer(crashReporterAPIData->get(), crashReporterAPIData->Length());
}
WriteAnnotation(apiData, "CrashTime", crashTimeString);
WriteAnnotation(apiData, "UptimeTS", uptimeTSString);
if (timeSinceLastCrash != 0) {
WriteAnnotation(apiData, "SecondsSinceLastCrash",
timeSinceLastCrashString);
@@ -1044,16 +1100,164 @@ bool MinidumpCallback(
#endif
}
#endif // XP_MACOSX
#endif // XP_UNIX
return returnValue;
}
+#if defined(XP_MACOSX) || defined(__ANDROID__)
+static size_t
+EnsureTrailingSlash(char* aBuf, size_t aBufLen)
+{
+ size_t len = XP_STRLEN(aBuf);
+ if ((len + 2) < aBufLen && aBuf[len - 1] != '/') {
+ aBuf[len] = '/';
+ ++len;
+ aBuf[len] = 0;
+ }
+ return len;
+}
+#endif
+
+#if defined(XP_WIN32)
+
+static size_t
+BuildTempPath(wchar_t* aBuf, size_t aBufLen)
+{
+ // first figure out buffer size
+ DWORD pathLen = GetTempPath(0, nullptr);
+ if (pathLen == 0 || pathLen >= aBufLen) {
+ return 0;
+ }
+
+ return GetTempPath(pathLen, aBuf);
+}
+
+#elif defined(XP_MACOSX)
+
+static size_t
+BuildTempPath(char* aBuf, size_t aBufLen)
+{
+ if (aBufLen < PATH_MAX) {
+ return 0;
+ }
+
+ FSRef fsRef;
+ OSErr err = FSFindFolder(kUserDomain, kTemporaryFolderType,
+ kCreateFolder, &fsRef);
+ if (err != noErr) {
+ return 0;
+ }
+
+ OSStatus status = FSRefMakePath(&fsRef, (UInt8*)aBuf, PATH_MAX);
+ if (status != noErr) {
+ return 0;
+ }
+
+ return EnsureTrailingSlash(aBuf, aBufLen);
+}
+
+#elif defined(__ANDROID__)
+
+static size_t
+BuildTempPath(char* aBuf, size_t aBufLen)
+{
+ // GeckoAppShell or Gonk's init.rc sets this in the environment
+ const char *tempenv = PR_GetEnv("TMPDIR");
+ if (!tempenv) {
+ return false;
+ }
+ int size = (int)aBufLen;
+ Concat(aBuf, tempenv, &size);
+ return EnsureTrailingSlash(aBuf, aBufLen);
+}
+
+#elif defined(XP_UNIX)
+
+static size_t
+BuildTempPath(char* aBuf, size_t aBufLen)
+{
+ // we assume it's always /tmp on unix systems
+ NS_NAMED_LITERAL_CSTRING(tmpPath, "/tmp/");
+ int size = (int)aBufLen;
+ Concat(aBuf, tmpPath.get(), &size);
+ return tmpPath.Length();
+}
+
+#else
+#error "Implement this for your platform"
+#endif
+
+template <typename CharT, size_t N>
+static size_t
+BuildTempPath(CharT (&aBuf)[N])
+{
+ static_assert(N >= XP_PATH_MAX, "char array length is too small");
+ return BuildTempPath(&aBuf[0], N);
+}
+
+template <typename PathStringT>
+static bool
+BuildTempPath(PathStringT& aResult)
+{
+ aResult.SetLength(XP_PATH_MAX);
+ size_t actualLen = BuildTempPath(aResult.BeginWriting(), XP_PATH_MAX);
+ if (!actualLen) {
+ return false;
+ }
+ aResult.SetLength(actualLen);
+ return true;
+}
+
+static void
+PrepareChildExceptionTimeAnnotations()
+{
+ MOZ_ASSERT(!XRE_IsParentProcess());
+ static XP_CHAR tempPath[XP_PATH_MAX] = {0};
+
+ // Get the temp path
+ size_t tempPathLen = BuildTempPath(tempPath);
+ if (!tempPathLen) {
+ return;
+ }
+
+ // Generate and append the file name
+ int size = XP_PATH_MAX - tempPathLen;
+ XP_CHAR* p = tempPath + tempPathLen;
+ p = Concat(p, childCrashAnnotationBaseName, &size);
+ XP_CHAR pidBuffer[32] = XP_TEXT("");
+#if defined(XP_WIN32)
+ _ui64tow(GetCurrentProcessId(), pidBuffer, 10);
+#else
+ XP_STOA(getpid(), pidBuffer, 10);
+#endif
+ p = Concat(p, pidBuffer, &size);
+
+ // Now open the file...
+ PlatformWriter apiData;
+ OpenAPIData(apiData, tempPath);
+
+ // ...and write out any annotations. These should be escaped if necessary
+ // (but don't call EscapeAnnotation here, because it touches the heap).
+ char oomAllocationSizeBuffer[32] = "";
+ if (gOOMAllocationSize) {
+ XP_STOA(gOOMAllocationSize, oomAllocationSizeBuffer, 10);
+ }
+
+ if (oomAllocationSizeBuffer[0]) {
+ WriteAnnotation(apiData, "OOMAllocationSize", oomAllocationSizeBuffer);
+ }
+
+ if (gMozCrashReason) {
+ WriteAnnotation(apiData, "MozCrashReason", gMozCrashReason);
+ }
+}
+
#ifdef XP_WIN
static void
ReserveBreakpadVM()
{
if (!gBreakpadReservedVM) {
gBreakpadReservedVM = VirtualAlloc(nullptr, kReserveSize, MEM_RESERVE,
PAGE_NOACCESS);
}
@@ -1094,16 +1298,28 @@ static bool FPEFilter(void* context, EXC
case STATUS_FLOAT_MULTIPLE_FAULTS:
case STATUS_FLOAT_MULTIPLE_TRAPS:
return false; // Don't write minidump, continue exception search
}
mozilla::IOInterposer::Disable();
FreeBreakpadVM();
return true;
}
+
+static bool
+ChildFPEFilter(void* context, EXCEPTION_POINTERS* exinfo,
+ MDRawAssertionInfo* assertion)
+{
+ bool result = FPEFilter(context, exinfo, assertion);
+ if (result) {
+ PrepareChildExceptionTimeAnnotations();
+ }
+ return result;
+}
+
#endif // XP_WIN
static bool ShouldReport()
{
// this environment variable prevents us from launching
// the crash reporter client
const char *envvar = PR_GetEnv("MOZ_CRASHREPORTER_NO_REPORT");
if (envvar && *envvar) {
@@ -1113,24 +1329,33 @@ static bool ShouldReport()
envvar = PR_GetEnv("MOZ_CRASHREPORTER_FULLDUMP");
if (envvar && *envvar) {
return false;
}
return true;
}
-namespace {
- bool Filter(void* context) {
- mozilla::IOInterposer::Disable();
- return true;
+static bool
+Filter(void* context)
+{
+ mozilla::IOInterposer::Disable();
+ return true;
+}
+
+static bool
+ChildFilter(void* context)
+{
+ bool result = Filter(context);
+ if (result) {
+ PrepareChildExceptionTimeAnnotations();
}
+ return result;
}
-
nsresult SetExceptionHandler(nsIFile* aXREDirectory,
bool force/*=false*/)
{
if (gExceptionHandler)
return NS_ERROR_ALREADY_INITIALIZED;
#if !defined(DEBUG) || defined(MOZ_WIDGET_GONK)
// In non-debug builds, enable the crash reporter by default, and allow
@@ -1214,51 +1439,22 @@ nsresult SetExceptionHandler(nsIFile* aX
crashReporterPath = ToNewCString(package);
}
#endif
}
// get temp path to use for minidump path
#if defined(XP_WIN32)
nsString tempPath;
-
- // first figure out buffer size
- int pathLen = GetTempPath(0, nullptr);
- if (pathLen == 0)
- return NS_ERROR_FAILURE;
-
- tempPath.SetLength(pathLen);
- GetTempPath(pathLen, (LPWSTR)tempPath.BeginWriting());
-#elif defined(XP_MACOSX)
+#else
nsCString tempPath;
- FSRef fsRef;
- OSErr err = FSFindFolder(kUserDomain, kTemporaryFolderType,
- kCreateFolder, &fsRef);
- if (err != noErr)
+#endif
+ if (!BuildTempPath(tempPath)) {
return NS_ERROR_FAILURE;
-
- char path[PATH_MAX];
- OSStatus status = FSRefMakePath(&fsRef, (UInt8*)path, PATH_MAX);
- if (status != noErr)
- return NS_ERROR_FAILURE;
-
- tempPath = path;
-
-#elif defined(__ANDROID__)
- // GeckoAppShell or Gonk's init.rc sets this in the environment
- const char *tempenv = PR_GetEnv("TMPDIR");
- if (!tempenv)
- return NS_ERROR_FAILURE;
- nsCString tempPath(tempenv);
-#elif defined(XP_UNIX)
- // we assume it's always /tmp on unix systems
- nsCString tempPath = NS_LITERAL_CSTRING("/tmp/");
-#else
-#error "Implement this for your platform"
-#endif
+ }
#ifdef XP_MACOSX
// Initialize spawn attributes, since this calls malloc.
if (posix_spawnattr_init(&spawnattr) != 0) {
return NS_ERROR_FAILURE;
}
// Set spawn attributes.
@@ -2672,34 +2868,174 @@ WriteExtraData(nsIFile* extraFile,
}
bool
AppendExtraData(nsIFile* extraFile, const AnnotationTable& data)
{
return WriteExtraData(extraFile, data, Blacklist());
}
+static bool
+GetExtraFileForChildPid(nsIFile* aMinidump, uint32_t aPid, nsIFile** aExtraFile)
+{
+ MOZ_ASSERT(XRE_IsParentProcess());
+
+ nsCOMPtr<nsIFile> extraFile;
+ nsresult rv;
+
+#if defined(XP_WIN) || defined(XP_MACOSX)
+# if defined(MOZ_CONTENT_SANDBOX)
+ if (!contentProcessTmpDir) {
+ return false;
+ }
+ CreateFileFromPath(*contentProcessTmpDir, getter_AddRefs(extraFile));
+ if (!extraFile) {
+ return false;
+ }
+# else
+ rv = aMinidump->Clone(getter_AddRefs(extraFile));
+ if (NS_FAILED(rv)) {
+ return false;
+ }
+# endif // defined(MOZ_CONTENT_SANDBOX)
+#elif defined(XP_UNIX)
+ rv = NS_NewLocalFile(NS_LITERAL_STRING("/tmp"), false,
+ getter_AddRefs(extraFile));
+ if (NS_FAILED(rv)) {
+ return false;
+ }
+#else
+#error "Implement this for your platform"
+#endif
+
+ nsAutoString leafName;
+#if defined(XP_WIN)
+ leafName.AppendPrintf("%S%u%S", childCrashAnnotationBaseName, aPid,
+ extraFileExtension);
+#else
+ leafName.AppendPrintf("%s%u%s", childCrashAnnotationBaseName, aPid,
+ extraFileExtension);
+#endif
+
+#if defined(XP_WIN) || defined(XP_MACOSX)
+# if defined(MOZ_CONTENT_SANDBOX)
+ rv = extraFile->Append(leafName);
+ if (NS_FAILED(rv)) {
+ return false;
+ }
+# else
+ rv = extraFile->SetLeafName(leafName);
+ if (NS_FAILED(rv)) {
+ return false;
+ }
+# endif // defined(MOZ_CONTENT_SANDBOX)
+#elif defined(XP_UNIX)
+ rv = extraFile->Append(leafName);
+ if (NS_FAILED(rv)) {
+ return false;
+ }
+#else
+#error "Implement this for your platform"
+#endif
+
+ extraFile.forget(aExtraFile);
+ return true;
+}
static bool
+IsDataEscaped(char* aData)
+{
+ if (strchr(aData, '\n')) {
+ // There should not be any newlines
+ return false;
+ }
+ char* pos = aData;
+ while ((pos = strchr(pos, '\\'))) {
+ if (*(pos + 1) != '\\') {
+ return false;
+ }
+ // Add 2 to account for the second pos
+ pos += 2;
+ }
+ return true;
+}
+
+static void
+ReadAndValidateExceptionTimeAnnotations(FILE*& aFd,
+ AnnotationTable& aAnnotations)
+{
+ char line[0x1000];
+ while (fgets(line, sizeof(line), aFd)) {
+ char* data = strchr(line, '=');
+ if (!data) {
+ // bad data? Abort!
+ break;
+ }
+ // Move past the '='
+ *data = 0;
+ ++data;
+ size_t dataLen = strlen(data);
+ // Chop off any trailing newline
+ if (dataLen > 0 && data[dataLen - 1] == '\n') {
+ data[dataLen - 1] = 0;
+ --dataLen;
+ }
+ // There should not be any newlines in the key
+ if (strchr(line, '\n')) {
+ break;
+ }
+ // Data should have been escaped by the child
+ if (!IsDataEscaped(data)) {
+ break;
+ }
+ // Looks good, save the (line,data) pair
+ aAnnotations.Put(nsDependentCString(line),
+ nsDependentCString(data, dataLen));
+ }
+}
+
+/**
+ * NOTE: One side effect of this function is that it deletes the
+ * GeckoChildCrash<pid>.extra file if it exists, once processed.
+ */
+static bool
WriteExtraForMinidump(nsIFile* minidump,
+ uint32_t pid,
const Blacklist& blacklist,
nsIFile** extraFile)
{
nsCOMPtr<nsIFile> extra;
- if (!GetExtraFileForMinidump(minidump, getter_AddRefs(extra)))
+ if (!GetExtraFileForMinidump(minidump, getter_AddRefs(extra))) {
return false;
+ }
if (!WriteExtraData(extra, *crashReporterAPIData_Hash,
blacklist,
true /*write crash time*/,
- true /*truncate*/))
+ true /*truncate*/)) {
return false;
-
- *extraFile = nullptr;
- extra.swap(*extraFile);
+ }
+
+ nsCOMPtr<nsIFile> exceptionTimeExtra;
+ FILE* fd;
+ if (pid && GetExtraFileForChildPid(minidump, pid,
+ getter_AddRefs(exceptionTimeExtra)) &&
+ NS_SUCCEEDED(exceptionTimeExtra->OpenANSIFileDesc("r", &fd))) {
+ AnnotationTable exceptionTimeAnnotations;
+ ReadAndValidateExceptionTimeAnnotations(fd, exceptionTimeAnnotations);
+ fclose(fd);
+ if (!AppendExtraData(extra, exceptionTimeAnnotations)) {
+ return false;
+ }
+ }
+ if (exceptionTimeExtra) {
+ exceptionTimeExtra->Remove(false);
+ }
+
+ extra.forget(extraFile);
return true;
}
// It really only makes sense to call this function when
// ShouldReport() is true.
static bool
MoveToPending(nsIFile* dumpFile, nsIFile* extraFile)
@@ -2743,32 +3079,33 @@ OnChildProcessDumpRequested(void* aConte
CreateFileFromPath(
#ifdef XP_MACOSX
aFilePath,
#else
*aFilePath,
#endif
getter_AddRefs(minidump));
- if (!WriteExtraForMinidump(minidump,
+ uint32_t pid =
+#ifdef XP_MACOSX
+ aClientInfo.pid();
+#else
+ aClientInfo->pid();
+#endif
+
+ if (!WriteExtraForMinidump(minidump, pid,
Blacklist(kSubprocessBlacklist,
ArrayLength(kSubprocessBlacklist)),
getter_AddRefs(extraFile)))
return;
if (ShouldReport())
MoveToPending(minidump, extraFile);
{
- uint32_t pid =
-#ifdef XP_MACOSX
- aClientInfo.pid();
-#else
- aClientInfo->pid();
-#endif
#ifdef MOZ_CRASHREPORTER_INJECTOR
bool runCallback;
#endif
{
MutexAutoLock lock(*dumpMapLock);
ChildProcessData* pd = pidToMinidump->PutEntry(pid);
MOZ_ASSERT(!pd->minidump);
@@ -2786,23 +3123,16 @@ OnChildProcessDumpRequested(void* aConte
}
static bool
OOPInitialized()
{
return pidToMinidump != nullptr;
}
-#ifdef XP_MACOSX
-static bool ChildFilter(void *context) {
- mozilla::IOInterposer::Disable();
- return true;
-}
-#endif
-
void
OOPInit()
{
class ProxyToMainThread : public nsRunnable
{
public:
NS_IMETHOD Run() {
OOPInit();
@@ -2819,16 +3149,24 @@ OOPInit()
if (OOPInitialized())
return;
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(gExceptionHandler != nullptr,
"attempt to initialize OOP crash reporter before in-process crashreporter!");
+#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
+ nsCOMPtr<nsIFile> tmpDir;
+ nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tmpDir));
+ if (NS_SUCCEEDED(rv)) {
+ contentProcessTmpDir = CreatePathFromFile(tmpDir);
+ }
+#endif
+
#if defined(XP_WIN)
childCrashNotifyPipe =
PR_smprintf("\\\\.\\pipe\\gecko-crash-server-pipe.%i",
static_cast<int>(::GetCurrentProcessId()));
const std::wstring dumpPath = gExceptionHandler->dump_path();
crashServer = new CrashGenerationServer(
std::wstring(NS_ConvertASCIItoUTF16(childCrashNotifyPipe).get()),
@@ -2857,17 +3195,17 @@ OOPInit()
#elif defined(XP_MACOSX)
childCrashNotifyPipe =
PR_smprintf("gecko-crash-server-pipe.%i",
static_cast<int>(getpid()));
const std::string dumpPath = gExceptionHandler->dump_path();
crashServer = new CrashGenerationServer(
childCrashNotifyPipe,
- ChildFilter,
+ nullptr,
nullptr,
OnChildProcessDumpRequested, nullptr,
nullptr, nullptr,
true, // automatically generate dumps
dumpPath);
#endif
if (!crashServer->Start())
@@ -3065,26 +3403,26 @@ SetRemoteExceptionHandler(const nsACStri
// crash reporting is disabled
if (crashPipe.Equals(kNullNotifyPipe))
return true;
MOZ_ASSERT(!gExceptionHandler, "crash client already init'd");
gExceptionHandler = new google_breakpad::
ExceptionHandler(L"",
- FPEFilter,
+ ChildFPEFilter,
nullptr, // no minidump callback
nullptr, // no callback context
google_breakpad::ExceptionHandler::HANDLER_ALL,
MiniDumpNormal,
NS_ConvertASCIItoUTF16(crashPipe).get(),
nullptr);
-#ifdef XP_WIN
gExceptionHandler->set_handle_debug_exceptions(true);
-#endif
+
+ mozalloc_set_oom_abort_handler(AnnotateOOMAllocationSize);
// we either do remote or nothing, no fallback to regular crash reporting
return gExceptionHandler->IsOutOfProcess();
}
//--------------------------------------------------
#elif defined(XP_LINUX)
@@ -3107,37 +3445,36 @@ CreateNotificationPipeForChild(int* chil
}
// Child-side API
bool
SetRemoteExceptionHandler()
{
MOZ_ASSERT(!gExceptionHandler, "crash client already init'd");
-#ifndef XP_LINUX
- xpstring path = "";
-#else
// MinidumpDescriptor requires a non-empty path.
google_breakpad::MinidumpDescriptor path(".");
-#endif
+
gExceptionHandler = new google_breakpad::
ExceptionHandler(path,
- nullptr, // no filter callback
+ ChildFilter,
nullptr, // no minidump callback
nullptr, // no callback context
true, // install signal handlers
kMagicChildCrashReportFd);
if (gDelayedAnnotations) {
for (uint32_t i = 0; i < gDelayedAnnotations->Length(); i++) {
gDelayedAnnotations->ElementAt(i)->Run();
}
delete gDelayedAnnotations;
}
+ mozalloc_set_oom_abort_handler(AnnotateOOMAllocationSize);
+
// we either do remote or nothing, no fallback to regular crash reporting
return gExceptionHandler->IsOutOfProcess();
}
//--------------------------------------------------
#elif defined(XP_MACOSX)
// Child-side API
bool
@@ -3146,22 +3483,24 @@ SetRemoteExceptionHandler(const nsACStri
// crash reporting is disabled
if (crashPipe.Equals(kNullNotifyPipe))
return true;
MOZ_ASSERT(!gExceptionHandler, "crash client already init'd");
gExceptionHandler = new google_breakpad::
ExceptionHandler("",
- Filter,
+ ChildFilter,
nullptr, // no minidump callback
nullptr, // no callback context
true, // install signal handlers
crashPipe.BeginReading());
+ mozalloc_set_oom_abort_handler(AnnotateOOMAllocationSize);
+
// we either do remote or nothing, no fallback to regular crash reporting
return gExceptionHandler->IsOutOfProcess();
}
#endif // XP_WIN
bool
TakeMinidumpForChild(uint32_t childPid, nsIFile** dump, uint32_t* aSequence)
@@ -3265,17 +3604,17 @@ PairedDumpCallbackExtra(
#ifdef XP_WIN32
nullptr, nullptr,
#endif
succeeded);
nsCOMPtr<nsIFile>& minidump = *static_cast< nsCOMPtr<nsIFile>* >(context);
nsCOMPtr<nsIFile> extra;
- return WriteExtraForMinidump(minidump, Blacklist(), getter_AddRefs(extra));
+ return WriteExtraForMinidump(minidump, 0, Blacklist(), getter_AddRefs(extra));
}
ThreadId
CurrentThreadId()
{
#if defined(XP_WIN)
return ::GetCurrentThreadId();
#elif defined(XP_LINUX)