diff --git a/README.md b/README.md index e20c53b68d..f97639ea5b 100644 --- a/README.md +++ b/README.md @@ -233,6 +233,29 @@ different Miri binaries, and as such worth documenting: interpret the code but compile it like rustc would. This is useful to be sure that the compiled `rlib`s are compatible with Miri. +## Miri `extern` functions + +Miri provides some `extern` functions that programs can import to access +Miri-specific functionality: + +```rust +#[cfg(miri)] +extern "Rust" { + /// Miri-provided extern function to mark the block `ptr` points to as a "root" + /// for some static memory. This memory and everything reachable by it is not + /// considered leaking even if it still exists when the program terminates. + /// + /// `ptr` has to point to the beginning of an allocated block. + fn miri_static_root(ptr: *const u8); + + /// Miri-provided extern function to begin unwinding with the given payload. + /// + /// This is internal and unstable and should not be used; we give it here + /// just to be complete. + fn miri_start_panic(payload: *mut u8) -> !; +} +``` + ## Contributing and getting help If you want to contribute to Miri, great! Please check out our diff --git a/rust-version b/rust-version index bfbf6b81b2..d0c938c53f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4825e12fc9c79954aa0fe18f5521efa6c19c7539 +0e11fc8053d32c44e7152865852acc5c3c54efb3 diff --git a/src/eval.rs b/src/eval.rs index 79ceb6be80..24cf0cbf06 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -5,6 +5,7 @@ use std::ffi::OsStr; use rand::rngs::StdRng; use rand::SeedableRng; +use log::info; use rustc_hir::def_id::DefId; use rustc_middle::ty::{self, layout::LayoutCx, TyCtxt}; @@ -195,8 +196,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( /// Returns `Some(return_code)` if program executed completed. /// Returns `None` if an evaluation error occured. pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option { - // FIXME: on Windows, we ignore leaks (https://github.com/rust-lang/miri/issues/1302). - let ignore_leaks = config.ignore_leaks || tcx.sess.target.target.target_os == "windows"; + // Copy setting before we move `config`. + let ignore_leaks = config.ignore_leaks; let (mut ecx, ret_place) = match create_ecx(tcx, main_id, config) { Ok(v) => v, @@ -244,7 +245,8 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> match res { Ok(return_code) => { if !ignore_leaks { - let leaks = ecx.memory.leak_report(); + info!("Additonal static roots: {:?}", ecx.machine.static_roots); + let leaks = ecx.memory.leak_report(&ecx.machine.static_roots); if leaks != 0 { tcx.sess.err("the evaluated program leaked memory"); // Ignore the provided return code - let the reported error diff --git a/src/machine.rs b/src/machine.rs index 49d647838c..e9217896ef 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -262,6 +262,9 @@ pub struct Evaluator<'mir, 'tcx> { /// Precomputed `TyLayout`s for primitive data types that are commonly used inside Miri. pub(crate) layouts: PrimitiveLayouts<'tcx>, + + /// Allocations that are considered roots of static memory (that may leak). + pub(crate) static_roots: Vec, } impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { @@ -289,6 +292,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { time_anchor: Instant::now(), layouts, threads: ThreadManager::default(), + static_roots: Vec::new(), } } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index a7495beef7..7323a664bd 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -111,7 +111,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx def_id: DefId, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, - _unwind: Option, + unwind: Option, ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { let this = self.eval_context_mut(); let attrs = this.tcx.get_attrs(def_id); @@ -126,6 +126,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // First: functions that diverge. let (dest, ret) = match ret { None => match link_name { + "miri_start_panic" => { + this.handle_miri_start_panic(args, unwind)?; + return Ok(None); + } // This matches calls to the foreign item `panic_impl`. // The implementation is provided by the function with the `#[panic_handler]` attribute. "panic_impl" => { @@ -193,6 +197,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Here we dispatch all the shims for foreign functions. If you have a platform specific // shim, add it to the corresponding submodule. match link_name { + // Miri-specific extern functions + "miri_static_root" => { + let &[ptr] = check_arg_count(args)?; + let ptr = this.read_scalar(ptr)?.not_undef()?; + let ptr = this.force_ptr(ptr)?; + if ptr.offset != Size::ZERO { + throw_unsup_format!("pointer passed to miri_static_root must point to beginning of an allocated block"); + } + this.machine.static_roots.push(ptr.alloc_id); + } + // Standard C allocation "malloc" => { let &[size] = check_arg_count(args)?; diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index c44caed34f..f542bebd82 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -18,7 +18,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, - unwind: Option, + _unwind: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let intrinsic_name = this.tcx.item_name(instance.def_id()); @@ -32,13 +32,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(()); } - // First handle intrinsics without return place. + // All supported intrinsics have a return place. let intrinsic_name = &*intrinsic_name.as_str(); let (dest, ret) = match ret { - None => match intrinsic_name { - "miri_start_panic" => return this.handle_miri_start_panic(args, unwind), - _ => throw_unsup_format!("unimplemented (diverging) intrinsic: {}", intrinsic_name), - }, + None => throw_unsup_format!("unimplemented (diverging) intrinsic: {}", intrinsic_name), Some(p) => p, }; diff --git a/tests/compile-fail/memleak.rs b/tests/compile-fail/memleak.rs index c3b27abcdb..71b4e2f442 100644 --- a/tests/compile-fail/memleak.rs +++ b/tests/compile-fail/memleak.rs @@ -1,5 +1,3 @@ -// ignore-windows: We do not check leaks on Windows - //error-pattern: the evaluated program leaked memory fn main() { diff --git a/tests/compile-fail/memleak_rc.rs b/tests/compile-fail/memleak_rc.rs index 446d28681b..b2bc6722af 100644 --- a/tests/compile-fail/memleak_rc.rs +++ b/tests/compile-fail/memleak_rc.rs @@ -1,5 +1,3 @@ -// ignore-windows: We do not check leaks on Windows - //error-pattern: the evaluated program leaked memory use std::rc::Rc;