diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 3fa001eabfd2..cc2ea0b76d87 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -1039,6 +1039,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let val = self.ecx.read_immediate(&place.into())?; let val = self.ecx.retag_reference(&val, mutbl, protector)?; self.ecx.write_immediate(*val, &place.into())?; + } else if matches!(place.layout.ty.kind(), ty::RawPtr(..)) { + // Wide raw pointers *do* have fields and their types are strange. + // vtables have a type like `&[*const (); 3]` or so! + // Do *not* recurse into them. + // (No need to worry about wide references or boxes, those always "qualify".) } else { // Maybe we need to go deeper. self.walk_value(place)?; diff --git a/tests/pass/stacked-borrows/stacked-borrows.rs b/tests/pass/stacked-borrows/stacked-borrows.rs index 3669a08a1bc4..b915a2ddf8f6 100644 --- a/tests/pass/stacked-borrows/stacked-borrows.rs +++ b/tests/pass/stacked-borrows/stacked-borrows.rs @@ -1,4 +1,5 @@ // compile-flags: -Zmiri-retag-fields +#![feature(allocator_api)] use std::ptr; // Test various stacked-borrows-related things. @@ -17,6 +18,7 @@ fn main() { raw_ref_to_part(); array_casts(); mut_below_shr(); + wide_raw_ptr_in_tuple(); } // Make sure that reading from an `&mut` does, like reborrowing to `&`, @@ -205,3 +207,15 @@ fn mut_below_shr() { let r = &**p; let _val = *r; } + +fn wide_raw_ptr_in_tuple() { + let mut x: Box = Box::new("ouch"); + let r = &mut *x as *mut dyn std::any::Any; + // This triggers the visitor-based recursive retagging. It is *not* supposed to retag raw + // pointers, but then the visitor might recurse into the "fields" of a wide raw pointer and + // finds a reference (to a vtable) there that it wants to retag... and that would be Wrong. + let pair = (r, &0); + let r = unsafe { &mut *pair.0 }; + // Make sure the fn ptr part of the vtable is still fine. + r.type_id(); +}