Skip to content

Commit 9d60a23

Browse files
authored
Merge pull request rust-lang#4652 from RalfJung/track-alloc-runtime
add miri magic function to configure allocation tracking at runtime
2 parents 80bd9cf + 8f70d2d commit 9d60a23

File tree

7 files changed

+52
-36
lines changed

7 files changed

+52
-36
lines changed

src/tools/miri/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,8 @@ to Miri failing to detect cases of undefined behavior in a program.
480480
* `-Zmiri-track-alloc-id=<id1>,<id2>,...` shows a backtrace when the given allocations are
481481
being allocated or freed. This helps in debugging memory leaks and
482482
use after free bugs. Specifying this argument multiple times does not overwrite the previous
483-
values, instead it appends its values to the list. Listing an id multiple times has no effect.
483+
values, instead it appends its values to the list. Listing an ID multiple times has no effect.
484+
You can also add IDs at runtime using `miri_track_alloc`.
484485
* `-Zmiri-track-pointer-tag=<tag1>,<tag2>,...` shows a backtrace when a given pointer tag
485486
is created and when (if ever) it is popped from a borrow stack (which is where the tag becomes invalid
486487
and any future use of it will error). This helps you in finding out why UB is

src/tools/miri/src/diagnostics.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ pub enum NonHaltingDiagnostic {
126126
CreatedPointerTag(NonZero<u64>, Option<String>, Option<(AllocId, AllocRange, ProvenanceExtra)>),
127127
/// This `Item` was popped from the borrow stack. The string explains the reason.
128128
PoppedPointerTag(Item, String),
129-
CreatedAlloc(AllocId, Size, Align, MemoryKind),
129+
TrackingAlloc(AllocId, Size, Align),
130130
FreedAlloc(AllocId),
131131
AccessedAlloc(AllocId, AccessKind),
132132
RejectedIsolatedOp(String),
@@ -656,7 +656,7 @@ impl<'tcx> MiriMachine<'tcx> {
656656
("GenMC might miss possible behaviors of this code".to_string(), DiagLevel::Warning),
657657
CreatedPointerTag(..)
658658
| PoppedPointerTag(..)
659-
| CreatedAlloc(..)
659+
| TrackingAlloc(..)
660660
| AccessedAlloc(..)
661661
| FreedAlloc(..)
662662
| ProgressReport { .. }
@@ -673,9 +673,9 @@ impl<'tcx> MiriMachine<'tcx> {
673673
"created tag {tag:?} with {perm} at {alloc_id:?}{range:?} derived from {orig_tag:?}"
674674
),
675675
PoppedPointerTag(item, cause) => format!("popped tracked tag for item {item:?}{cause}"),
676-
CreatedAlloc(AllocId(id), size, align, kind) =>
676+
TrackingAlloc(AllocId(id), size, align) =>
677677
format!(
678-
"created {kind} allocation of {size} bytes (alignment {align} bytes) with id {id}",
678+
"now tracking allocation of {size} bytes (alignment {align} bytes) with id {id}",
679679
size = size.bytes(),
680680
align = align.bytes(),
681681
),

src/tools/miri/src/machine.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,7 @@ pub struct MiriMachine<'tcx> {
595595

596596
/// The allocation IDs to report when they are being allocated
597597
/// (helps for debugging memory leaks and use after free bugs).
598-
tracked_alloc_ids: FxHashSet<AllocId>,
598+
pub(crate) tracked_alloc_ids: FxHashSet<AllocId>,
599599
/// For the tracked alloc ids, also report read/write accesses.
600600
track_alloc_accesses: bool,
601601

@@ -951,7 +951,7 @@ impl<'tcx> MiriMachine<'tcx> {
951951
align: Align,
952952
) -> InterpResult<'tcx, AllocExtra<'tcx>> {
953953
if ecx.machine.tracked_alloc_ids.contains(&id) {
954-
ecx.emit_diagnostic(NonHaltingDiagnostic::CreatedAlloc(id, size, align, kind));
954+
ecx.emit_diagnostic(NonHaltingDiagnostic::TrackingAlloc(id, size, align));
955955
}
956956

957957
let borrow_tracker = ecx

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,21 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
350350
MiriMemoryKind::Miri.into(),
351351
)?;
352352
}
353+
"miri_track_alloc" => {
354+
let [ptr] = this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?;
355+
let ptr = this.read_pointer(ptr)?;
356+
let (alloc_id, _, _) = this.ptr_get_alloc_id(ptr, 0).map_err_kind(|_e| {
357+
err_machine_stop!(TerminationInfo::Abort(format!(
358+
"pointer passed to `miri_get_alloc_id` must not be dangling, got {ptr:?}"
359+
)))
360+
})?;
361+
if this.machine.tracked_alloc_ids.insert(alloc_id) {
362+
let info = this.get_alloc_info(alloc_id);
363+
this.emit_diagnostic(NonHaltingDiagnostic::TrackingAlloc(
364+
alloc_id, info.size, info.align,
365+
));
366+
}
367+
}
353368
"miri_start_unwind" => {
354369
let [payload] =
355370
this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?;
Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,15 @@
1-
#![no_std]
2-
#![no_main]
3-
//@compile-flags: -Zmiri-track-alloc-id=19 -Zmiri-track-alloc-accesses -Cpanic=abort
4-
//@normalize-stderr-test: "id 19" -> "id $$ALLOC"
5-
//@only-target: linux # alloc IDs differ between OSes (due to extern static allocations)
1+
//@compile-flags: -Zmiri-track-alloc-accesses
2+
//@normalize-stderr-test: "id \d+" -> "id $$ALLOC"
63

7-
extern "Rust" {
8-
fn miri_alloc(size: usize, align: usize) -> *mut u8;
9-
fn miri_dealloc(ptr: *mut u8, size: usize, align: usize);
10-
}
4+
#[path = "../utils/mod.rs"]
5+
mod utils;
116

12-
#[no_mangle]
13-
fn miri_start(_argc: isize, _argv: *const *const u8) -> isize {
7+
fn main() {
148
unsafe {
15-
let ptr = miri_alloc(123, 1);
9+
let mut b = Box::<[u8; 123]>::new_uninit();
10+
let ptr = b.as_mut_ptr() as *mut u8;
11+
utils::miri_track_alloc(ptr);
1612
*ptr = 42; // Crucially, only a write is printed here, no read!
1713
assert_eq!(*ptr, 42);
18-
miri_dealloc(ptr, 123, 1);
1914
}
20-
0
21-
}
22-
23-
#[panic_handler]
24-
fn panic_handler(_: &core::panic::PanicInfo) -> ! {
25-
loop {}
2615
}
Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
note: created Miri bare-metal heap allocation of 123 bytes (alignment ALIGN bytes) with id $ALLOC
1+
note: now tracking allocation of 123 bytes (alignment ALIGN bytes) with id $ALLOC
22
--> tests/pass/alloc-access-tracking.rs:LL:CC
33
|
4-
LL | let ptr = miri_alloc(123, 1);
5-
| ^^^^^^^^^^^^^^^^^^ tracking was triggered here
4+
LL | utils::miri_track_alloc(ptr);
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tracking was triggered here
66
|
77
= note: BACKTRACE:
8-
= note: inside `miri_start` at tests/pass/alloc-access-tracking.rs:LL:CC
8+
= note: inside `main` at tests/pass/alloc-access-tracking.rs:LL:CC
99

1010
note: write access to allocation with id $ALLOC
1111
--> tests/pass/alloc-access-tracking.rs:LL:CC
@@ -14,7 +14,7 @@ LL | *ptr = 42; // Crucially, only a write is printed here, no read!
1414
| ^^^^^^^^^ tracking was triggered here
1515
|
1616
= note: BACKTRACE:
17-
= note: inside `miri_start` at tests/pass/alloc-access-tracking.rs:LL:CC
17+
= note: inside `main` at tests/pass/alloc-access-tracking.rs:LL:CC
1818

1919
note: read access to allocation with id $ALLOC
2020
--> tests/pass/alloc-access-tracking.rs:LL:CC
@@ -23,15 +23,21 @@ LL | assert_eq!(*ptr, 42);
2323
| ^^^^^^^^^^^^^^^^^^^^ tracking was triggered here
2424
|
2525
= note: BACKTRACE:
26-
= note: inside `miri_start` at RUSTLIB/core/src/macros/mod.rs:LL:CC
26+
= note: inside `main` at RUSTLIB/core/src/macros/mod.rs:LL:CC
2727
= note: this note originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
2828

2929
note: freed allocation with id $ALLOC
30-
--> tests/pass/alloc-access-tracking.rs:LL:CC
30+
--> RUSTLIB/alloc/src/boxed.rs:LL:CC
3131
|
32-
LL | miri_dealloc(ptr, 123, 1);
33-
| ^^^^^^^^^^^^^^^^^^^^^^^^^ tracking was triggered here
32+
LL | self.1.deallocate(From::from(ptr.cast()), layout);
33+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tracking was triggered here
3434
|
3535
= note: BACKTRACE:
36-
= note: inside `miri_start` at tests/pass/alloc-access-tracking.rs:LL:CC
36+
= note: inside `<std::boxed::Box<std::mem::MaybeUninit<[u8; 123]>> as std::ops::Drop>::drop` at RUSTLIB/alloc/src/boxed.rs:LL:CC
37+
= note: inside `std::ptr::drop_in_place::<std::boxed::Box<std::mem::MaybeUninit<[u8; 123]>>> - shim(Some(std::boxed::Box<std::mem::MaybeUninit<[u8; 123]>>))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC
38+
note: inside `main`
39+
--> tests/pass/alloc-access-tracking.rs:LL:CC
40+
|
41+
LL | }
42+
| ^
3743

src/tools/miri/tests/utils/miri_extern.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,11 @@ extern "Rust" {
119119
/// Miri-provided extern function to deallocate memory.
120120
pub fn miri_dealloc(ptr: *mut u8, size: usize, align: usize);
121121

122+
/// Add the allocation that this pointer points to to the "tracked" allocations.
123+
/// This is equivalent to `-Zmiri-track-allic-id=<id>`, but also works if the ID is
124+
/// only known at runtime.
125+
pub fn miri_track_alloc(ptr: *const u8);
126+
122127
/// Convert a path from the host Miri runs on to the target Miri interprets.
123128
/// Performs conversion of path separators as needed.
124129
///

0 commit comments

Comments
 (0)