| 1 | #![cfg(unix)] |
| 2 | |
| 3 | #[test] |
| 4 | fn crash_child() { |
| 5 | let Some(path) = std::env::var_os("SNOWBOUND_TEST_CRASH") else { |
| 6 | return; |
| 7 | }; |
| 8 | crash_report::hook("test", "native-test".into(), "test system".into(), |_| {}); |
| 9 | crash_report::set_path(path.into()).unwrap(); |
| 10 | #[cfg(target_os = "linux")] |
| 11 | { |
| 12 | extern "C" fn fatal(signal: i32, info: *mut libc::siginfo_t, _: *mut libc::c_void) { |
| 13 | unsafe { |
| 14 | crash_report::record_signal(signal, info); |
| 15 | libc::raise(signal); |
| 16 | } |
| 17 | } |
| 18 | let mut action: libc::sigaction = unsafe { std::mem::zeroed() }; |
| 19 | action.sa_sigaction = fatal as *const () as libc::sighandler_t; |
| 20 | action.sa_flags = libc::SA_SIGINFO | libc::SA_RESETHAND; |
| 21 | unsafe { |
| 22 | libc::sigaction(libc::SIGABRT, &action, std::ptr::null_mut()); |
| 23 | } |
| 24 | } |
| 25 | if std::env::var_os("SNOWBOUND_TEST_PANIC").is_some() { |
| 26 | crash_report::conceal("AI.one"); |
| 27 | let _ = std::panic::catch_unwind(|| panic!("Cannot read section AI")); |
| 28 | } |
| 29 | std::process::abort(); |
| 30 | } |
| 31 | |
| 32 | #[test] |
| 33 | fn fatal_signals_leave_a_report_and_preserve_the_first_panic() { |
| 34 | use std::{ |
| 35 | os::unix::process::ExitStatusExt, |
| 36 | process::{Command, Stdio}, |
| 37 | }; |
| 38 | let folder = tempfile::tempdir().unwrap(); |
| 39 | for panic in [false, true] { |
| 40 | let report = folder |
| 41 | .path() |
| 42 | .join(if panic { "panic.txt" } else { "native.txt" }); |
| 43 | let mut child = Command::new(std::env::current_exe().unwrap()); |
| 44 | child |
| 45 | .args(["--exact", "crash_child", "--nocapture"]) |
| 46 | .env("SNOWBOUND_TEST_CRASH", &report) |
| 47 | .stdout(Stdio::null()) |
| 48 | .stderr(Stdio::null()); |
| 49 | if panic { |
| 50 | child.env("SNOWBOUND_TEST_PANIC", "1"); |
| 51 | } |
| 52 | assert_eq!(child.status().unwrap().signal(), Some(libc::SIGABRT)); |
| 53 | let saved = std::fs::read_to_string(report).unwrap(); |
| 54 | assert!( |
| 55 | saved.starts_with("Snowbound test, native-test\nSystem: test system\n"), |
| 56 | "{saved}" |
| 57 | ); |
| 58 | if panic { |
| 59 | assert!( |
| 60 | saved.contains("Panic: Cannot read section <name>"), |
| 61 | "{saved}" |
| 62 | ); |
| 63 | assert!(!saved.contains("Native signal"), "{saved}"); |
| 64 | } else { |
| 65 | assert!(saved.contains("Native signal:"), "{saved}"); |
| 66 | assert!(!saved.contains("Fault address:"), "{saved}"); |
| 67 | } |
| 68 | } |
| 69 | } |