Skip to content

Commit 136a1db

Browse files
committed
Auto merge of rust-lang#2614 - saethlin:stack-inspection-tools, r=RalfJung
Improve miri_print_borrow_stacks Per post-merge review on rust-lang/miri#2322 * `miri_print_stacks` renamed to `miri_print_borrow_stacks` * A bit more details in docs, clarified how unstable these functions are meant to be * Print an `unknown_bottom` if one exists Open question: Currently `miri_get_alloc_id` gets the expected `AllocId` for `Wildcard` pointers, but for pointers with no provenance, the function reports UB and halts the interpreter. That's definitely wrong. But what _should_ we do? Is it reasonable to check if the pointer has `None` provenance and try to get an `AllocId` for its address? That still leaves us with a failure path, which in this case might be best-handled as an ICE? I'm just not sure that changing the return type of `miri_get_alloc_id` to `Option` is a win because it complicates all normal uses of this.
2 parents a46ccba + 71e6815 commit 136a1db

File tree

5 files changed

+47
-14
lines changed

5 files changed

+47
-14
lines changed

src/tools/miri/README.md

+13-5
Original file line numberDiff line numberDiff line change
@@ -538,15 +538,23 @@ extern "Rust" {
538538
fn miri_start_panic(payload: *mut u8) -> !;
539539

540540
/// Miri-provided extern function to get the internal unique identifier for the allocation that a pointer
541-
/// points to. This is only useful as an input to `miri_print_stacks`, and it is a separate call because
541+
/// points to. If this pointer is invalid (not pointing to an allocation), interpretation will abort.
542+
///
543+
/// This is only useful as an input to `miri_print_borrow_stacks`, and it is a separate call because
542544
/// getting a pointer to an allocation at runtime can change the borrow stacks in the allocation.
545+
/// This function should be considered unstable. It exists only to support `miri_print_borrow_stacks` and so
546+
/// inherits all of its instability.
543547
fn miri_get_alloc_id(ptr: *const ()) -> u64;
544548

545549
/// Miri-provided extern function to print (from the interpreter, not the program) the contents of all
546-
/// borrow stacks in an allocation. The format of what this emits is unstable and may change at any time.
547-
/// In particular, users should be aware that Miri will periodically attempt to garbage collect the
548-
/// contents of all stacks. Callers of this function may wish to pass `-Zmiri-tag-gc=0` to disable the GC.
549-
fn miri_print_stacks(alloc_id: u64);
550+
/// borrow stacks in an allocation. The leftmost tag is the bottom of the stack.
551+
/// The format of what this emits is unstable and may change at any time. In particular, users should be
552+
/// aware that Miri will periodically attempt to garbage collect the contents of all stacks. Callers of
553+
/// this function may wish to pass `-Zmiri-tag-gc=0` to disable the GC.
554+
///
555+
/// This function is extremely unstable. At any time the format of its output may change, its signature may
556+
/// change, or it may be removed entirely.
557+
fn miri_print_borrow_stacks(alloc_id: u64);
550558

551559
/// Miri-provided extern function to print (from the interpreter, not the
552560
/// program) the contents of a section of program memory, as bytes. Bytes

src/tools/miri/src/shims/foreign_items.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -420,10 +420,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
420420
"miri_get_alloc_id" => {
421421
let [ptr] = this.check_shim(abi, Abi::Rust, link_name, args)?;
422422
let ptr = this.read_pointer(ptr)?;
423-
let (alloc_id, _, _) = this.ptr_get_alloc_id(ptr)?;
423+
let (alloc_id, _, _) = this.ptr_get_alloc_id(ptr).map_err(|_e| {
424+
err_machine_stop!(TerminationInfo::Abort(
425+
format!("pointer passed to miri_get_alloc_id must not be dangling, got {ptr:?}")
426+
))
427+
})?;
424428
this.write_scalar(Scalar::from_u64(alloc_id.0.get()), dest)?;
425429
}
426-
"miri_print_stacks" => {
430+
"miri_print_borrow_stacks" => {
427431
let [id] = this.check_shim(abi, Abi::Rust, link_name, args)?;
428432
let id = this.read_scalar(id)?.to_u64()?;
429433
if let Some(id) = std::num::NonZeroU64::new(id) {

src/tools/miri/src/stacked_borrows/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1154,6 +1154,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
11541154
let stacks = alloc_extra.stacked_borrows.as_ref().unwrap().borrow();
11551155
for (range, stack) in stacks.stacks.iter_all() {
11561156
print!("{range:?}: [");
1157+
if let Some(bottom) = stack.unknown_bottom() {
1158+
print!(" unknown-bottom(..{bottom:?})");
1159+
}
11571160
for i in 0..stack.len() {
11581161
let item = stack.get(i).unwrap();
11591162
print!(" {:?}{:?}", item.perm(), item.tag());
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,46 @@
1+
//@compile-flags: -Zmiri-permissive-provenance
2+
#![feature(strict_provenance)]
13
use std::{
24
alloc::{self, Layout},
35
mem::ManuallyDrop,
46
};
57

68
extern "Rust" {
79
fn miri_get_alloc_id(ptr: *const u8) -> u64;
8-
fn miri_print_stacks(alloc_id: u64);
10+
fn miri_print_borrow_stacks(alloc_id: u64);
11+
}
12+
13+
fn get_alloc_id(ptr: *const u8) -> u64 {
14+
unsafe { miri_get_alloc_id(ptr) }
15+
}
16+
17+
fn print_borrow_stacks(alloc_id: u64) {
18+
unsafe { miri_print_borrow_stacks(alloc_id) }
919
}
1020

1121
fn main() {
1222
let ptr = unsafe { alloc::alloc(Layout::new::<u8>()) };
13-
let alloc_id = unsafe { miri_get_alloc_id(ptr) };
14-
unsafe { miri_print_stacks(alloc_id) };
23+
let alloc_id = get_alloc_id(ptr);
24+
print_borrow_stacks(alloc_id);
1525

1626
assert!(!ptr.is_null());
17-
unsafe { miri_print_stacks(alloc_id) };
27+
print_borrow_stacks(alloc_id);
1828

1929
unsafe { *ptr = 42 };
20-
unsafe { miri_print_stacks(alloc_id) };
30+
print_borrow_stacks(alloc_id);
2131

2232
let _b = unsafe { ManuallyDrop::new(Box::from_raw(ptr)) };
23-
unsafe { miri_print_stacks(alloc_id) };
33+
print_borrow_stacks(alloc_id);
2434

2535
let _ptr = unsafe { &*ptr };
26-
unsafe { miri_print_stacks(alloc_id) };
36+
print_borrow_stacks(alloc_id);
37+
38+
// Create an unknown bottom, and print it
39+
let ptr = ptr as usize as *mut u8;
40+
unsafe {
41+
*ptr = 5;
42+
}
43+
print_borrow_stacks(alloc_id);
2744

2845
unsafe { alloc::dealloc(ptr, Layout::new::<u8>()) };
2946
}

src/tools/miri/tests/pass/stacked-borrows/stack-printing.stdout

+1
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
0..1: [ SharedReadWrite<TAG> ]
44
0..1: [ SharedReadWrite<TAG> Unique<TAG> Unique<TAG> Unique<TAG> Unique<TAG> Unique<TAG> ]
55
0..1: [ SharedReadWrite<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> SharedReadOnly<TAG> ]
6+
0..1: [ unknown-bottom(..<TAG>) ]

0 commit comments

Comments
 (0)