Files
servo/ports/servoshell/backtrace.rs
Jonathan Schwender e4eca03a7b servoshell: Fix function_casts_as_integer lint (#43469)
Found when building with Rust 1.94. The lint itself only complains about
the direct function ptr to usize cast and recommends an intermediate `as
*const ()` cast. We also don't need provenance here, so we can also use
the more explicit .addr() cast.

Testing: Covered by compilation in CI.

Signed-off-by: Jonathan Schwender <schwenderjonathan@gmail.com>
2026-03-20 07:06:01 +00:00

119 lines
3.8 KiB
Rust
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
//! Similar to `println!("{:?}", Backtrace::new())`, but doesnt allocate.
//!
//! Seems to fix some deadlocks: <https://github.com/servo/servo/issues/24881>
//!
//! FIXME: if/when a future version of the `backtrace` crate has
//! <https://github.com/rust-lang/backtrace-rs/pull/265>, use that instead.
use std::fmt::{self, Write};
use backtrace::{BytesOrWideString, PrintFmt};
#[inline(never)]
pub(crate) fn print(w: &mut dyn std::io::Write) -> Result<(), std::io::Error> {
write!(
w,
"{:?}",
Print {
print_fn_address: (print as *const ()).addr(),
}
)
}
#[cfg(target_env = "ohos")]
pub(crate) fn print_ohos() {
// Print to `hilog`
log::error!(
"{:?}",
Print {
print_fn_address: (print as *const ()).addr(),
}
)
}
struct Print {
/// Function pointer without provenance - do not cast back and dereference.
print_fn_address: usize,
}
impl fmt::Debug for Print {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
// Safety: were in a signal handler that is about to call `libc::_exit`.
// Potential data races from using `*_unsynchronized` functions are perhaps
// less bad than potential deadlocks?
unsafe {
let mut print_fn_frame = 0;
let mut frame_count = 0;
backtrace::trace_unsynchronized(|frame| {
let found = frame.symbol_address().addr() == self.print_fn_address;
if found {
print_fn_frame = frame_count;
}
frame_count += 1;
!found
});
let mode = PrintFmt::Short;
let mut p = print_path;
let mut f = backtrace::BacktraceFmt::new(fmt, mode, &mut p);
f.add_context()?;
let mut result = Ok(());
let mut frame_count = 0;
backtrace::trace_unsynchronized(|frame| {
let skip = frame_count < print_fn_frame;
frame_count += 1;
if skip {
return true;
}
let mut frame_fmt = f.frame();
let mut any_symbol = false;
backtrace::resolve_frame_unsynchronized(frame, |symbol| {
any_symbol = true;
if let Err(e) = frame_fmt.symbol(frame, symbol) {
result = Err(e)
}
});
if !any_symbol {
if let Err(e) = frame_fmt.print_raw(frame.ip(), None, None, None) {
result = Err(e)
}
}
result.is_ok()
});
result?;
f.finish()
}
}
}
fn print_path(fmt: &mut fmt::Formatter<'_>, path: BytesOrWideString<'_>) -> fmt::Result {
match path {
BytesOrWideString::Bytes(mut bytes) => loop {
match std::str::from_utf8(bytes) {
Ok(s) => {
fmt.write_str(s)?;
break;
},
Err(err) => {
fmt.write_char(std::char::REPLACEMENT_CHARACTER)?;
match err.error_len() {
Some(len) => bytes = &bytes[err.valid_up_to() + len..],
None => break,
}
},
}
},
BytesOrWideString::Wide(wide) => {
for c in std::char::decode_utf16(wide.iter().cloned()) {
fmt.write_char(c.unwrap_or(std::char::REPLACEMENT_CHARACTER))?
}
},
}
Ok(())
}