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")]
|
#[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "41079")]
|
||||||
pub fn ptr_offset_from<T>(ptr: *const T, base: *const T) -> isize;
|
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"
|
/// Internal placeholder for injecting code coverage counters when the "instrument-coverage"
|
||||||
/// option is enabled. The placeholder is replaced with `llvm.instrprof.increment` during code
|
/// option is enabled. The placeholder is replaced with `llvm.instrprof.increment` during code
|
||||||
/// generation.
|
/// generation.
|
||||||
|
|
|
@ -6,11 +6,16 @@ use core::any::Any;
|
||||||
// Must be pointer-sized.
|
// Must be pointer-sized.
|
||||||
type Payload = Box<Box<dyn Any + Send>>;
|
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 {
|
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
|
// 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.
|
// in `cleanup` below. So we just box it up once, to get something pointer-sized.
|
||||||
let payload_box: Payload = Box::new(payload);
|
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> {
|
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;
|
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(
|
if self.codegen_panic_intrinsic(
|
||||||
&helper,
|
&helper,
|
||||||
&mut bx,
|
&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.
|
// Collect the set of allocations that are *reachable* from `Global` allocations.
|
||||||
let reachable = {
|
let reachable = {
|
||||||
let mut reachable = FxHashSet::default();
|
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, _)| {
|
let mut todo: Vec<_> = self.alloc_map.filter_map_collect(move |&id, &(kind, _)| {
|
||||||
if Some(kind) == global_kind { Some(id) } else { None }
|
if Some(kind) == global_kind { Some(id) } else { None }
|
||||||
});
|
});
|
||||||
|
todo.extend(static_roots);
|
||||||
while let Some(id) = todo.pop() {
|
while let Some(id) = todo.pop() {
|
||||||
if reachable.insert(id) {
|
if reachable.insert(id) {
|
||||||
// This is a new allocation, add its relocations to `todo`.
|
// This is a new allocation, add its relocations to `todo`.
|
||||||
|
|
|
@ -677,7 +677,6 @@ symbols! {
|
||||||
minnumf32,
|
minnumf32,
|
||||||
minnumf64,
|
minnumf64,
|
||||||
mips_target_feature,
|
mips_target_feature,
|
||||||
miri_start_panic,
|
|
||||||
mmx_target_feature,
|
mmx_target_feature,
|
||||||
module,
|
module,
|
||||||
module_path,
|
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::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 => {
|
sym::count_code_region => {
|
||||||
(0, vec![tcx.types.u64, tcx.types.u32, tcx.types.u32, tcx.types.u32], tcx.mk_unit())
|
(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,
|
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) {
|
unsafe fn register_dtor(key: Key, dtor: Dtor) {
|
||||||
let mut node = Box::new(Node { key, dtor, next: ptr::null_mut() });
|
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 {
|
loop {
|
||||||
node.next = head;
|
node.next = head;
|
||||||
match DTORS.compare_exchange(head, &mut *node, SeqCst, SeqCst) {
|
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,
|
Err(cur) => head = cur,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue