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
This commit is contained in:
commit
5ef299eb98
7 changed files with 27 additions and 23 deletions
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue