X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Ftools%2Fmiri%2Fsrc%2Fmachine.rs;h=4d3444bc39cdd97a839f0f9fcf6eb727a8dd4352;hb=0849084d0664d1e50b7b4b086f6d221a054f5b46;hp=231a99c1d034ed0ef9316dc82271b3c471b1a607;hpb=c9fc5cbeb5b682eb207cb190670027c497ea47a1;p=rust.git diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 231a99c1d03..4d3444bc39c 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -50,12 +50,18 @@ pub struct FrameData<'tcx> { /// for the start of this frame. When we finish executing this frame, /// we use this to register a completed event with `measureme`. pub timing: Option, + + /// Indicates whether a `Frame` is part of a workspace-local crate and is also not + /// `#[track_caller]`. We compute this once on creation and store the result, as an + /// optimization. + /// This is used by `MiriMachine::current_span` and `MiriMachine::caller_span` + pub is_user_relevant: bool, } impl<'tcx> std::fmt::Debug for FrameData<'tcx> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { // Omitting `timing`, it does not support `Debug`. - let FrameData { stacked_borrows, catch_unwind, timing: _ } = self; + let FrameData { stacked_borrows, catch_unwind, timing: _, is_user_relevant: _ } = self; f.debug_struct("FrameData") .field("stacked_borrows", stacked_borrows) .field("catch_unwind", catch_unwind) @@ -65,7 +71,7 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { impl VisitTags for FrameData<'_> { fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) { - let FrameData { catch_unwind, stacked_borrows, timing: _ } = self; + let FrameData { catch_unwind, stacked_borrows, timing: _, is_user_relevant: _ } = self; catch_unwind.visit_tags(visit); stacked_borrows.visit_tags(visit); @@ -77,6 +83,8 @@ fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) { pub enum MiriMemoryKind { /// `__rust_alloc` memory. Rust, + /// `miri_alloc` memory. + Miri, /// `malloc` memory. C, /// Windows `HeapAlloc` memory. @@ -110,7 +118,7 @@ impl MayLeak for MiriMemoryKind { fn may_leak(self) -> bool { use self::MiriMemoryKind::*; match self { - Rust | C | WinHeap | Runtime => false, + Rust | Miri | C | WinHeap | Runtime => false, Machine | Global | ExternStatic | Tls => true, } } @@ -121,6 +129,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use self::MiriMemoryKind::*; match self { Rust => write!(f, "Rust heap"), + Miri => write!(f, "Miri bare-metal heap"), C => write!(f, "C heap"), WinHeap => write!(f, "Windows heap"), Machine => write!(f, "machine-managed memory"), @@ -133,7 +142,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } /// Pointer provenance. -#[derive(Debug, Clone, Copy)] +#[derive(Clone, Copy)] pub enum Provenance { Concrete { alloc_id: AllocId, @@ -176,18 +185,9 @@ pub enum ProvenanceExtra { #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] static_assert_size!(Scalar, 32); -impl interpret::Provenance for Provenance { - /// We use absolute addresses in the `offset` of a `Pointer`. - const OFFSET_IS_ADDR: bool = true; - - /// We cannot err on partial overwrites, it happens too often in practice (due to unions). - const ERR_ON_PARTIAL_PTR_OVERWRITE: bool = false; - - fn fmt(ptr: &Pointer, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let (prov, addr) = ptr.into_parts(); // address is absolute - write!(f, "{:#x}", addr.bytes())?; - - match prov { +impl fmt::Debug for Provenance { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { Provenance::Concrete { alloc_id, sb } => { // Forward `alternate` flag to `alloc_id` printing. if f.alternate() { @@ -202,9 +202,13 @@ fn fmt(ptr: &Pointer, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "[wildcard]")?; } } - Ok(()) } +} + +impl interpret::Provenance for Provenance { + /// We use absolute addresses in the `offset` of a `Pointer`. + const OFFSET_IS_ADDR: bool = true; fn get_alloc_id(self) -> Option { match self { @@ -359,6 +363,9 @@ pub struct MiriMachine<'mir, 'tcx> { /// Miri does not expose env vars from the host to the emulated program. pub(crate) env_vars: EnvVars<'tcx>, + /// Return place of the main function. + pub(crate) main_fn_ret_place: Option>, + /// Program arguments (`Option` because we can only initialize them after creating the ecx). /// These are *pointers* to argc/argv because macOS. /// We also need the full command line as one string because of Windows. @@ -488,6 +495,7 @@ pub(crate) fn new(config: &MiriConfig, layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) intptrcast: RefCell::new(intptrcast::GlobalStateInner::new(config)), // `env_vars` depends on a full interpreter so we cannot properly initialize it yet. env_vars: EnvVars::default(), + main_fn_ret_place: None, argc: None, argv: None, cmd_line: None, @@ -552,10 +560,11 @@ pub(crate) fn new(config: &MiriConfig, layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) pub(crate) fn late_init( this: &mut MiriInterpCx<'mir, 'tcx>, config: &MiriConfig, + on_main_stack_empty: StackEmptyCallback<'mir, 'tcx>, ) -> InterpResult<'tcx> { EnvVars::init(this, config)?; MiriMachine::init_extern_statics(this)?; - ThreadManager::init(this); + ThreadManager::init(this, on_main_stack_empty); Ok(()) } @@ -653,6 +662,7 @@ fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) { threads, tls, env_vars, + main_fn_ret_place, argc, argv, cmd_line, @@ -698,6 +708,7 @@ fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) { data_race.visit_tags(visit); stacked_borrows.visit_tags(visit); intptrcast.visit_tags(visit); + main_fn_ret_place.visit_tags(visit); argc.visit_tags(visit); argv.visit_tags(visit); cmd_line.visit_tags(visit); @@ -897,12 +908,12 @@ fn adjust_allocation<'b>( let alloc = alloc.into_owned(); let stacks = ecx.machine.stacked_borrows.as_ref().map(|stacked_borrows| { - Stacks::new_allocation( + stacked_borrows::Stacks::new_allocation( id, alloc.size(), stacked_borrows, kind, - ecx.machine.current_span(), + &ecx.machine, ) }); let race_alloc = ecx.machine.data_race.as_ref().map(|data_race| { @@ -1005,22 +1016,12 @@ fn before_memory_read( range: AllocRange, ) -> InterpResult<'tcx> { if let Some(data_race) = &alloc_extra.data_race { - data_race.read( - alloc_id, - range, - machine.data_race.as_ref().unwrap(), - &machine.threads, - )?; + data_race.read(alloc_id, range, machine)?; } if let Some(stacked_borrows) = &alloc_extra.stacked_borrows { - stacked_borrows.borrow_mut().before_memory_read( - alloc_id, - prov_extra, - range, - machine.stacked_borrows.as_ref().unwrap(), - machine.current_span(), - &machine.threads, - )?; + stacked_borrows + .borrow_mut() + .before_memory_read(alloc_id, prov_extra, range, machine)?; } if let Some(weak_memory) = &alloc_extra.weak_memory { weak_memory.memory_accessed(range, machine.data_race.as_ref().unwrap()); @@ -1037,22 +1038,10 @@ fn before_memory_write( range: AllocRange, ) -> InterpResult<'tcx> { if let Some(data_race) = &mut alloc_extra.data_race { - data_race.write( - alloc_id, - range, - machine.data_race.as_mut().unwrap(), - &machine.threads, - )?; + data_race.write(alloc_id, range, machine)?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { - stacked_borrows.get_mut().before_memory_write( - alloc_id, - prov_extra, - range, - machine.stacked_borrows.as_ref().unwrap(), - machine.current_span(), - &machine.threads, - )?; + stacked_borrows.get_mut().before_memory_write(alloc_id, prov_extra, range, machine)?; } if let Some(weak_memory) = &alloc_extra.weak_memory { weak_memory.memory_accessed(range, machine.data_race.as_ref().unwrap()); @@ -1072,21 +1061,14 @@ fn before_memory_deallocation( machine.emit_diagnostic(NonHaltingDiagnostic::FreedAlloc(alloc_id)); } if let Some(data_race) = &mut alloc_extra.data_race { - data_race.deallocate( - alloc_id, - range, - machine.data_race.as_mut().unwrap(), - &machine.threads, - )?; + data_race.deallocate(alloc_id, range, machine)?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { stacked_borrows.get_mut().before_memory_deallocation( alloc_id, prove_extra, range, - machine.stacked_borrows.as_ref().unwrap(), - machine.current_span(), - &machine.threads, + machine, ) } else { Ok(()) @@ -1128,7 +1110,9 @@ fn init_frame_extra( stacked_borrows: stacked_borrows.map(|sb| sb.borrow_mut().new_frame(&ecx.machine)), catch_unwind: None, timing, + is_user_relevant: ecx.machine.is_user_relevant(&frame), }; + Ok(frame.with_extra(extra)) } @@ -1176,6 +1160,13 @@ fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> #[inline(always)] fn after_stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { + if ecx.frame().extra.is_user_relevant { + // We just pushed a local frame, so we know that the topmost local frame is the topmost + // frame. If we push a non-local frame, there's no need to do anything. + let stack_len = ecx.active_thread_stack().len(); + ecx.active_thread_mut().set_top_user_relevant_frame(stack_len - 1); + } + if ecx.machine.stacked_borrows.is_some() { ecx.retag_return_place() } else { Ok(()) } } @@ -1185,6 +1176,13 @@ fn after_stack_pop( mut frame: Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>, unwinding: bool, ) -> InterpResult<'tcx, StackPopJump> { + if frame.extra.is_user_relevant { + // All that we store is whether or not the frame we just removed is local, so now we + // have no idea where the next topmost local frame is. So we recompute it. + // (If this ever becomes a bottleneck, we could have `push` store the previous + // user-relevant frame and restore that here.) + ecx.active_thread_mut().recompute_top_user_relevant_frame(); + } let timing = frame.extra.timing.take(); if let Some(stacked_borrows) = &ecx.machine.stacked_borrows { stacked_borrows.borrow_mut().end_call(&frame.extra);