diff --git a/toolkit/crashreporter/nsExceptionHandler.cpp b/toolkit/crashreporter/nsExceptionHandler.cpp --- a/toolkit/crashreporter/nsExceptionHandler.cpp +++ b/toolkit/crashreporter/nsExceptionHandler.cpp @@ -885,10 +885,46 @@ return true; } #endif +void +WriteEscapedMozCrashReason(PlatformWriter& aWriter) +{ + const char *reason; + size_t len; + char *rust_panic_reason; + bool rust_panic = get_rust_panic_reason(&rust_panic_reason, &len); + + if (rust_panic) { + reason = rust_panic_reason; + } else if (gMozCrashReason != nullptr) { + reason = gMozCrashReason; + len = strlen(reason); + } else { + return; // No crash reason, bail out + } + + WriteString(aWriter, AnnotationToString(Annotation::MozCrashReason)); + WriteLiteral(aWriter, "="); + + // The crash reason might be non-null-terminated in the case of a rust panic, + // it has also not being escaped so escape it one character at a time and + // write out the resulting string. + for (size_t i = 0; i < len; i++) { + if (reason[i] == '\\') { + WriteLiteral(aWriter, "\\\\"); + } else if (reason[i] == '\n') { + WriteLiteral(aWriter, "\\n"); + } else { + aWriter.WriteBuffer(reason + i, 1); + } + } + + WriteLiteral(aWriter, "\n"); +} + // Callback invoked from breakpad's exception handler, this writes out the // last annotations after a crash occurs and launches the crash reporter client. // // This function is not declared static even though it's not used outside of // this file because of an issue in Fennec which prevents breakpad's exception @@ -1086,22 +1122,12 @@ } #endif WriteGlobalMemoryStatus(&apiData, &eventFile); #endif // XP_WIN - char* rust_panic_reason; - size_t rust_panic_len; - if (get_rust_panic_reason(&rust_panic_reason, &rust_panic_len)) { - // rust_panic_reason is not null-terminated. - WriteAnnotation(apiData, Annotation::MozCrashReason, rust_panic_reason, - rust_panic_len); - WriteAnnotation(eventFile, Annotation::MozCrashReason, rust_panic_reason, - rust_panic_len); - } else if (gMozCrashReason) { - WriteAnnotation(apiData, Annotation::MozCrashReason, gMozCrashReason); - WriteAnnotation(eventFile, Annotation::MozCrashReason, gMozCrashReason); - } + WriteEscapedMozCrashReason(apiData); + WriteEscapedMozCrashReason(eventFile); if (oomAllocationSizeBuffer[0]) { WriteAnnotation(apiData, Annotation::OOMAllocationSize, oomAllocationSizeBuffer); WriteAnnotation(eventFile, Annotation::OOMAllocationSize, @@ -1291,19 +1317,11 @@ if (oomAllocationSizeBuffer[0]) { WriteAnnotation(apiData, Annotation::OOMAllocationSize, oomAllocationSizeBuffer); } - char* rust_panic_reason; - size_t rust_panic_len; - if (get_rust_panic_reason(&rust_panic_reason, &rust_panic_len)) { - // rust_panic_reason is not null-terminated. - WriteAnnotation(apiData, Annotation::MozCrashReason, rust_panic_reason, - rust_panic_len); - } else if (gMozCrashReason) { - WriteAnnotation(apiData, Annotation::MozCrashReason, gMozCrashReason); - } + WriteEscapedMozCrashReason(apiData); std::function getThreadAnnotationCB = [&] (const char * aValue) -> void { if (aValue) { WriteAnnotation(apiData, Annotation::ThreadIdNameMapping, aValue); @@ -3054,11 +3072,11 @@ // There should not be any newlines return false; } char* pos = aData; while ((pos = strchr(pos, '\\'))) { - if (*(pos + 1) != '\\') { + if (*(pos + 1) != '\\' && *(pos + 1) != 'n') { return false; } // Add 2 to account for the second pos pos += 2; } diff --git a/toolkit/crashreporter/test/unit/test_crash_rust_panic.js b/toolkit/crashreporter/test/unit/test_crash_rust_panic.js --- a/toolkit/crashreporter/test/unit/test_crash_rust_panic.js +++ b/toolkit/crashreporter/test/unit/test_crash_rust_panic.js @@ -1,11 +1,11 @@ function run_test() { // Try crashing with a Rust panic do_crash(function() { - Cc["@mozilla.org/xpcom/debug;1"].getService(Ci.nsIDebug2).rustPanic("OH NO"); + Cc["@mozilla.org/xpcom/debug;1"].getService(Ci.nsIDebug2).rustPanic("OH NO\nOH NOES!"); }, function(mdump, extra) { - Assert.equal(extra.MozCrashReason, "OH NO"); + Assert.equal(extra.MozCrashReason, "OH NO\nOH NOES!"); }, // process will exit with a zero exit status true); } diff --git a/toolkit/crashreporter/test/unit/xpcshell.ini b/toolkit/crashreporter/test/unit/xpcshell.ini --- a/toolkit/crashreporter/test/unit/xpcshell.ini +++ b/toolkit/crashreporter/test/unit/xpcshell.ini @@ -6,10 +6,11 @@ crasher_subprocess_tail.js [test_crash_moz_crash.js] [test_crash_purevirtual.js] [test_crash_rust_panic.js] +[test_crash_rust_panic_multiline.js] [test_crash_after_js_oom_reported.js] [test_crash_after_js_oom_recovered.js] [test_crash_after_js_oom_reported_2.js] [test_crash_after_js_large_allocation_failure.js] [test_crash_after_js_large_allocation_failure_reporting.js] diff --git a/toolkit/crashreporter/test/unit_ipc/test_content_rust_panic.js b/toolkit/crashreporter/test/unit_ipc/test_content_rust_panic.js --- a/toolkit/crashreporter/test/unit_ipc/test_content_rust_panic.js +++ b/toolkit/crashreporter/test/unit_ipc/test_content_rust_panic.js @@ -10,12 +10,12 @@ // Try crashing with a Rust panic do_triggered_content_crash( function() { Cc["@mozilla.org/xpcom/debug;1"] .getService(Ci.nsIDebug2) - .rustPanic("OH NO"); + .rustPanic("OH NO\nOH NOES!"); }, function(mdump, extra) { - Assert.equal(extra.MozCrashReason, "OH NO"); + Assert.equal(extra.MozCrashReason, "OH NO\nOH NOES!"); } ); } diff --git a/toolkit/crashreporter/test/unit_ipc/xpcshell.ini b/toolkit/crashreporter/test/unit_ipc/xpcshell.ini --- a/toolkit/crashreporter/test/unit_ipc/xpcshell.ini +++ b/toolkit/crashreporter/test/unit_ipc/xpcshell.ini @@ -10,6 +10,7 @@ [test_content_exception_time_annotation.js] [test_content_oom_annotation_windows.js] skip-if = os != 'win' [test_content_memory_list.js] skip-if = os != 'win' -[test_content_rust_panic.js] \ No newline at end of file +[test_content_rust_panic.js] +[test_content_rust_panic_multiline.js]