summaryrefslogtreecommitdiffstats
path: root/third_party/rust/failure/src/backtrace
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/failure/src/backtrace
parentInitial commit. (diff)
downloadfirefox-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.rs132
-rw-r--r--third_party/rust/failure/src/backtrace/mod.rs159
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(()) }
+ }
+ }
+}