diff --git a/sentry-backtrace/src/parse.rs b/sentry-backtrace/src/parse.rs index 04d9bc55..03f3df89 100644 --- a/sentry-backtrace/src/parse.rs +++ b/sentry-backtrace/src/parse.rs @@ -45,7 +45,7 @@ pub fn parse_stacktrace(bt: &str) -> Option { let filename = abs_path.as_ref().map(|p| filename(p).to_string()); let real_symbol = captures["symbol"].to_string(); let symbol = strip_symbol(&real_symbol); - let function = demangle_symbol(symbol); + let function = demangle_symbol(&symbol); // Obtain the instruction address. A missing address usually indicates an inlined stack // frame, in which case the previous address needs to be used. diff --git a/sentry-backtrace/src/process.rs b/sentry-backtrace/src/process.rs index 1d2b5cc7..82334c9a 100644 --- a/sentry-backtrace/src/process.rs +++ b/sentry-backtrace/src/process.rs @@ -104,7 +104,7 @@ pub fn backtrace_to_stacktrace(bt: &Backtrace) -> Option { .name() .map_or(Cow::Borrowed(""), |n| Cow::Owned(n.to_string())); let symbol = strip_symbol(&real_symbol); - let function = demangle_symbol(symbol); + let function = demangle_symbol(&symbol); Frame { symbol: if symbol != function { Some(symbol.into()) diff --git a/sentry-backtrace/src/utils.rs b/sentry-backtrace/src/utils.rs index 47c48491..3822f652 100644 --- a/sentry-backtrace/src/utils.rs +++ b/sentry-backtrace/src/utils.rs @@ -1,3 +1,5 @@ +use std::borrow::Cow; + use once_cell::sync::Lazy; use regex::{Captures, Regex}; @@ -10,6 +12,15 @@ static HASH_FUNC_RE: Lazy = Lazy::new(|| { .unwrap() }); +static CRATE_HASH_RE: Lazy = Lazy::new(|| { + Regex::new( + r#"(?x) + \b(\[[a-f0-9]{16}\]) + "#, + ) + .unwrap() +}); + static CRATE_RE: Lazy = Lazy::new(|| { Regex::new( r#"(?x) @@ -17,7 +28,7 @@ static CRATE_RE: Lazy = Lazy::new(|| { (?:_?<)? # trait impl syntax (?:\w+\ as \ )? # anonymous implementor ([a-zA-Z0-9_]+?) # crate name - (?:\.\.|::) # crate delimiter (.. or ::) + (?:\.\.|::|\[) # crate delimiter (.. or :: or [) "#, ) .unwrap() @@ -47,11 +58,13 @@ pub fn filename(s: &str) -> &str { s.rsplit(&['/', '\\'][..]).next().unwrap() } -pub fn strip_symbol(s: &str) -> &str { - HASH_FUNC_RE +pub fn strip_symbol(s: &str) -> Cow { + let stripped_trailing_hash = HASH_FUNC_RE .captures(s) .map(|c| c.get(1).unwrap().as_str()) - .unwrap_or(s) + .unwrap_or(s); + + CRATE_HASH_RE.replace_all(stripped_trailing_hash, "") } pub fn demangle_symbol(s: &str) -> String { @@ -196,6 +209,23 @@ mod tests { ); } + #[test] + fn strip_crate_hash() { + assert_eq!( + &strip_symbol("std::panic::catch_unwind::hd044952603e5f56c"), + "std::panic::catch_unwind" + ); + assert_eq!( + &strip_symbol("std[550525b9dd91a68e]::rt::lang_start::<()>"), + "std::rt::lang_start::<()>" + ); + assert_eq!( + &strip_symbol(">::call_once"), + ">::call_once" + ); + assert_eq!(&strip_symbol(">, core[bb3d6b31f0e973c8]::cell::Cell)>>::with::<::with<::with_active::{closure#0}, ()>::{closure#0}, ()>::{closure#0}, ()>"), ">, core::cell::Cell)>>::with::<::with<::with_active::{closure#0}, ()>::{closure#0}, ()>::{closure#0}, ()>"); + } + #[test] fn test_parse_crate_name_none() { assert_eq!(parse_crate_name("main"), None); @@ -208,4 +238,16 @@ mod tests { Some("failure".into()) ); } + + #[test] + fn test_parse_crate_name_hash() { + assert_eq!( + parse_crate_name("backtrace[856cf81bbf211f65]::backtrace::libunwind::trace"), + Some("backtrace".into()) + ); + assert_eq!( + parse_crate_name("::new"), + Some("backtrace".into()) + ); + } }