Coverage Report

Created: 2025-07-04 06:57

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