Skip to content

Make Miri backtraces work with #[global_allocator] #462

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 43 additions & 6 deletions src/backtrace/miri.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
use alloc::boxed::Box;
use alloc::vec::Vec;
use core::ffi::c_void;

extern "Rust" {
fn miri_get_backtrace(flags: u64) -> Box<[*mut ()]>;
fn miri_backtrace_size(flags: u64) -> usize;
fn miri_get_backtrace(flags: u64, buf: *mut *mut ());
fn miri_resolve_frame(ptr: *mut (), flags: u64) -> MiriFrame;
fn miri_resolve_frame_names(ptr: *mut (), flags: u64, name_buf: *mut u8, filename_buf: *mut u8);
}

#[derive(Clone, Debug)]
#[repr(C)]
pub struct MiriFrame {
pub name_len: usize,
pub filename_len: usize,
pub lineno: u32,
pub colno: u32,
pub fn_ptr: *mut c_void,
}

#[derive(Clone, Debug)]
pub struct FullMiriFrame {
pub name: Box<[u8]>,
pub filename: Box<[u8]>,
pub lineno: u32,
Expand All @@ -19,7 +30,7 @@ pub struct MiriFrame {
#[derive(Debug, Clone)]
pub struct Frame {
pub addr: *mut c_void,
pub inner: MiriFrame,
pub inner: FullMiriFrame,
}

// SAFETY: Miri guarantees that the returned pointer
Expand Down Expand Up @@ -54,15 +65,41 @@ pub fn trace<F: FnMut(&super::Frame) -> bool>(cb: F) {
pub fn resolve_addr(ptr: *mut c_void) -> Frame {
// SAFETY: Miri will stop execution with an error if this pointer
// is invalid.
let frame: MiriFrame = unsafe { miri_resolve_frame(ptr as *mut (), 0) };
let frame = unsafe { miri_resolve_frame(ptr as *mut (), 1) };

let mut name = Vec::with_capacity(frame.name_len);
let mut filename = Vec::with_capacity(frame.filename_len);

// SAFETY: name and filename have been allocated with the amount
// of memory miri has asked for, and miri guarantees it will initialize it
unsafe {
miri_resolve_frame_names(ptr as *mut (), 0, name.as_mut_ptr(), filename.as_mut_ptr());

name.set_len(frame.name_len);
filename.set_len(frame.filename_len);
}

Frame {
addr: ptr,
inner: frame,
inner: FullMiriFrame {
name: name.into(),
filename: filename.into(),
lineno: frame.lineno,
colno: frame.colno,
fn_ptr: frame.fn_ptr,
},
}
}

pub unsafe fn trace_unsynchronized<F: FnMut(&super::Frame) -> bool>(mut cb: F) {
let frames = miri_get_backtrace(0);
let len = miri_backtrace_size(0);

let mut frames = Vec::with_capacity(len);

miri_get_backtrace(1, frames.as_mut_ptr());

frames.set_len(len);

for ptr in frames.iter() {
let frame = resolve_addr(*ptr as *mut c_void);
cb(&super::Frame { inner: frame });
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@
#[macro_use]
extern crate std;

// This is only used for gimli right now, which is only used on some platforms,
// This is only used for gimli right now, which is only used on some platforms, and miri
// so don't worry if it's unused in other configurations.
#[allow(unused_extern_crates)]
extern crate alloc;
Expand Down