Skip to main content

servoshell/
backtrace.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5//! Similar to `println!("{:?}", Backtrace::new())`, but doesn’t allocate.
6//!
7//! Seems to fix some deadlocks: <https://github.com/servo/servo/issues/24881>
8//!
9//! FIXME: if/when a future version of the `backtrace` crate has
10//! <https://github.com/rust-lang/backtrace-rs/pull/265>, use that instead.
11
12use std::fmt::{self, Write};
13
14use backtrace::{BytesOrWideString, PrintFmt};
15
16#[inline(never)]
17pub(crate) fn print(w: &mut dyn std::io::Write) -> Result<(), std::io::Error> {
18    write!(
19        w,
20        "{:?}",
21        Print {
22            print_fn_address: (print as *const ()).addr(),
23        }
24    )
25}
26
27#[cfg(target_env = "ohos")]
28pub(crate) fn print_ohos() {
29    // Print to `hilog`
30    log::error!(
31        "{:?}",
32        Print {
33            print_fn_address: (print as *const ()).addr(),
34        }
35    )
36}
37
38struct Print {
39    /// Function pointer without provenance - do not cast back and dereference.
40    print_fn_address: usize,
41}
42
43impl fmt::Debug for Print {
44    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
45        // Safety: we’re in a signal handler that is about to call `libc::_exit`.
46        // Potential data races from using `*_unsynchronized` functions are perhaps
47        // less bad than potential deadlocks?
48        unsafe {
49            let mut print_fn_frame = 0;
50            let mut frame_count = 0;
51            backtrace::trace_unsynchronized(|frame| {
52                let found = frame.symbol_address().addr() == self.print_fn_address;
53                if found {
54                    print_fn_frame = frame_count;
55                }
56                frame_count += 1;
57                !found
58            });
59
60            let mode = PrintFmt::Short;
61            let mut p = print_path;
62            let mut f = backtrace::BacktraceFmt::new(fmt, mode, &mut p);
63            f.add_context()?;
64            let mut result = Ok(());
65            let mut frame_count = 0;
66            backtrace::trace_unsynchronized(|frame| {
67                let skip = frame_count < print_fn_frame;
68                frame_count += 1;
69                if skip {
70                    return true;
71                }
72
73                let mut frame_fmt = f.frame();
74                let mut any_symbol = false;
75                backtrace::resolve_frame_unsynchronized(frame, |symbol| {
76                    any_symbol = true;
77                    if let Err(e) = frame_fmt.symbol(frame, symbol) {
78                        result = Err(e)
79                    }
80                });
81                if !any_symbol && let Err(e) = frame_fmt.print_raw(frame.ip(), None, None, None) {
82                    result = Err(e)
83                }
84                result.is_ok()
85            });
86            result?;
87            f.finish()
88        }
89    }
90}
91
92fn print_path(fmt: &mut fmt::Formatter<'_>, path: BytesOrWideString<'_>) -> fmt::Result {
93    match path {
94        BytesOrWideString::Bytes(mut bytes) => loop {
95            match std::str::from_utf8(bytes) {
96                Ok(s) => {
97                    fmt.write_str(s)?;
98                    break;
99                },
100                Err(err) => {
101                    fmt.write_char(std::char::REPLACEMENT_CHARACTER)?;
102                    match err.error_len() {
103                        Some(len) => bytes = &bytes[err.valid_up_to() + len..],
104                        None => break,
105                    }
106                },
107            }
108        },
109        BytesOrWideString::Wide(wide) => {
110            for c in std::char::decode_utf16(wide.iter().cloned()) {
111                fmt.write_char(c.unwrap_or(std::char::REPLACEMENT_CHARACTER))?
112            }
113        },
114    }
115    Ok(())
116}