diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/failure/src/backtrace | |
parent | Initial commit. (diff) | |
download | firefox-upstream.tar.xz firefox-upstream.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/failure/src/backtrace')
-rw-r--r-- | third_party/rust/failure/src/backtrace/internal.rs | 132 | ||||
-rw-r--r-- | third_party/rust/failure/src/backtrace/mod.rs | 159 |
2 files changed, 291 insertions, 0 deletions
diff --git a/third_party/rust/failure/src/backtrace/internal.rs b/third_party/rust/failure/src/backtrace/internal.rs new file mode 100644 index 0000000000..5e421201fa --- /dev/null +++ b/third_party/rust/failure/src/backtrace/internal.rs @@ -0,0 +1,132 @@ +use std::cell::UnsafeCell; +use std::env; +use std::ffi::OsString; +use std::fmt; +#[allow(deprecated)] // to allow for older Rust versions (<1.24) +use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; +use std::sync::Mutex; + +pub use super::backtrace::Backtrace; + +const GENERAL_BACKTRACE: &str = "RUST_BACKTRACE"; +const FAILURE_BACKTRACE: &str = "RUST_FAILURE_BACKTRACE"; + +pub(super) struct InternalBacktrace { + backtrace: Option<MaybeResolved>, +} + +struct MaybeResolved { + resolved: Mutex<bool>, + backtrace: UnsafeCell<Backtrace>, +} + +unsafe impl Send for MaybeResolved {} +unsafe impl Sync for MaybeResolved {} + +impl InternalBacktrace { + pub(super) fn new() -> InternalBacktrace { + #[allow(deprecated)] // to allow for older Rust versions (<1.24) + static ENABLED: AtomicUsize = ATOMIC_USIZE_INIT; + + match ENABLED.load(Ordering::SeqCst) { + 0 => { + let enabled = is_backtrace_enabled(|var| env::var_os(var)); + ENABLED.store(enabled as usize + 1, Ordering::SeqCst); + if !enabled { + return InternalBacktrace { backtrace: None } + } + } + 1 => return InternalBacktrace { backtrace: None }, + _ => {} + } + + InternalBacktrace { + backtrace: Some(MaybeResolved { + resolved: Mutex::new(false), + backtrace: UnsafeCell::new(Backtrace::new_unresolved()), + }), + } + } + + pub(super) fn none() -> InternalBacktrace { + InternalBacktrace { backtrace: None } + } + + pub(super) fn as_backtrace(&self) -> Option<&Backtrace> { + let bt = match self.backtrace { + Some(ref bt) => bt, + None => return None, + }; + let mut resolved = bt.resolved.lock().unwrap(); + unsafe { + if !*resolved { + (*bt.backtrace.get()).resolve(); + *resolved = true; + } + Some(&*bt.backtrace.get()) + } + } + + pub(super) fn is_none(&self) -> bool { + self.backtrace.is_none() + } +} + +impl fmt::Debug for InternalBacktrace { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("InternalBacktrace") + .field("backtrace", &self.as_backtrace()) + .finish() + } +} + +fn is_backtrace_enabled<F: Fn(&str) -> Option<OsString>>(get_var: F) -> bool { + match get_var(FAILURE_BACKTRACE) { + Some(ref val) if val != "0" => true, + Some(ref val) if val == "0" => false, + _ => match get_var(GENERAL_BACKTRACE) { + Some(ref val) if val != "0" => true, + _ => false, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + const YEA: Option<&str> = Some("1"); + const NAY: Option<&str> = Some("0"); + const NOT_SET: Option<&str> = None; + + macro_rules! test_enabled { + (failure: $failure:ident, general: $general:ident => $result:expr) => {{ + assert_eq!(is_backtrace_enabled(|var| match var { + FAILURE_BACKTRACE => $failure.map(OsString::from), + GENERAL_BACKTRACE => $general.map(OsString::from), + _ => panic!() + }), $result); + }} + } + + #[test] + fn always_enabled_if_failure_is_set_to_yes() { + test_enabled!(failure: YEA, general: YEA => true); + test_enabled!(failure: YEA, general: NOT_SET => true); + test_enabled!(failure: YEA, general: NAY => true); + } + + #[test] + fn never_enabled_if_failure_is_set_to_no() { + test_enabled!(failure: NAY, general: YEA => false); + test_enabled!(failure: NAY, general: NOT_SET => false); + test_enabled!(failure: NAY, general: NAY => false); + } + + #[test] + fn follows_general_if_failure_is_not_set() { + test_enabled!(failure: NOT_SET, general: YEA => true); + test_enabled!(failure: NOT_SET, general: NOT_SET => false); + test_enabled!(failure: NOT_SET, general: NAY => false); + } +} diff --git a/third_party/rust/failure/src/backtrace/mod.rs b/third_party/rust/failure/src/backtrace/mod.rs new file mode 100644 index 0000000000..9eba16d9cb --- /dev/null +++ b/third_party/rust/failure/src/backtrace/mod.rs @@ -0,0 +1,159 @@ +use core::fmt::{self, Debug, Display}; + +macro_rules! with_backtrace { ($($i:item)*) => ($(#[cfg(all(feature = "backtrace", feature = "std"))]$i)*) } +macro_rules! without_backtrace { ($($i:item)*) => ($(#[cfg(not(all(feature = "backtrace", feature = "std")))]$i)*) } + +without_backtrace! { + /// A `Backtrace`. + /// + /// This is an opaque wrapper around the backtrace provided by + /// libbacktrace. A variety of optimizations have been performed to avoid + /// unnecessary or ill-advised work: + /// + /// - If this crate is compiled in `no_std` compatible mode, `Backtrace` + /// is an empty struct, and will be completely compiled away. + /// - If this crate is run without the `RUST_BACKTRACE` environmental + /// variable enabled, the backtrace will not be generated at runtime. + /// - Even if a backtrace is generated, the most expensive part of + /// generating a backtrace is symbol resolution. This backtrace does not + /// perform symbol resolution until it is actually read (e.g. by + /// printing it). If the Backtrace is never used for anything, symbols + /// never get resolved. + /// + /// Even with these optimizations, including a backtrace in your failure + /// may not be appropriate to your use case. You are not required to put a + /// backtrace in a custom `Fail` type. + /// + /// > (We have detected that this crate was documented with no_std + /// > compatibility turned on. The version of this crate that has been + /// > documented here will never generate a backtrace.) + pub struct Backtrace { + _secret: (), + } + + impl Backtrace { + /// Constructs a new backtrace. This will only create a real backtrace + /// if the crate is compiled in std mode and the `RUST_BACKTRACE` + /// environmental variable is activated. + /// + /// > (We have detected that this crate was documented with no_std + /// > compatibility turned on. The version of this crate that has been + /// > documented here will never generate a backtrace.) + pub fn new() -> Backtrace { + Backtrace { _secret: () } + } + + #[cfg(feature = "std")] + pub(crate) fn none() -> Backtrace { + Backtrace { _secret: () } + } + + #[cfg(feature = "std")] + pub(crate) fn is_none(&self) -> bool { + true + } + + /// Returns true if displaying this backtrace would be an empty string. + /// + /// > (We have detected that this crate was documented with no_std + /// > compatibility turned on. The version of this crate that has been + /// > documented here will never generate a backtrace and this method + /// > will always return true.) + pub fn is_empty(&self) -> bool { + true + } + } + + impl Default for Backtrace { + fn default() -> Backtrace { + Backtrace::new() + } + } + + impl Debug for Backtrace { + fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { + Ok(()) + } + } + + impl Display for Backtrace { + fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { + Ok(()) + } + } +} + +with_backtrace! { + extern crate backtrace; + + mod internal; + + use self::internal::InternalBacktrace; + + /// A `Backtrace`. + /// + /// This is an opaque wrapper around the backtrace provided by + /// libbacktrace. A variety of optimizations have been performed to avoid + /// unnecessary or ill-advised work: + /// + /// - If this crate is compiled in `no_std` compatible mode, `Backtrace` + /// is an empty struct, and will be completely compiled away. + /// - If this crate is run without the `RUST_BACKTRACE` environmental + /// variable enabled, the backtrace will not be generated at runtime. + /// - Even if a backtrace is generated, the most expensive part of + /// generating a backtrace is symbol resolution. This backtrace does not + /// perform symbol resolution until it is actually read (e.g. by + /// printing it). If the Backtrace is never used for anything, symbols + /// never get resolved. + /// + /// Even with these optimizations, including a backtrace in your failure + /// may not be appropriate to your use case. You are not required to put a + /// backtrace in a custom `Fail` type. + pub struct Backtrace { + internal: InternalBacktrace + } + + impl Backtrace { + /// Constructs a new backtrace. This will only create a real backtrace + /// if the crate is compiled in std mode and the `RUST_BACKTRACE` + /// environmental variable is activated. + pub fn new() -> Backtrace { + Backtrace { internal: InternalBacktrace::new() } + } + + pub(crate) fn none() -> Backtrace { + Backtrace { internal: InternalBacktrace::none() } + } + + pub(crate) fn is_none(&self) -> bool { + self.internal.is_none() + } + + /// Returns true if displaying this backtrace would be an empty string. + pub fn is_empty(&self) -> bool { + self.internal.is_none() + } + } + + impl Default for Backtrace { + fn default() -> Backtrace { + Backtrace::new() + } + } + + impl Debug for Backtrace { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Some(bt) = self.internal.as_backtrace() { + Debug::fmt(bt, f) + } else { Ok(()) } + } + } + + impl Display for Backtrace { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Some(bt) = self.internal.as_backtrace() { + Debug::fmt(bt, f) + } else { Ok(()) } + } + } +} |