Coverage Report

Created: 2025-12-28 06:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/anyhow-1.0.75/src/backtrace.rs
Line
Count
Source
1
#[cfg(backtrace)]
2
pub(crate) use std::backtrace::{Backtrace, BacktraceStatus};
3
4
#[cfg(all(not(backtrace), feature = "backtrace"))]
5
pub(crate) use self::capture::{Backtrace, BacktraceStatus};
6
7
#[cfg(not(any(backtrace, feature = "backtrace")))]
8
pub(crate) enum Backtrace {}
9
10
#[cfg(backtrace)]
11
macro_rules! impl_backtrace {
12
    () => {
13
        std::backtrace::Backtrace
14
    };
15
}
16
17
#[cfg(all(not(backtrace), feature = "backtrace"))]
18
macro_rules! impl_backtrace {
19
    () => {
20
        impl core::fmt::Debug + core::fmt::Display
21
    };
22
}
23
24
#[cfg(any(backtrace, feature = "backtrace"))]
25
macro_rules! backtrace {
26
    () => {
27
        Some(crate::backtrace::Backtrace::capture())
28
    };
29
}
30
31
#[cfg(not(any(backtrace, feature = "backtrace")))]
32
macro_rules! backtrace {
33
    () => {
34
        None
35
    };
36
}
37
38
#[cfg(backtrace)]
39
macro_rules! backtrace_if_absent {
40
    ($err:expr) => {
41
        match std::error::request_ref::<std::backtrace::Backtrace>($err as &dyn std::error::Error) {
42
            Some(_) => None,
43
            None => backtrace!(),
44
        }
45
    };
46
}
47
48
#[cfg(all(feature = "std", not(backtrace), feature = "backtrace"))]
49
macro_rules! backtrace_if_absent {
50
    ($err:expr) => {
51
        backtrace!()
52
    };
53
}
54
55
#[cfg(all(feature = "std", not(backtrace), not(feature = "backtrace")))]
56
macro_rules! backtrace_if_absent {
57
    ($err:expr) => {
58
        None
59
    };
60
}
61
62
#[cfg(all(not(backtrace), feature = "backtrace"))]
63
mod capture {
64
    use backtrace::{BacktraceFmt, BytesOrWideString, Frame, PrintFmt, SymbolName};
65
    use core::cell::UnsafeCell;
66
    use core::fmt::{self, Debug, Display};
67
    use core::sync::atomic::{AtomicUsize, Ordering};
68
    use std::borrow::Cow;
69
    use std::env;
70
    use std::path::{self, Path, PathBuf};
71
    use std::sync::Once;
72
73
    pub(crate) struct Backtrace {
74
        inner: Inner,
75
    }
76
77
    pub(crate) enum BacktraceStatus {
78
        Unsupported,
79
        Disabled,
80
        Captured,
81
    }
82
83
    enum Inner {
84
        Unsupported,
85
        Disabled,
86
        Captured(LazilyResolvedCapture),
87
    }
88
89
    struct Capture {
90
        actual_start: usize,
91
        resolved: bool,
92
        frames: Vec<BacktraceFrame>,
93
    }
94
95
    struct BacktraceFrame {
96
        frame: Frame,
97
        symbols: Vec<BacktraceSymbol>,
98
    }
99
100
    struct BacktraceSymbol {
101
        name: Option<Vec<u8>>,
102
        filename: Option<BytesOrWide>,
103
        lineno: Option<u32>,
104
        colno: Option<u32>,
105
    }
106
107
    enum BytesOrWide {
108
        Bytes(Vec<u8>),
109
        Wide(Vec<u16>),
110
    }
111
112
    impl Debug for Backtrace {
113
        fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
114
            let capture = match &self.inner {
115
                Inner::Unsupported => return fmt.write_str("<unsupported>"),
116
                Inner::Disabled => return fmt.write_str("<disabled>"),
117
                Inner::Captured(c) => c.force(),
118
            };
119
120
            let frames = &capture.frames[capture.actual_start..];
121
122
            write!(fmt, "Backtrace ")?;
123
124
            let mut dbg = fmt.debug_list();
125
126
            for frame in frames {
127
                if frame.frame.ip().is_null() {
128
                    continue;
129
                }
130
131
                dbg.entries(&frame.symbols);
132
            }
133
134
            dbg.finish()
135
        }
136
    }
137
138
    impl Debug for BacktraceFrame {
139
        fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
140
            let mut dbg = fmt.debug_list();
141
            dbg.entries(&self.symbols);
142
            dbg.finish()
143
        }
144
    }
145
146
    impl Debug for BacktraceSymbol {
147
        fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
148
            write!(fmt, "{{ ")?;
149
150
            if let Some(fn_name) = self.name.as_ref().map(|b| SymbolName::new(b)) {
151
                write!(fmt, "fn: \"{:#}\"", fn_name)?;
152
            } else {
153
                write!(fmt, "fn: <unknown>")?;
154
            }
155
156
            if let Some(fname) = self.filename.as_ref() {
157
                write!(fmt, ", file: \"{:?}\"", fname)?;
158
            }
159
160
            if let Some(line) = self.lineno {
161
                write!(fmt, ", line: {:?}", line)?;
162
            }
163
164
            write!(fmt, " }}")
165
        }
166
    }
167
168
    impl Debug for BytesOrWide {
169
        fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
170
            output_filename(
171
                fmt,
172
                match self {
173
                    BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w),
174
                    BytesOrWide::Wide(w) => BytesOrWideString::Wide(w),
175
                },
176
                PrintFmt::Short,
177
                env::current_dir().as_ref().ok(),
178
            )
179
        }
180
    }
181
182
    impl Backtrace {
183
        fn enabled() -> bool {
184
            static ENABLED: AtomicUsize = AtomicUsize::new(0);
185
            match ENABLED.load(Ordering::Relaxed) {
186
                0 => {}
187
                1 => return false,
188
                _ => return true,
189
            }
190
            let enabled = match env::var_os("RUST_LIB_BACKTRACE") {
191
                Some(s) => s != "0",
192
                None => match env::var_os("RUST_BACKTRACE") {
193
                    Some(s) => s != "0",
194
                    None => false,
195
                },
196
            };
197
            ENABLED.store(enabled as usize + 1, Ordering::Relaxed);
198
            enabled
199
        }
200
201
        #[inline(never)] // want to make sure there's a frame here to remove
202
        pub(crate) fn capture() -> Backtrace {
203
            if Backtrace::enabled() {
204
                Backtrace::create(Backtrace::capture as usize)
205
            } else {
206
                let inner = Inner::Disabled;
207
                Backtrace { inner }
208
            }
209
        }
210
211
        // Capture a backtrace which starts just before the function addressed
212
        // by `ip`
213
        fn create(ip: usize) -> Backtrace {
214
            let mut frames = Vec::new();
215
            let mut actual_start = None;
216
            backtrace::trace(|frame| {
217
                frames.push(BacktraceFrame {
218
                    frame: frame.clone(),
219
                    symbols: Vec::new(),
220
                });
221
                if frame.symbol_address() as usize == ip && actual_start.is_none() {
222
                    actual_start = Some(frames.len() + 1);
223
                }
224
                true
225
            });
226
227
            // If no frames came out assume that this is an unsupported platform
228
            // since `backtrace` doesn't provide a way of learning this right
229
            // now, and this should be a good enough approximation.
230
            let inner = if frames.is_empty() {
231
                Inner::Unsupported
232
            } else {
233
                Inner::Captured(LazilyResolvedCapture::new(Capture {
234
                    actual_start: actual_start.unwrap_or(0),
235
                    frames,
236
                    resolved: false,
237
                }))
238
            };
239
240
            Backtrace { inner }
241
        }
242
243
        pub(crate) fn status(&self) -> BacktraceStatus {
244
            match self.inner {
245
                Inner::Unsupported => BacktraceStatus::Unsupported,
246
                Inner::Disabled => BacktraceStatus::Disabled,
247
                Inner::Captured(_) => BacktraceStatus::Captured,
248
            }
249
        }
250
    }
251
252
    impl Display for Backtrace {
253
        fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
254
            let capture = match &self.inner {
255
                Inner::Unsupported => return fmt.write_str("unsupported backtrace"),
256
                Inner::Disabled => return fmt.write_str("disabled backtrace"),
257
                Inner::Captured(c) => c.force(),
258
            };
259
260
            let full = fmt.alternate();
261
            let (frames, style) = if full {
262
                (&capture.frames[..], PrintFmt::Full)
263
            } else {
264
                (&capture.frames[capture.actual_start..], PrintFmt::Short)
265
            };
266
267
            // When printing paths we try to strip the cwd if it exists,
268
            // otherwise we just print the path as-is. Note that we also only do
269
            // this for the short format, because if it's full we presumably
270
            // want to print everything.
271
            let cwd = env::current_dir();
272
            let mut print_path = move |fmt: &mut fmt::Formatter, path: BytesOrWideString| {
273
                output_filename(fmt, path, style, cwd.as_ref().ok())
274
            };
275
276
            let mut f = BacktraceFmt::new(fmt, style, &mut print_path);
277
            f.add_context()?;
278
            for frame in frames {
279
                let mut f = f.frame();
280
                if frame.symbols.is_empty() {
281
                    f.print_raw(frame.frame.ip(), None, None, None)?;
282
                } else {
283
                    for symbol in frame.symbols.iter() {
284
                        f.print_raw_with_column(
285
                            frame.frame.ip(),
286
                            symbol.name.as_ref().map(|b| SymbolName::new(b)),
287
                            symbol.filename.as_ref().map(|b| match b {
288
                                BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w),
289
                                BytesOrWide::Wide(w) => BytesOrWideString::Wide(w),
290
                            }),
291
                            symbol.lineno,
292
                            symbol.colno,
293
                        )?;
294
                    }
295
                }
296
            }
297
            f.finish()?;
298
            Ok(())
299
        }
300
    }
301
302
    struct LazilyResolvedCapture {
303
        sync: Once,
304
        capture: UnsafeCell<Capture>,
305
    }
306
307
    impl LazilyResolvedCapture {
308
        fn new(capture: Capture) -> Self {
309
            LazilyResolvedCapture {
310
                sync: Once::new(),
311
                capture: UnsafeCell::new(capture),
312
            }
313
        }
314
315
        fn force(&self) -> &Capture {
316
            self.sync.call_once(|| {
317
                // Safety: This exclusive reference can't overlap with any
318
                // others. `Once` guarantees callers will block until this
319
                // closure returns. `Once` also guarantees only a single caller
320
                // will enter this closure.
321
                unsafe { &mut *self.capture.get() }.resolve();
322
            });
323
324
            // Safety: This shared reference can't overlap with the exclusive
325
            // reference above.
326
            unsafe { &*self.capture.get() }
327
        }
328
    }
329
330
    // Safety: Access to the inner value is synchronized using a thread-safe
331
    // `Once`. So long as `Capture` is `Sync`, `LazilyResolvedCapture` is too
332
    unsafe impl Sync for LazilyResolvedCapture where Capture: Sync {}
333
334
    impl Capture {
335
        fn resolve(&mut self) {
336
            // If we're already resolved, nothing to do!
337
            if self.resolved {
338
                return;
339
            }
340
            self.resolved = true;
341
342
            for frame in self.frames.iter_mut() {
343
                let symbols = &mut frame.symbols;
344
                let frame = &frame.frame;
345
                backtrace::resolve_frame(frame, |symbol| {
346
                    symbols.push(BacktraceSymbol {
347
                        name: symbol.name().map(|m| m.as_bytes().to_vec()),
348
                        filename: symbol.filename_raw().map(|b| match b {
349
                            BytesOrWideString::Bytes(b) => BytesOrWide::Bytes(b.to_owned()),
350
                            BytesOrWideString::Wide(b) => BytesOrWide::Wide(b.to_owned()),
351
                        }),
352
                        lineno: symbol.lineno(),
353
                        colno: symbol.colno(),
354
                    });
355
                });
356
            }
357
        }
358
    }
359
360
    // Prints the filename of the backtrace frame.
361
    fn output_filename(
362
        fmt: &mut fmt::Formatter,
363
        bows: BytesOrWideString,
364
        print_fmt: PrintFmt,
365
        cwd: Option<&PathBuf>,
366
    ) -> fmt::Result {
367
        let file: Cow<Path> = match bows {
368
            #[cfg(unix)]
369
            BytesOrWideString::Bytes(bytes) => {
370
                use std::os::unix::ffi::OsStrExt;
371
                Path::new(std::ffi::OsStr::from_bytes(bytes)).into()
372
            }
373
            #[cfg(not(unix))]
374
            BytesOrWideString::Bytes(bytes) => {
375
                Path::new(std::str::from_utf8(bytes).unwrap_or("<unknown>")).into()
376
            }
377
            #[cfg(windows)]
378
            BytesOrWideString::Wide(wide) => {
379
                use std::os::windows::ffi::OsStringExt;
380
                Cow::Owned(std::ffi::OsString::from_wide(wide).into())
381
            }
382
            #[cfg(not(windows))]
383
            BytesOrWideString::Wide(_wide) => Path::new("<unknown>").into(),
384
        };
385
        if print_fmt == PrintFmt::Short && file.is_absolute() {
386
            if let Some(cwd) = cwd {
387
                if let Ok(stripped) = file.strip_prefix(&cwd) {
388
                    if let Some(s) = stripped.to_str() {
389
                        return write!(fmt, ".{}{}", path::MAIN_SEPARATOR, s);
390
                    }
391
                }
392
            }
393
        }
394
        Display::fmt(&file.display(), fmt)
395
    }
396
}
397
398
0
fn _assert_send_sync() {
399
0
    fn _assert<T: Send + Sync>() {}
400
0
    _assert::<Backtrace>();
401
0
}