Skip to content

Commit 91b58c9

Browse files
committed
Auto merge of #1485 - RalfJung:miri-extern-fn, r=oli-obk
Miri: use extern fn to expose interpreter operations to program; fix leak checker on Windows This is the Miri side of rust-lang/rust#74681. Fixes #1302 Fixes #1318
2 parents 592b140 + c641fbd commit 91b58c9

File tree

8 files changed

+52
-15
lines changed

8 files changed

+52
-15
lines changed

README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,29 @@ different Miri binaries, and as such worth documenting:
233233
interpret the code but compile it like rustc would. This is useful to be sure
234234
that the compiled `rlib`s are compatible with Miri.
235235

236+
## Miri `extern` functions
237+
238+
Miri provides some `extern` functions that programs can import to access
239+
Miri-specific functionality:
240+
241+
```rust
242+
#[cfg(miri)]
243+
extern "Rust" {
244+
/// Miri-provided extern function to mark the block `ptr` points to as a "root"
245+
/// for some static memory. This memory and everything reachable by it is not
246+
/// considered leaking even if it still exists when the program terminates.
247+
///
248+
/// `ptr` has to point to the beginning of an allocated block.
249+
fn miri_static_root(ptr: *const u8);
250+
251+
/// Miri-provided extern function to begin unwinding with the given payload.
252+
///
253+
/// This is internal and unstable and should not be used; we give it here
254+
/// just to be complete.
255+
fn miri_start_panic(payload: *mut u8) -> !;
256+
}
257+
```
258+
236259
## Contributing and getting help
237260

238261
If you want to contribute to Miri, great! Please check out our

rust-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
4825e12fc9c79954aa0fe18f5521efa6c19c7539
1+
0e11fc8053d32c44e7152865852acc5c3c54efb3

src/eval.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use std::ffi::OsStr;
55

66
use rand::rngs::StdRng;
77
use rand::SeedableRng;
8+
use log::info;
89

910
use rustc_hir::def_id::DefId;
1011
use rustc_middle::ty::{self, layout::LayoutCx, TyCtxt};
@@ -195,8 +196,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
195196
/// Returns `Some(return_code)` if program executed completed.
196197
/// Returns `None` if an evaluation error occured.
197198
pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option<i64> {
198-
// FIXME: on Windows, we ignore leaks (https://github.com/rust-lang/miri/issues/1302).
199-
let ignore_leaks = config.ignore_leaks || tcx.sess.target.target.target_os == "windows";
199+
// Copy setting before we move `config`.
200+
let ignore_leaks = config.ignore_leaks;
200201

201202
let (mut ecx, ret_place) = match create_ecx(tcx, main_id, config) {
202203
Ok(v) => v,
@@ -244,7 +245,8 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) ->
244245
match res {
245246
Ok(return_code) => {
246247
if !ignore_leaks {
247-
let leaks = ecx.memory.leak_report();
248+
info!("Additonal static roots: {:?}", ecx.machine.static_roots);
249+
let leaks = ecx.memory.leak_report(&ecx.machine.static_roots);
248250
if leaks != 0 {
249251
tcx.sess.err("the evaluated program leaked memory");
250252
// Ignore the provided return code - let the reported error

src/machine.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,9 @@ pub struct Evaluator<'mir, 'tcx> {
262262

263263
/// Precomputed `TyLayout`s for primitive data types that are commonly used inside Miri.
264264
pub(crate) layouts: PrimitiveLayouts<'tcx>,
265+
266+
/// Allocations that are considered roots of static memory (that may leak).
267+
pub(crate) static_roots: Vec<AllocId>,
265268
}
266269

267270
impl<'mir, 'tcx> Evaluator<'mir, 'tcx> {
@@ -289,6 +292,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> {
289292
time_anchor: Instant::now(),
290293
layouts,
291294
threads: ThreadManager::default(),
295+
static_roots: Vec::new(),
292296
}
293297
}
294298
}

src/shims/foreign_items.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
111111
def_id: DefId,
112112
args: &[OpTy<'tcx, Tag>],
113113
ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>,
114-
_unwind: Option<mir::BasicBlock>,
114+
unwind: Option<mir::BasicBlock>,
115115
) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> {
116116
let this = self.eval_context_mut();
117117
let attrs = this.tcx.get_attrs(def_id);
@@ -126,6 +126,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
126126
// First: functions that diverge.
127127
let (dest, ret) = match ret {
128128
None => match link_name {
129+
"miri_start_panic" => {
130+
this.handle_miri_start_panic(args, unwind)?;
131+
return Ok(None);
132+
}
129133
// This matches calls to the foreign item `panic_impl`.
130134
// The implementation is provided by the function with the `#[panic_handler]` attribute.
131135
"panic_impl" => {
@@ -193,6 +197,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
193197
// Here we dispatch all the shims for foreign functions. If you have a platform specific
194198
// shim, add it to the corresponding submodule.
195199
match link_name {
200+
// Miri-specific extern functions
201+
"miri_static_root" => {
202+
let &[ptr] = check_arg_count(args)?;
203+
let ptr = this.read_scalar(ptr)?.not_undef()?;
204+
let ptr = this.force_ptr(ptr)?;
205+
if ptr.offset != Size::ZERO {
206+
throw_unsup_format!("pointer passed to miri_static_root must point to beginning of an allocated block");
207+
}
208+
this.machine.static_roots.push(ptr.alloc_id);
209+
}
210+
196211
// Standard C allocation
197212
"malloc" => {
198213
let &[size] = check_arg_count(args)?;

src/shims/intrinsics.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
1818
instance: ty::Instance<'tcx>,
1919
args: &[OpTy<'tcx, Tag>],
2020
ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>,
21-
unwind: Option<mir::BasicBlock>,
21+
_unwind: Option<mir::BasicBlock>,
2222
) -> InterpResult<'tcx> {
2323
let this = self.eval_context_mut();
2424
let intrinsic_name = this.tcx.item_name(instance.def_id());
@@ -32,13 +32,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
3232
return Ok(());
3333
}
3434

35-
// First handle intrinsics without return place.
35+
// All supported intrinsics have a return place.
3636
let intrinsic_name = &*intrinsic_name.as_str();
3737
let (dest, ret) = match ret {
38-
None => match intrinsic_name {
39-
"miri_start_panic" => return this.handle_miri_start_panic(args, unwind),
40-
_ => throw_unsup_format!("unimplemented (diverging) intrinsic: {}", intrinsic_name),
41-
},
38+
None => throw_unsup_format!("unimplemented (diverging) intrinsic: {}", intrinsic_name),
4239
Some(p) => p,
4340
};
4441

tests/compile-fail/memleak.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// ignore-windows: We do not check leaks on Windows
2-
31
//error-pattern: the evaluated program leaked memory
42

53
fn main() {

tests/compile-fail/memleak_rc.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// ignore-windows: We do not check leaks on Windows
2-
31
//error-pattern: the evaluated program leaked memory
42

53
use std::rc::Rc;

0 commit comments

Comments
 (0)