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 {