From 4033358956eaca6ccd7fe6d905b572c243673a62 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 23 Jul 2020 15:20:36 +0200 Subject: [PATCH 1/5] make miri_start_panic intrinsic an FFI function --- src/shims/foreign_items.rs | 6 +++++- src/shims/intrinsics.rs | 9 +++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index a7495beef7..cf85636b57 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" => { 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, }; From fef5fa2ae160118d7165a6394ff9d5447da17729 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 23 Jul 2020 15:47:33 +0200 Subject: [PATCH 2/5] add a Miri extern fn to mark an allocation as being a static root for leak checking --- src/eval.rs | 8 +++++--- src/machine.rs | 4 ++++ src/shims/foreign_items.rs | 11 +++++++++++ 3 files changed, 20 insertions(+), 3 deletions(-) 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 cf85636b57..f1b04afe0a 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -197,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)?; From bc0569253f6e8ab98232dd8020bd44b7262c91ec Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 23 Jul 2020 15:49:22 +0200 Subject: [PATCH 3/5] enable leak check tests on Windows --- src/shims/foreign_items.rs | 2 +- tests/compile-fail/memleak.rs | 2 -- tests/compile-fail/memleak_rc.rs | 2 -- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index f1b04afe0a..7323a664bd 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -203,7 +203,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx 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"); + 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); } 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; From 06f8bf6afa887a04ecdce0e5d8c7b4c66e2736d2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 23 Jul 2020 17:14:25 +0200 Subject: [PATCH 4/5] document Miri extern functions --- README.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) 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 From c641fbde0223cde9fae67de3cc4892998a21cec0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 25 Jul 2020 10:02:25 +0200 Subject: [PATCH 5/5] update rust-version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index bfbf6b81b2..d0c938c53f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4825e12fc9c79954aa0fe18f5521efa6c19c7539 +0e11fc8053d32c44e7152865852acc5c3c54efb3