Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  backtrace.rs   Sprache: unbekannt

 
#[cfg(backtrace)]
pub(crate) use std::backtrace::{Backtrace, BacktraceStatus};

#[cfg(all(not(backtrace), feature = "backtrace"))]
pub(crate) use self::capture::{Backtrace, BacktraceStatus};

#[cfg(not(any(backtrace, feature = "backtrace")))]
pub(crate) enum Backtrace {}

#[cfg(backtrace)]
macro_rules! impl_backtrace {
    () => {
        std::backtrace::Backtrace
    };
}

#[cfg(all(not(backtrace), feature = "backtrace"))]
macro_rules! impl_backtrace {
    () => {
        impl core::fmt::Debug + core::fmt::Display
    };
}

#[cfg(any(backtrace, feature = "backtrace"))]
macro_rules! backtrace {
    () => {
        Some(crate::backtrace::Backtrace::capture())
    };
}

#[cfg(not(any(backtrace, feature = "backtrace")))]
macro_rules! backtrace {
    () => {
        None
    };
}

#[cfg(backtrace)]
macro_rules! backtrace_if_absent {
    ($err:expr) => {
        match ($err as &dyn std::error::Error).request_ref::<std::backtrace::Backtrace>() {
            Some(_) => None,
            None => backtrace!(),
        }
    };
}

#[cfg(all(feature = "std", not(backtrace), feature = "backtrace"))]
macro_rules! backtrace_if_absent {
    ($err:expr) => {
        backtrace!()
    };
}

#[cfg(all(feature = "std", not(backtrace), not(feature = "backtrace")))]
macro_rules! backtrace_if_absent {
    ($err:expr) => {
        None
    };
}

#[cfg(all(not(backtrace), feature = "backtrace"))]
mod capture {
    use backtrace::{BacktraceFmt, BytesOrWideString, Frame, PrintFmt, SymbolName};
    use core::cell::UnsafeCell;
    use core::fmt::{self, Debug, Display};
    use core::sync::atomic::{AtomicUsize, Ordering};
    use std::borrow::Cow;
    use std::env;
    use std::path::{self, Path, PathBuf};
    use std::sync::Once;

    pub(crate) struct Backtrace {
        inner: Inner,
    }

    pub(crate) enum BacktraceStatus {
        Unsupported,
        Disabled,
        Captured,
    }

    enum Inner {
        Unsupported,
        Disabled,
        Captured(LazilyResolvedCapture),
    }

    struct Capture {
        actual_start: usize,
        resolved: bool,
        frames: Vec<BacktraceFrame>,
    }

    struct BacktraceFrame {
        frame: Frame,
        symbols: Vec<BacktraceSymbol>,
    }

    struct BacktraceSymbol {
        name: Option<Vec<u8>>,
        filename: Option<BytesOrWide>,
        lineno: Option<u32>,
        colno: Option<u32>,
    }

    enum BytesOrWide {
        Bytes(Vec<u8>),
        Wide(Vec<u16>),
    }

    impl Debug for Backtrace {
        fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
            let capture = match &self.inner {
                Inner::Unsupported => return fmt.write_str("<unsupported>"),
                Inner::Disabled => return fmt.write_str("<disabled>"),
                Inner::Captured(c) => c.force(),
            };

            let frames = &capture.frames[capture.actual_start..];

            write!(fmt, "Backtrace ")?;

            let mut dbg = fmt.debug_list();

            for frame in frames {
                if frame.frame.ip().is_null() {
                    continue;
                }

                dbg.entries(&frame.symbols);
            }

            dbg.finish()
        }
    }

    impl Debug for BacktraceFrame {
        fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
            let mut dbg = fmt.debug_list();
            dbg.entries(&self.symbols);
            dbg.finish()
        }
    }

    impl Debug for BacktraceSymbol {
        fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
            write!(fmt, "{{ ")?;

            if let Some(fn_name) = self.name.as_ref().map(|b| SymbolName::new(b)) {
                write!(fmt, "fn: \"{:#}\"", fn_name)?;
            } else {
                write!(fmt, "fn: <unknown>")?;
            }

            if let Some(fname) = self.filename.as_ref() {
                write!(fmt, ", file: \"{:?}\"", fname)?;
            }

            if let Some(line) = self.lineno {
                write!(fmt, ", line: {:?}", line)?;
            }

            write!(fmt, " }}")
        }
    }

    impl Debug for BytesOrWide {
        fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
            output_filename(
                fmt,
                match self {
                    BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w),
                    BytesOrWide::Wide(w) => BytesOrWideString::Wide(w),
                },
                PrintFmt::Short,
                env::current_dir().as_ref().ok(),
            )
        }
    }

    impl Backtrace {
        fn enabled() -> bool {
            static ENABLED: AtomicUsize = AtomicUsize::new(0);
            match ENABLED.load(Ordering::Relaxed) {
                0 => {}
                1 => return false,
                _ => return true,
            }
            let enabled = match env::var_os("RUST_LIB_BACKTRACE") {
                Some(s) => s != "0",
                None => match env::var_os("RUST_BACKTRACE") {
                    Some(s) => s != "0",
                    None => false,
                },
            };
            ENABLED.store(enabled as usize + 1, Ordering::Relaxed);
            enabled
        }

        #[inline(never)] // want to make sure there's a frame here to remove
        pub(crate) fn capture() -> Backtrace {
            if Backtrace::enabled() {
                Backtrace::create(Backtrace::capture as usize)
            } else {
                let inner = Inner::Disabled;
                Backtrace { inner }
            }
        }

        // Capture a backtrace which starts just before the function addressed
        // by `ip`
        fn create(ip: usize) -> Backtrace {
            let mut frames = Vec::new();
            let mut actual_start = None;
            backtrace::trace(|frame| {
                frames.push(BacktraceFrame {
                    frame: frame.clone(),
                    symbols: Vec::new(),
                });
                if frame.symbol_address() as usize == ip && actual_start.is_none() {
                    actual_start = Some(frames.len() + 1);
                }
                true
            });

            // If no frames came out assume that this is an unsupported platform
            // since `backtrace` doesn't provide a way of learning this right
            // now, and this should be a good enough approximation.
            let inner = if frames.is_empty() {
                Inner::Unsupported
            } else {
                Inner::Captured(LazilyResolvedCapture::new(Capture {
                    actual_start: actual_start.unwrap_or(0),
                    frames,
                    resolved: false,
                }))
            };

            Backtrace { inner }
        }

        pub(crate) fn status(&self) -> BacktraceStatus {
            match self.inner {
                Inner::Unsupported => BacktraceStatus::Unsupported,
                Inner::Disabled => BacktraceStatus::Disabled,
                Inner::Captured(_) => BacktraceStatus::Captured,
            }
        }
    }

    impl Display for Backtrace {
        fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
            let capture = match &self.inner {
                Inner::Unsupported => return fmt.write_str("unsupported backtrace"),
                Inner::Disabled => return fmt.write_str("disabled backtrace"),
                Inner::Captured(c) => c.force(),
            };

            let full = fmt.alternate();
            let (frames, style) = if full {
                (&capture.frames[..], PrintFmt::Full)
            } else {
                (&capture.frames[capture.actual_start..], PrintFmt::Short)
            };

            // When printing paths we try to strip the cwd if it exists,
            // otherwise we just print the path as-is. Note that we also only do
            // this for the short format, because if it's full we presumably
            // want to print everything.
            let cwd = env::current_dir();
            let mut print_path = move |fmt: &mut fmt::Formatter, path: BytesOrWideString| {
                output_filename(fmt, path, style, cwd.as_ref().ok())
            };

            let mut f = BacktraceFmt::new(fmt, style, &mut print_path);
            f.add_context()?;
            for frame in frames {
                let mut f = f.frame();
                if frame.symbols.is_empty() {
                    f.print_raw(frame.frame.ip(), None, None, None)?;
                } else {
                    for symbol in frame.symbols.iter() {
                        f.print_raw_with_column(
                            frame.frame.ip(),
                            symbol.name.as_ref().map(|b| SymbolName::new(b)),
                            symbol.filename.as_ref().map(|b| match b {
                                BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w),
                                BytesOrWide::Wide(w) => BytesOrWideString::Wide(w),
                            }),
                            symbol.lineno,
                            symbol.colno,
                        )?;
                    }
                }
            }
            f.finish()?;
            Ok(())
        }
    }

    struct LazilyResolvedCapture {
        sync: Once,
        capture: UnsafeCell<Capture>,
    }

    impl LazilyResolvedCapture {
        fn new(capture: Capture) -> Self {
            LazilyResolvedCapture {
                sync: Once::new(),
                capture: UnsafeCell::new(capture),
            }
        }

        fn force(&self) -> &Capture {
            self.sync.call_once(|| {
                // Safety: This exclusive reference can't overlap with any
                // others. `Once` guarantees callers will block until this
                // closure returns. `Once` also guarantees only a single caller
                // will enter this closure.
                unsafe { &mut *self.capture.get() }.resolve();
            });

            // Safety: This shared reference can't overlap with the exclusive
            // reference above.
            unsafe { &*self.capture.get() }
        }
    }

    // Safety: Access to the inner value is synchronized using a thread-safe
    // `Once`. So long as `Capture` is `Sync`, `LazilyResolvedCapture` is too
    unsafe impl Sync for LazilyResolvedCapture where Capture: Sync {}

    impl Capture {
        fn resolve(&mut self) {
            // If we're already resolved, nothing to do!
            if self.resolved {
                return;
            }
            self.resolved = true;

            for frame in self.frames.iter_mut() {
                let symbols = &mut frame.symbols;
                let frame = &frame.frame;
                backtrace::resolve_frame(frame, |symbol| {
                    symbols.push(BacktraceSymbol {
                        name: symbol.name().map(|m| m.as_bytes().to_vec()),
                        filename: symbol.filename_raw().map(|b| match b {
                            BytesOrWideString::Bytes(b) => BytesOrWide::Bytes(b.to_owned()),
                            BytesOrWideString::Wide(b) => BytesOrWide::Wide(b.to_owned()),
                        }),
                        lineno: symbol.lineno(),
                        colno: symbol.colno(),
                    });
                });
            }
        }
    }

    // Prints the filename of the backtrace frame.
    fn output_filename(
        fmt: &mut fmt::Formatter,
        bows: BytesOrWideString,
        print_fmt: PrintFmt,
        cwd: Option<&PathBuf>,
    ) -> fmt::Result {
        let file: Cow<Path> = match bows {
            #[cfg(unix)]
            BytesOrWideString::Bytes(bytes) => {
                use std::os::unix::ffi::OsStrExt;
                Path::new(std::ffi::OsStr::from_bytes(bytes)).into()
            }
            #[cfg(not(unix))]
            BytesOrWideString::Bytes(bytes) => {
                Path::new(std::str::from_utf8(bytes).unwrap_or("<unknown>")).into()
            }
            #[cfg(windows)]
            BytesOrWideString::Wide(wide) => {
                use std::os::windows::ffi::OsStringExt;
                Cow::Owned(std::ffi::OsString::from_wide(wide).into())
            }
            #[cfg(not(windows))]
            BytesOrWideString::Wide(_wide) => Path::new("<unknown>").into(),
        };
        if print_fmt == PrintFmt::Short && file.is_absolute() {
            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);
                    }
                }
            }
        }
        Display::fmt(&file.display(), fmt)
    }
}

fn _assert_send_sync() {
    fn _assert<T: Send + Sync>() {}
    _assert::<Backtrace>();
}

[ Dauer der Verarbeitung: 0.24 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge