Commit 5ef299eb authored by bors's avatar bors

Auto merge of #74681 - RalfJung:miri-extern-fn, r=oli-obk

 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 https://github.com/rust-lang/miri/issues/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 https://github.com/rust-lang/miri/issues/1318.

The Miri side of this is at https://github.com/rust-lang/miri/pull/1485.

r? @oli-obk
parents d8cf7495 67b4f3b1
......@@ -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.
......
......@@ -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> {
......
......@@ -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,
......
......@@ -716,7 +716,9 @@ 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();
......@@ -724,6 +726,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
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`.
......
......@@ -677,7 +677,6 @@ symbols! {
minnumf32,
minnumf64,
mips_target_feature,
miri_start_panic,
mmx_target_feature,
module,
module_path,
......
......@@ -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())
}
......
......@@ -110,6 +110,16 @@ 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() });
......@@ -117,7 +127,13 @@ unsafe fn register_dtor(key: Key, dtor: Dtor) {
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,
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment