Skip to content

Commit 73d5c42

Browse files
committed
Auto merge of #1580 - Aaron1011:feature/backtrace-fn-ptr, r=RalfJung
Add an `fn_ptr` field to `MiriFrame` The `backtrace-rs` crate can use this to implement `Frame::symbol_address`, which is used to skip frames above the call to `Backtrace::capture` on the stack. The function pointer will not be useable for comparison purposes if the function is generic, as CTFE creates a new function pointer for each cast of a (monomorphized) generic function. However, this already affects code running under Miri, and isn't a problem for `backtrace-rs` (which only casts a non-generic function). I've added logic to allow `MiriFrame` to have either 4 or 5 fields - if a 5th field is present, we write the function pointer to it.
2 parents c467345 + c889eba commit 73d5c42

File tree

6 files changed

+57
-27
lines changed

6 files changed

+57
-27
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,10 @@ extern "Rust" {
292292
/// lineno: u32,
293293
/// // The column number currently being executed in `filename`, starting from '1'.
294294
/// colno: u32,
295+
/// // The function pointer to the function currently being executed.
296+
/// // This can be compared against function pointers obtained by
297+
/// // casting a function (e.g. `my_fn as *mut ()`)
298+
/// fn_ptr: *mut ()
295299
/// }
296300
/// ```
297301
///

src/shims/backtrace.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
9292
throw_ub_format!("expected function pointer, found {:?}", ptr);
9393
};
9494

95-
if dest.layout.layout.fields.count() != 4 {
96-
throw_ub_format!("bad declaration of miri_resolve_frame - should return a struct with 4 fields");
95+
// Reconstruct the original function pointer,
96+
// which we pass to user code.
97+
let mut fn_ptr = ptr;
98+
fn_ptr.offset = Size::from_bytes(0);
99+
let fn_ptr = Scalar::Ptr(fn_ptr);
100+
101+
let num_fields = dest.layout.layout.fields.count();
102+
103+
if !(4..=5).contains(&num_fields) {
104+
// Always mention 5 fields, since the 4-field struct
105+
// is deprecated and slated for removal.
106+
throw_ub_format!("bad declaration of miri_resolve_frame - should return a struct with 5 fields");
97107
}
98108

99109
let pos = BytePos(ptr.offset.bytes().try_into().unwrap());
@@ -122,6 +132,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
122132
this.write_immediate(filename_alloc.to_ref(), this.mplace_field(dest, 1)?.into())?;
123133
this.write_scalar(lineno_alloc, this.mplace_field(dest, 2)?.into())?;
124134
this.write_scalar(colno_alloc, this.mplace_field(dest, 3)?.into())?;
135+
136+
// Support a 4-field struct for now - this is deprecated
137+
// and slated for removal.
138+
if num_fields == 5 {
139+
this.write_scalar(fn_ptr, this.mplace_field(dest, 4)?.into())?;
140+
}
141+
125142
Ok(())
126143
}
127144
}

tests/compile-fail/backtrace/bad-backtrace-decl.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ fn main() {
77
let frames = unsafe { miri_get_backtrace(0) };
88
for frame in frames.into_iter() {
99
unsafe {
10-
miri_resolve_frame(*frame, 0); //~ ERROR Undefined Behavior: bad declaration of miri_resolve_frame - should return a struct with 4 fields
10+
miri_resolve_frame(*frame, 0); //~ ERROR Undefined Behavior: bad declaration of miri_resolve_frame - should return a struct with 5 fields
1111
}
1212
}
1313
}

tests/run-pass/backtrace-api.rs

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,6 @@
22
// normalize-stderr-test "RUSTLIB/(.*):\d+:\d+ "-> "RUSTLIB/$1:LL:COL "
33
// normalize-stderr-test "::<.*>" -> ""
44

5-
extern "Rust" {
6-
fn miri_get_backtrace(flags: u64) -> Box<[*mut ()]>;
7-
fn miri_resolve_frame(ptr: *mut (), flags: u64) -> MiriFrame;
8-
}
9-
10-
#[derive(Debug)]
11-
#[repr(C)]
12-
struct MiriFrame {
13-
name: Box<[u8]>,
14-
filename: Box<[u8]>,
15-
lineno: u32,
16-
colno: u32
17-
}
18-
195
#[inline(never)] fn func_a() -> Box<[*mut ()]> { func_b::<u8>() }
206
#[inline(never)] fn func_b<T>() -> Box<[*mut ()]> { func_c() }
217

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

23+
if name == "func_a" {
24+
assert_eq!(func_a as *mut (), miri_frame.fn_ptr);
25+
}
26+
3727
// Print every frame to stderr.
3828
let out = format!("{}:{}:{} ({})", filename, miri_frame.lineno, miri_frame.colno, name);
3929
eprintln!("{}", out);
@@ -45,3 +35,22 @@ fn main() {
4535
}
4636
}
4737
}
38+
39+
// This goes at the bottom of the file so that we can change it
40+
// without disturbing line numbers of the functions in the backtrace.
41+
42+
extern "Rust" {
43+
fn miri_get_backtrace(flags: u64) -> Box<[*mut ()]>;
44+
fn miri_resolve_frame(ptr: *mut (), flags: u64) -> MiriFrame;
45+
}
46+
47+
#[derive(Debug)]
48+
#[repr(C)]
49+
struct MiriFrame {
50+
name: Box<[u8]>,
51+
filename: Box<[u8]>,
52+
lineno: u32,
53+
colno: u32,
54+
fn_ptr: *mut (),
55+
}
56+

tests/run-pass/backtrace-api.stderr

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
$DIR/backtrace-api.rs:27:59 (func_d)
2-
$DIR/backtrace-api.rs:26:50 (func_c)
3-
$DIR/backtrace-api.rs:20:53 (func_b)
4-
$DIR/backtrace-api.rs:19:50 (func_a)
5-
$DIR/backtrace-api.rs:31:18 (main)
1+
$DIR/backtrace-api.rs:13:59 (func_d)
2+
$DIR/backtrace-api.rs:12:50 (func_c)
3+
$DIR/backtrace-api.rs:6:53 (func_b)
4+
$DIR/backtrace-api.rs:5:50 (func_a)
5+
$DIR/backtrace-api.rs:17:18 (main)
66
RUSTLIB/core/src/ops/function.rs:LL:COL (<fn() as std::ops::FnOnce<()>>::call_once - shim(fn()))
77
RUSTLIB/std/src/sys_common/backtrace.rs:LL:COL (std::sys_common::backtrace::__rust_begin_short_backtrace)
88
RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start::{closure#0})

tests/run-pass/backtrace-api.stdout

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
$DIR/backtrace-api.rs:27:59 (func_d)
2-
$DIR/backtrace-api.rs:26:50 (func_c)
3-
$DIR/backtrace-api.rs:20:53 (func_b::<u8>)
4-
$DIR/backtrace-api.rs:19:50 (func_a)
5-
$DIR/backtrace-api.rs:31:18 (main)
1+
$DIR/backtrace-api.rs:13:59 (func_d)
2+
$DIR/backtrace-api.rs:12:50 (func_c)
3+
$DIR/backtrace-api.rs:6:53 (func_b::<u8>)
4+
$DIR/backtrace-api.rs:5:50 (func_a)
5+
$DIR/backtrace-api.rs:17:18 (main)

0 commit comments

Comments
 (0)