diff --git a/README.md b/README.md index 76f95ee55e8..a86de4a5551 100644 --- a/README.md +++ b/README.md @@ -192,7 +192,8 @@ Miri adds its own set of `-Z` flags: for cryptographic use! Do not generate secret keys in Miri or perform other kinds of cryptographic operations that rely on proper random numbers. * `-Zmiri-track-alloc-id=<id>` shows a backtrace when the given allocation is - being allocated. This helps in debugging memory leaks. + being allocated or freed. This helps in debugging memory leaks and + use after free bugs. * `-Zmiri-track-pointer-tag=<tag>` shows a backtrace when the given pointer tag is popped from a borrow stack (which is where the tag becomes invalid and any future use of it will error). This helps you in finding out why UB is diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 2359b67323d..8c7bb8a47c6 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -42,6 +42,7 @@ impl MachineStopType for TerminationInfo {} pub enum NonHaltingDiagnostic { PoppedTrackedPointerTag(Item), CreatedAlloc(AllocId), + FreedAlloc(AllocId), } /// Emit a custom diagnostic without going through the miri-engine machinery @@ -191,6 +192,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx format!("popped tracked tag for item {:?}", item), CreatedAlloc(AllocId(id)) => format!("created allocation with id {}", id), + FreedAlloc(AllocId(id)) => + format!("freed allocation with id {}", id), }; report_msg(this, "tracking was triggered", msg, vec![], false); } diff --git a/src/machine.rs b/src/machine.rs index 94603c3dfb4..5cf42df8268 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -116,7 +116,7 @@ pub struct MemoryExtra { pub(crate) rng: RefCell<StdRng>, /// An allocation ID to report when it is being allocated - /// (helps for debugging memory leaks). + /// (helps for debugging memory leaks and use after free bugs). tracked_alloc_id: Option<AllocId>, /// Controls whether alignment of memory accesses is being checked. @@ -466,6 +466,18 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { (Cow::Owned(alloc), base_tag) } + #[inline(always)] + fn before_deallocation( + memory_extra: &mut Self::MemoryExtra, + id: AllocId, + ) -> InterpResult<'tcx> { + if Some(id) == memory_extra.tracked_alloc_id { + register_diagnostic(NonHaltingDiagnostic::FreedAlloc(id)); + } + + Ok(()) + } + #[inline(always)] fn tag_global_base_pointer(memory_extra: &MemoryExtra, id: AllocId) -> Self::PointerTag { if let Some(stacked_borrows) = &memory_extra.stacked_borrows {