From 5f680443579ae914c005cc40485a1c029cbe4cdc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 Mar 2026 18:37:52 +0100 Subject: [PATCH] miri recursive checking: only check one layer deep --- .../rustc_const_eval/src/interpret/validity.rs | 14 +++++++++++--- src/tools/miri/README.md | 5 +++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 62ee653000dca..9310cda8450b6 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -1512,6 +1512,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, } impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { + /// The internal core entry point for all validation operations. fn validate_operand_internal( &mut self, val: &PlaceTy<'tcx, M::Provenance>, @@ -1519,6 +1520,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ref_tracking: Option<&mut RefTracking, Vec>>, ctfe_mode: Option, reset_provenance_and_padding: bool, + start_in_may_dangle: bool, ) -> InterpResult<'tcx> { trace!("validate_operand_internal: {:?}, {:?}", *val, val.layout.ty); @@ -1536,7 +1538,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ecx, reset_provenance_and_padding, data_bytes: reset_padding.then_some(RangeSet(Vec::new())), - may_dangle: false, + may_dangle: start_in_may_dangle, }; v.visit_value(val)?; v.reset_padding(val)?; @@ -1579,6 +1581,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Some(ref_tracking), Some(ctfe_mode), /*reset_provenance*/ false, + /*start_in_may_dangle*/ false, ) } @@ -1610,6 +1613,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { None, None, reset_provenance_and_padding, + /*start_in_may_dangle*/ false, ); } // Do a recursive check. @@ -1620,15 +1624,19 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Some(&mut ref_tracking), None, reset_provenance_and_padding, + /*start_in_may_dangle*/ false, )?; while let Some((mplace, path)) = ref_tracking.todo.pop() { - // Things behind reference do *not* have the provenance reset. + // Things behind reference do *not* have the provenance reset. In fact + // we treat the entire thing as being inside MaybeDangling, i.e., references + // do not have to be dereferenceable. self.validate_operand_internal( &mplace.into(), path, - Some(&mut ref_tracking), + None, // no further recursion None, /*reset_provenance_and_padding*/ false, + /*start_in_may_dangle*/ true, )?; } interp_ok(()) diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index 97f385ad755bc..f51cd96486b4f 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -476,8 +476,9 @@ to Miri failing to detect cases of undefined behavior in a program. but reports to the program that it did actually write. This is useful when you are not interested in the actual program's output, but only want to see Miri's errors and warnings. -* `-Zmiri-recursive-validation` is a *highly experimental* flag that makes validity checking - recurse below references. +* `-Zmiri-recursive-validation` is a *highly experimental* flag that makes validity checking recurse + *one level* below references. The in-memory value is treated as-if it was inside a + `MaybeDangling`, i.e., nested references do not even have to be dereferenceable. * `-Zmiri-preemption-rate` configures the probability that at the end of a basic block, the active thread will be preempted. The default is `0.01` (i.e., 1%). Setting this to `0` disables preemption. Note that even without preemption, the schedule is still non-deterministic: