diff options
| author | bors <bors@rust-lang.org> | 2019-09-11 14:46:08 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2019-09-11 14:46:08 +0000 |
| commit | fe6d05a8b32f5c66c427ca524dbcce5a7145f87e (patch) | |
| tree | 8c28b22f8fc089fa753c1359341bd67039d0f596 /src/libstd/sys_common | |
| parent | 74d5c70b174f06843049af2d764ff57ddc81c81c (diff) | |
| parent | 34662c69614028944668f96c91ef294e7da048f0 (diff) | |
| download | rust-fe6d05a8b32f5c66c427ca524dbcce5a7145f87e.tar.gz rust-fe6d05a8b32f5c66c427ca524dbcce5a7145f87e.zip | |
Auto merge of #64154 - alexcrichton:std-backtrace, r=sfackler
std: Add a `backtrace` module This commit adds a `backtrace` module to the standard library, as designed in [RFC 2504]. The `Backtrace` type is intentionally very conservative, effectively only allowing capturing it and printing it. Additionally this commit also adds a `backtrace` method to the `Error` trait which defaults to returning `None`, as specified in [RFC 2504]. More information about the design here can be found in [RFC 2504] and in the [tracking issue]. Implementation-wise this is all based on the `backtrace` crate and very closely mirrors the `backtrace::Backtrace` type on crates.io. Otherwise it's pretty standard in how it handles everything internally. [RFC 2504]: https://github.com/rust-lang/rfcs/blob/master/text/2504-fix-error.md [tracking issue]: https://github.com/rust-lang/rust/issues/53487 cc #53487
Diffstat (limited to 'src/libstd/sys_common')
| -rw-r--r-- | src/libstd/sys_common/backtrace.rs | 119 |
1 files changed, 65 insertions, 54 deletions
diff --git a/src/libstd/sys_common/backtrace.rs b/src/libstd/sys_common/backtrace.rs index 43550ab04ca..1a78abf5086 100644 --- a/src/libstd/sys_common/backtrace.rs +++ b/src/libstd/sys_common/backtrace.rs @@ -4,8 +4,9 @@ use crate::env; use crate::fmt; use crate::io; +use crate::borrow::Cow; use crate::io::prelude::*; -use crate::path::{self, Path}; +use crate::path::{self, Path, PathBuf}; use crate::sync::atomic::{self, Ordering}; use crate::sys::mutex::Mutex; @@ -14,10 +15,26 @@ use backtrace::{BacktraceFmt, BytesOrWideString, PrintFmt}; /// Max number of frames to print. const MAX_NB_FRAMES: usize = 100; -/// Prints the current backtrace. -pub fn print(w: &mut dyn Write, format: PrintFmt) -> io::Result<()> { +pub fn lock() -> impl Drop { + struct Guard; static LOCK: Mutex = Mutex::new(); + impl Drop for Guard { + fn drop(&mut self) { + unsafe { + LOCK.unlock(); + } + } + } + + unsafe { + LOCK.lock(); + return Guard; + } +} + +/// Prints the current backtrace. +pub fn print(w: &mut dyn Write, format: PrintFmt) -> io::Result<()> { // There are issues currently linking libbacktrace into tests, and in // general during libstd's own unit tests we're not testing this path. In // test mode immediately return here to optimize away any references to the @@ -29,71 +46,67 @@ pub fn print(w: &mut dyn Write, format: PrintFmt) -> io::Result<()> { // Use a lock to prevent mixed output in multithreading context. // Some platforms also requires it, like `SymFromAddr` on Windows. unsafe { - LOCK.lock(); - let res = _print(w, format); - LOCK.unlock(); - res + let _lock = lock(); + _print(w, format) } } -fn _print(w: &mut dyn Write, format: PrintFmt) -> io::Result<()> { +unsafe fn _print(w: &mut dyn Write, format: PrintFmt) -> io::Result<()> { struct DisplayBacktrace { format: PrintFmt, } impl fmt::Display for DisplayBacktrace { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - _print_fmt(fmt, self.format) + unsafe { + _print_fmt(fmt, self.format) + } } } write!(w, "{}", DisplayBacktrace { format }) } -fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::Result { +unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::Result { + let cwd = env::current_dir().ok(); let mut print_path = move |fmt: &mut fmt::Formatter<'_>, bows: BytesOrWideString<'_>| { - output_filename(fmt, bows, print_fmt) + output_filename(fmt, bows, print_fmt, cwd.as_ref()) }; let mut bt_fmt = BacktraceFmt::new(fmt, print_fmt, &mut print_path); bt_fmt.add_context()?; - let mut skipped = false; - unsafe { - let mut idx = 0; - let mut res = Ok(()); - backtrace::trace_unsynchronized(|frame| { - if print_fmt == PrintFmt::Short && idx > MAX_NB_FRAMES { - skipped = true; - return false; - } + let mut idx = 0; + let mut res = Ok(()); + backtrace::trace_unsynchronized(|frame| { + if print_fmt == PrintFmt::Short && idx > MAX_NB_FRAMES { + return false; + } - let mut hit = false; - let mut stop = false; - backtrace::resolve_frame_unsynchronized(frame, |symbol| { - hit = true; - if print_fmt == PrintFmt::Short { - if let Some(sym) = symbol.name().and_then(|s| s.as_str()) { - if sym.contains("__rust_begin_short_backtrace") { - skipped = true; - stop = true; - return; - } + let mut hit = false; + let mut stop = false; + backtrace::resolve_frame_unsynchronized(frame, |symbol| { + hit = true; + if print_fmt == PrintFmt::Short { + if let Some(sym) = symbol.name().and_then(|s| s.as_str()) { + if sym.contains("__rust_begin_short_backtrace") { + stop = true; + return; } } - - res = bt_fmt.frame().symbol(frame, symbol); - }); - if stop { - return false; - } - if !hit { - res = bt_fmt.frame().print_raw(frame.ip(), None, None, None); } - idx += 1; - res.is_ok() + res = bt_fmt.frame().symbol(frame, symbol); }); - res?; - } + if stop { + return false; + } + if !hit { + res = bt_fmt.frame().print_raw(frame.ip(), None, None, None); + } + + idx += 1; + res.is_ok() + }); + res?; bt_fmt.finish()?; - if skipped { + if print_fmt == PrintFmt::Short { writeln!( fmt, "note: Some details are omitted, \ @@ -153,36 +166,34 @@ pub fn log_enabled() -> Option<PrintFmt> { /// Prints the filename of the backtrace frame. /// /// See also `output`. -fn output_filename( +pub fn output_filename( fmt: &mut fmt::Formatter<'_>, bows: BytesOrWideString<'_>, print_fmt: PrintFmt, + cwd: Option<&PathBuf>, ) -> fmt::Result { - #[cfg(windows)] - let path_buf; - let file = match bows { + let file: Cow<'_, Path> = match bows { #[cfg(unix)] BytesOrWideString::Bytes(bytes) => { use crate::os::unix::prelude::*; - Path::new(crate::ffi::OsStr::from_bytes(bytes)) + Path::new(crate::ffi::OsStr::from_bytes(bytes)).into() } #[cfg(not(unix))] BytesOrWideString::Bytes(bytes) => { - Path::new(crate::str::from_utf8(bytes).unwrap_or("<unknown>")) + Path::new(crate::str::from_utf8(bytes).unwrap_or("<unknown>")).into() } #[cfg(windows)] BytesOrWideString::Wide(wide) => { use crate::os::windows::prelude::*; - path_buf = crate::ffi::OsString::from_wide(wide); - Path::new(&path_buf) + Cow::Owned(crate::ffi::OsString::from_wide(wide).into()) } #[cfg(not(windows))] BytesOrWideString::Wide(_wide) => { - Path::new("<unknown>") + Path::new("<unknown>").into() } }; if print_fmt == PrintFmt::Short && file.is_absolute() { - if let Ok(cwd) = env::current_dir() { + if let Some(cwd) = cwd { if let Ok(stripped) = file.strip_prefix(&cwd) { if let Some(s) = stripped.to_str() { return write!(fmt, ".{}{}", path::MAIN_SEPARATOR, s); |
