feat: Attempt to dump a stacktrace to stderr prior to process abort on SIGSEGV/SIGILL/SIGBUS (#2155)
* feat: Attempt to dump a stacktrace to stdout prior to process abort * refactor: rewrite signal handling in terms of libc, remove sig dep * refactor: print to stderr * fix: Update src/main.rs * docs: note provenancepull/24376/head
parent
21270b7072
commit
7ca31703a4
|
@ -1619,6 +1619,7 @@ dependencies = [
|
||||||
"arrow-flight",
|
"arrow-flight",
|
||||||
"arrow_util",
|
"arrow_util",
|
||||||
"assert_cmd",
|
"assert_cmd",
|
||||||
|
"backtrace",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"bytes",
|
"bytes",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
@ -1640,6 +1641,7 @@ dependencies = [
|
||||||
"influxdb_line_protocol",
|
"influxdb_line_protocol",
|
||||||
"internal_types",
|
"internal_types",
|
||||||
"itertools 0.10.1",
|
"itertools 0.10.1",
|
||||||
|
"libc",
|
||||||
"logfmt",
|
"logfmt",
|
||||||
"metrics",
|
"metrics",
|
||||||
"mutable_buffer",
|
"mutable_buffer",
|
||||||
|
|
|
@ -77,6 +77,7 @@ trogging = { path = "trogging", features = ["structopt"] }
|
||||||
# Crates.io dependencies, in alphabetical order
|
# Crates.io dependencies, in alphabetical order
|
||||||
arrow = { version = "5.0", features = ["prettyprint"] }
|
arrow = { version = "5.0", features = ["prettyprint"] }
|
||||||
arrow-flight = "5.0"
|
arrow-flight = "5.0"
|
||||||
|
backtrace = "0.3"
|
||||||
byteorder = "1.3.4"
|
byteorder = "1.3.4"
|
||||||
bytes = "1.0"
|
bytes = "1.0"
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
|
@ -88,6 +89,7 @@ flate2 = "1.0"
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
http = "0.2.0"
|
http = "0.2.0"
|
||||||
hyper = "0.14"
|
hyper = "0.14"
|
||||||
|
libc = { version = "0.2" }
|
||||||
once_cell = { version = "1.4.0", features = ["parking_lot"] }
|
once_cell = { version = "1.4.0", features = ["parking_lot"] }
|
||||||
opentelemetry-jaeger = { version = "0.12", features = ["tokio"] }
|
opentelemetry-jaeger = { version = "0.12", features = ["tokio"] }
|
||||||
opentelemetry-otlp = "0.6"
|
opentelemetry-otlp = "0.6"
|
||||||
|
|
49
src/main.rs
49
src/main.rs
|
@ -137,6 +137,8 @@ enum Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<(), std::io::Error> {
|
fn main() -> Result<(), std::io::Error> {
|
||||||
|
install_crash_handler(); // attempt to render a useful stacktrace to stderr
|
||||||
|
|
||||||
// load all environment variables from .env before doing anything
|
// load all environment variables from .env before doing anything
|
||||||
load_dotenv();
|
load_dotenv();
|
||||||
|
|
||||||
|
@ -256,3 +258,50 @@ fn load_dotenv() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Based on ideas from
|
||||||
|
// https://github.com/servo/servo/blob/f03ddf6c6c6e94e799ab2a3a89660aea4a01da6f/ports/servo/main.rs#L58-L79
|
||||||
|
fn install_crash_handler() {
|
||||||
|
unsafe {
|
||||||
|
set_signal_handler(libc::SIGSEGV, signal_handler); // handle segfaults
|
||||||
|
set_signal_handler(libc::SIGILL, signal_handler); // handle stack overflow and unsupported CPUs
|
||||||
|
set_signal_handler(libc::SIGBUS, signal_handler); // handle invalid memory access
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn signal_handler(sig: i32) {
|
||||||
|
use backtrace::Backtrace;
|
||||||
|
use std::process::abort;
|
||||||
|
let name = std::thread::current()
|
||||||
|
.name()
|
||||||
|
.map(|n| format!(" for thread \"{}\"", n))
|
||||||
|
.unwrap_or_else(|| "".to_owned());
|
||||||
|
eprintln!(
|
||||||
|
"Signal {}, Stack trace{}\n{:?}",
|
||||||
|
sig,
|
||||||
|
name,
|
||||||
|
Backtrace::new()
|
||||||
|
);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
// based on https://github.com/adjivas/sig/blob/master/src/lib.rs#L34-L52
|
||||||
|
unsafe fn set_signal_handler(signal: libc::c_int, handler: unsafe extern "C" fn(libc::c_int)) {
|
||||||
|
use libc::{sigaction, sigfillset, sighandler_t};
|
||||||
|
let mut sigset = std::mem::zeroed();
|
||||||
|
|
||||||
|
// Block all signals during the handler. This is the expected behavior, but
|
||||||
|
// it's not guaranteed by `signal()`.
|
||||||
|
if sigfillset(&mut sigset) != -1 {
|
||||||
|
// Done because sigaction has private members.
|
||||||
|
// This is safe because sa_restorer and sa_handlers are pointers that
|
||||||
|
// might be null (that is, zero).
|
||||||
|
let mut action: sigaction = std::mem::zeroed();
|
||||||
|
|
||||||
|
// action.sa_flags = 0;
|
||||||
|
action.sa_mask = sigset;
|
||||||
|
action.sa_sigaction = handler as sighandler_t;
|
||||||
|
|
||||||
|
sigaction(signal, &action, std::ptr::null_mut());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue