Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,10 @@ extern "Rust" {
/// lineno: u32,
/// // The column number currently being executed in `filename`, starting from '1'.
/// colno: u32,
/// // The function pointer to the function currently being executed.
/// // This can be compared against function pointers obtained by
/// // casting a function (e.g. `my_fn as *mut ()`)
/// fn_ptr: *mut ()
/// }
/// ```
///
Expand Down
19 changes: 17 additions & 2 deletions src/shims/backtrace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
throw_ub_format!("expected function pointer, found {:?}", ptr);
};

if dest.layout.layout.fields.count() != 4 {
throw_ub_format!("bad declaration of miri_resolve_frame - should return a struct with 4 fields");
// Reconstruct the original function pointer,
// which we pass to user code.
let mut fn_ptr = ptr;
fn_ptr.offset = Size::from_bytes(0);
let fn_ptr = Scalar::Ptr(fn_ptr);

let num_fields = dest.layout.layout.fields.count();

if num_fields != 4 && num_fields != 5 {
// Always mention 5 fields, since the 4-field struct is only supported
// for backwards compatiblity. New code should declare 5 fields
throw_ub_format!("bad declaration of miri_resolve_frame - should return a struct with 5 fields");
}

let pos = BytePos(ptr.offset.bytes().try_into().unwrap());
Expand Down Expand Up @@ -122,6 +132,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
this.write_immediate(filename_alloc.to_ref(), this.mplace_field(dest, 1)?.into())?;
this.write_scalar(lineno_alloc, this.mplace_field(dest, 2)?.into())?;
this.write_scalar(colno_alloc, this.mplace_field(dest, 3)?.into())?;

if num_fields == 5 {
this.write_scalar(fn_ptr, this.mplace_field(dest, 4)?.into())?;
}

Ok(())
}
}
2 changes: 1 addition & 1 deletion tests/compile-fail/backtrace/bad-backtrace-decl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ fn main() {
let frames = unsafe { miri_get_backtrace(0) };
for frame in frames.into_iter() {
unsafe {
miri_resolve_frame(*frame, 0); //~ ERROR Undefined Behavior: bad declaration of miri_resolve_frame - should return a struct with 4 fields
miri_resolve_frame(*frame, 0); //~ ERROR Undefined Behavior: bad declaration of miri_resolve_frame - should return a struct with 5 fields
}
}
}
37 changes: 23 additions & 14 deletions tests/run-pass/backtrace-api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,6 @@
// normalize-stderr-test "RUSTLIB/(.*):\d+:\d+ "-> "RUSTLIB/$1:LL:COL "
// normalize-stderr-test "::<.*>" -> ""

extern "Rust" {
fn miri_get_backtrace(flags: u64) -> Box<[*mut ()]>;
fn miri_resolve_frame(ptr: *mut (), flags: u64) -> MiriFrame;
}

#[derive(Debug)]
#[repr(C)]
struct MiriFrame {
name: Box<[u8]>,
filename: Box<[u8]>,
lineno: u32,
colno: u32
}

#[inline(never)] fn func_a() -> Box<[*mut ()]> { func_b::<u8>() }
#[inline(never)] fn func_b<T>() -> Box<[*mut ()]> { func_c() }

Expand All @@ -34,6 +20,10 @@ fn main() {
let name = String::from_utf8(miri_frame.name.into()).unwrap();
let filename = String::from_utf8(miri_frame.filename.into()).unwrap();

if name == "func_a" {
assert_eq!(func_a as *mut (), miri_frame.fn_ptr);
}

// Print every frame to stderr.
let out = format!("{}:{}:{} ({})", filename, miri_frame.lineno, miri_frame.colno, name);
eprintln!("{}", out);
Expand All @@ -45,3 +35,22 @@ fn main() {
}
}
}

// This goes at the bottom of the file so that we can change it
// without disturbing line numbers of the functions in the backtrace.

extern "Rust" {
fn miri_get_backtrace(flags: u64) -> Box<[*mut ()]>;
fn miri_resolve_frame(ptr: *mut (), flags: u64) -> MiriFrame;
}

#[derive(Debug)]
#[repr(C)]
struct MiriFrame {
name: Box<[u8]>,
filename: Box<[u8]>,
lineno: u32,
colno: u32,
fn_ptr: *mut (),
}

10 changes: 5 additions & 5 deletions tests/run-pass/backtrace-api.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
$DIR/backtrace-api.rs:27:59 (func_d)
$DIR/backtrace-api.rs:26:50 (func_c)
$DIR/backtrace-api.rs:20:53 (func_b)
$DIR/backtrace-api.rs:19:50 (func_a)
$DIR/backtrace-api.rs:31:18 (main)
$DIR/backtrace-api.rs:13:59 (func_d)
$DIR/backtrace-api.rs:12:50 (func_c)
$DIR/backtrace-api.rs:6:53 (func_b)
$DIR/backtrace-api.rs:5:50 (func_a)
$DIR/backtrace-api.rs:17:18 (main)
RUSTLIB/core/src/ops/function.rs:LL:COL (<fn() as std::ops::FnOnce<()>>::call_once - shim(fn()))
RUSTLIB/std/src/sys_common/backtrace.rs:LL:COL (std::sys_common::backtrace::__rust_begin_short_backtrace)
RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start::{closure#0})
Expand Down
10 changes: 5 additions & 5 deletions tests/run-pass/backtrace-api.stdout
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
$DIR/backtrace-api.rs:27:59 (func_d)
$DIR/backtrace-api.rs:26:50 (func_c)
$DIR/backtrace-api.rs:20:53 (func_b::<u8>)
$DIR/backtrace-api.rs:19:50 (func_a)
$DIR/backtrace-api.rs:31:18 (main)
$DIR/backtrace-api.rs:13:59 (func_d)
$DIR/backtrace-api.rs:12:50 (func_c)
$DIR/backtrace-api.rs:6:53 (func_b::<u8>)
$DIR/backtrace-api.rs:5:50 (func_a)
$DIR/backtrace-api.rs:17:18 (main)