зеркало из https://github.com/mozilla/gecko-dev.git
bug 1275780 - capture Rust panic message in crash reports. r=froydnj
MozReview-Commit-ID: IUlYqPEtkgg --HG-- extra : rebase_source : c328db9b979eb2ff1f469b6ebc4a63e7ac337c63
This commit is contained in:
Родитель
5f9adc61f1
Коммит
2c431cb961
|
@ -116,6 +116,13 @@ using google_breakpad::PageAllocator;
|
|||
using namespace mozilla;
|
||||
using mozilla::ipc::CrashReporterClient;
|
||||
|
||||
// From toolkit/library/rust/shared/lib.rs
|
||||
extern "C" {
|
||||
void install_rust_panic_hook();
|
||||
bool get_rust_panic_reason(char** reason, size_t* length);
|
||||
}
|
||||
|
||||
|
||||
namespace CrashReporter {
|
||||
|
||||
#ifdef XP_WIN32
|
||||
|
@ -1131,7 +1138,17 @@ bool MinidumpCallback(
|
|||
WriteGlobalMemoryStatus(&apiData, &eventFile);
|
||||
#endif // XP_WIN
|
||||
|
||||
if (gMozCrashReason) {
|
||||
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.
|
||||
WriteLiteral(apiData, "MozCrashReason=");
|
||||
apiData.WriteBuffer(rust_panic_reason, rust_panic_len);
|
||||
WriteLiteral(apiData, "\n");
|
||||
WriteLiteral(eventFile, "MozCrashReason=");
|
||||
eventFile.WriteBuffer(rust_panic_reason, rust_panic_len);
|
||||
WriteLiteral(eventFile, "\n");
|
||||
} else if (gMozCrashReason) {
|
||||
WriteAnnotation(apiData, "MozCrashReason", gMozCrashReason);
|
||||
WriteAnnotation(eventFile, "MozCrashReason", gMozCrashReason);
|
||||
}
|
||||
|
@ -1577,6 +1594,8 @@ nsresult SetExceptionHandler(nsIFile* aXREDirectory,
|
|||
if (gExceptionHandler)
|
||||
return NS_ERROR_ALREADY_INITIALIZED;
|
||||
|
||||
install_rust_panic_hook();
|
||||
|
||||
#if !defined(DEBUG) || defined(MOZ_WIDGET_GONK)
|
||||
// In non-debug builds, enable the crash reporter by default, and allow
|
||||
// disabling it with the MOZ_CRASHREPORTER_DISABLE environment variable.
|
||||
|
|
|
@ -4,7 +4,7 @@ function run_test() {
|
|||
Components.classes["@mozilla.org/xpcom/debug;1"].getService(Components.interfaces.nsIDebug2).rustPanic("OH NO");
|
||||
},
|
||||
function(mdump, extra) {
|
||||
//TODO: check some extra things?
|
||||
do_check_eq(extra.MozCrashReason, "OH NO");
|
||||
},
|
||||
// process will exit with a zero exit status
|
||||
true);
|
||||
|
|
|
@ -11,11 +11,58 @@ extern crate rust_url_capi;
|
|||
#[cfg(feature = "quantum_render")]
|
||||
extern crate webrender_bindings;
|
||||
|
||||
use std::boxed::Box;
|
||||
use std::ffi::CStr;
|
||||
use std::os::raw::c_char;
|
||||
use std::panic;
|
||||
|
||||
/// Used to implement `nsIDebug2::RustPanic` for testing purposes.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn intentional_panic(message: *const c_char) {
|
||||
panic!("{}", unsafe { CStr::from_ptr(message) }.to_string_lossy());
|
||||
}
|
||||
|
||||
/// Contains the panic message, if set.
|
||||
static mut PANIC_REASON: Option<(*const str, usize)> = None;
|
||||
|
||||
/// Configure a panic hook to capture panic messages for crash reports.
|
||||
///
|
||||
/// We don't store this in `gMozCrashReason` because:
|
||||
/// a) Rust strings aren't null-terminated, so we'd have to allocate
|
||||
/// memory to get a null-terminated string
|
||||
/// b) The panic=abort handler is going to call `abort()` on non-Windows,
|
||||
/// which is `mozalloc_abort` for us, which will use `MOZ_CRASH` and
|
||||
/// overwrite `gMozCrashReason` with an unhelpful string.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn install_rust_panic_hook() {
|
||||
panic::set_hook(Box::new(|info| {
|
||||
// Try to handle &str/String payloads, which should handle 99% of cases.
|
||||
let payload = info.payload();
|
||||
// We'll hold a raw *const str here, but it will be OK because
|
||||
// Rust is going to abort the process before the payload could be
|
||||
// deallocated.
|
||||
if let Some(s) = payload.downcast_ref::<&str>() {
|
||||
unsafe { PANIC_REASON = Some((*s as *const str, s.len())) }
|
||||
} else if let Some(s) = payload.downcast_ref::<String>() {
|
||||
unsafe { PANIC_REASON = Some((s.as_str() as *const str, s.len())) }
|
||||
} else {
|
||||
// Not the most helpful thing, but seems unlikely to happen
|
||||
// in practice.
|
||||
println!("Unhandled panic payload!");
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn get_rust_panic_reason(reason: *mut *const c_char, length: *mut usize) -> bool {
|
||||
unsafe {
|
||||
match PANIC_REASON {
|
||||
Some((s, len)) => {
|
||||
*reason = s as *const c_char;
|
||||
*length = len;
|
||||
true
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче