Skip to content

Commit

Permalink
Rollup merge of rust-lang#74681 - RalfJung:miri-extern-fn, r=oli-obk
Browse files Browse the repository at this point in the history
 Miri: use extern fn to expose interpreter operations to program; fix leak checker on Windows

This PR realizes an idea that @oli-obk has been suggesting for a while: to use Miri-specific `extern` functions to provide some extra capabilities to the program. Initially, we have two of these methods, which libstd itself needs:
* `miri_start_panic`, which replaces the intrinsic of the same name (mostly for consistency, to avoid having multiple mechanisms for Miri-specific functionality).
* `miri_static_root`, which adds an allocation to a list of static "roots" that Miri considers as not having leaked (including all memory reachable through them). This is needed for rust-lang/miri#1302.

We use `extern` functions instead of intrinsics for this so that user code can more easily call these Miri hoolks -- e.g. `miri_static_root` should be useful for rust-lang/miri#1318.

The Miri side of this is at rust-lang/miri#1485.

r? @oli-obk
  • Loading branch information
Dylan-DPC committed Jul 24, 2020
2 parents 4ce6ee5 + 67b4f3b commit bd22cc5
Show file tree
Hide file tree
Showing 7 changed files with 27 additions and 23 deletions.
8 changes: 0 additions & 8 deletions src/libcore/intrinsics.rs
Expand Up @@ -1947,14 +1947,6 @@ extern "rust-intrinsic" {
#[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "41079")]
pub fn ptr_offset_from<T>(ptr: *const T, base: *const T) -> isize;

/// Internal hook used by Miri to implement unwinding.
/// ICEs when encountered during non-Miri codegen.
///
/// The `payload` ptr here will be exactly the one `do_catch` gets passed by `try`.
///
/// Perma-unstable: do not use.
pub fn miri_start_panic(payload: *mut u8) -> !;

/// Internal placeholder for injecting code coverage counters when the "instrument-coverage"
/// option is enabled. The placeholder is replaced with `llvm.instrprof.increment` during code
/// generation.
Expand Down
7 changes: 6 additions & 1 deletion src/libpanic_unwind/miri.rs
Expand Up @@ -6,11 +6,16 @@ use core::any::Any;
// Must be pointer-sized.
type Payload = Box<Box<dyn Any + Send>>;

extern "Rust" {
/// Miri-provided extern function to begin unwinding.
fn miri_start_panic(payload: *mut u8) -> !;
}

pub unsafe fn panic(payload: Box<dyn Any + Send>) -> u32 {
// The payload we pass to `miri_start_panic` will be exactly the argument we get
// in `cleanup` below. So we just box it up once, to get something pointer-sized.
let payload_box: Payload = Box::new(payload);
core::intrinsics::miri_start_panic(Box::into_raw(payload_box) as *mut u8)
miri_start_panic(Box::into_raw(payload_box) as *mut u8)
}

pub unsafe fn cleanup(payload_box: *mut u8) -> Box<dyn Any + Send> {
Expand Down
5 changes: 0 additions & 5 deletions src/librustc_codegen_ssa/mir/block.rs
Expand Up @@ -606,11 +606,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
return;
}

// For normal codegen, this Miri-specific intrinsic should never occur.
if intrinsic == Some(sym::miri_start_panic) {
bug!("`miri_start_panic` should never end up in compiled code");
}

if self.codegen_panic_intrinsic(
&helper,
&mut bx,
Expand Down
5 changes: 4 additions & 1 deletion src/librustc_mir/interpret/memory.rs
Expand Up @@ -716,14 +716,17 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
}
}

pub fn leak_report(&self) -> usize {
/// Print leaked memory. Allocations reachable from `static_roots` or a `Global` allocation
/// are not considered leaked. Leaks whose kind `may_leak()` returns true are not reported.
pub fn leak_report(&self, static_roots: &[AllocId]) -> usize {
// Collect the set of allocations that are *reachable* from `Global` allocations.
let reachable = {
let mut reachable = FxHashSet::default();
let global_kind = M::GLOBAL_KIND.map(MemoryKind::Machine);
let mut todo: Vec<_> = self.alloc_map.filter_map_collect(move |&id, &(kind, _)| {
if Some(kind) == global_kind { Some(id) } else { None }
});
todo.extend(static_roots);
while let Some(id) = todo.pop() {
if reachable.insert(id) {
// This is a new allocation, add its relocations to `todo`.
Expand Down
1 change: 0 additions & 1 deletion src/librustc_span/symbol.rs
Expand Up @@ -677,7 +677,6 @@ symbols! {
minnumf32,
minnumf64,
mips_target_feature,
miri_start_panic,
mmx_target_feature,
module,
module_path,
Expand Down
6 changes: 0 additions & 6 deletions src/librustc_typeck/check/intrinsic.rs
Expand Up @@ -379,12 +379,6 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {

sym::nontemporal_store => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()),

sym::miri_start_panic => {
// FIXME - the relevant types aren't lang items,
// so it's not trivial to check this
return;
}

sym::count_code_region => {
(0, vec![tcx.types.u64, tcx.types.u32, tcx.types.u32, tcx.types.u32], tcx.mk_unit())
}
Expand Down
18 changes: 17 additions & 1 deletion src/libstd/sys/windows/thread_local_key.rs
Expand Up @@ -110,14 +110,30 @@ struct Node {
next: *mut Node,
}

#[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);
}

unsafe fn register_dtor(key: Key, dtor: Dtor) {
let mut node = Box::new(Node { key, dtor, next: ptr::null_mut() });

let mut head = DTORS.load(SeqCst);
loop {
node.next = head;
match DTORS.compare_exchange(head, &mut *node, SeqCst, SeqCst) {
Ok(_) => return mem::forget(node),
Ok(_) => {
#[cfg(miri)]
miri_static_root(&*node as *const _ as *const u8);

mem::forget(node);
return;
}
Err(cur) => head = cur,
}
}
Expand Down

0 comments on commit bd22cc5

Please sign in to comment.