diff --git a/src/operator.rs b/src/operator.rs index e5c695009cfa..be05c2259957 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -142,8 +142,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // allocations sit right next to each other. The C/C++ standards are // somewhat fuzzy about this case, so I think for now this check is // "good enough". - self.memory().check_bounds_ptr(left, false)?; - self.memory().check_bounds_ptr(right, false)?; + // We require liveness, as dead allocations can of course overlap. + self.memory().check_bounds_ptr(left, InboundsCheck::Live)?; + self.memory().check_bounds_ptr(right, InboundsCheck::Live)?; // Two live in-bounds pointers, we can compare across allocations left == right } @@ -153,15 +154,17 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' (Scalar::Bits { bits, size }, Scalar::Ptr(ptr)) => { assert_eq!(size as u64, self.pointer_size().bytes()); let bits = bits as u64; - let (alloc_size, alloc_align) = self.memory().get_size_and_align(ptr.alloc_id); // Case I: Comparing with NULL if bits == 0 { // Test if the ptr is in-bounds. Then it cannot be NULL. - if ptr.offset <= alloc_size { + if self.memory().check_bounds_ptr(ptr, InboundsCheck::MaybeDead).is_ok() { return Ok(false); } } + + let (alloc_size, alloc_align) = self.memory().get_size_and_align(ptr.alloc_id); + // Case II: Alignment gives it away if ptr.offset.bytes() % alloc_align.abi() == 0 { // The offset maintains the allocation alignment, so we know `base+offset` @@ -293,11 +296,11 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let offset = offset.checked_mul(pointee_size).ok_or_else(|| EvalErrorKind::Overflow(mir::BinOp::Mul))?; // Now let's see what kind of pointer this is if let Scalar::Ptr(ptr) = ptr { - // Both old and new pointer must be in-bounds. + // Both old and new pointer must be in-bounds of a *live* allocation. // (Of the same allocation, but that part is trivial with our representation.) - self.memory().check_bounds_ptr(ptr, false)?; + self.memory().check_bounds_ptr(ptr, InboundsCheck::Live)?; let ptr = ptr.signed_offset(offset, self)?; - self.memory().check_bounds_ptr(ptr, false)?; + self.memory().check_bounds_ptr(ptr, InboundsCheck::Live)?; Ok(Scalar::Ptr(ptr)) } else { // An integer pointer. They can only be offset by 0, and we pretend there diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 0da130260df2..063a544baa65 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -5,7 +5,7 @@ use rustc::hir::{Mutability, MutMutable, MutImmutable}; use crate::{ EvalResult, EvalErrorKind, MiriEvalContext, HelpersEvalContextExt, Evaluator, MutValueVisitor, - MemoryKind, MiriMemoryKind, RangeMap, AllocId, Allocation, AllocationExtra, + MemoryKind, MiriMemoryKind, RangeMap, AllocId, Allocation, AllocationExtra, InboundsCheck, Pointer, MemPlace, Scalar, Immediate, ImmTy, PlaceTy, MPlaceTy, }; @@ -523,7 +523,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { } // Get the allocation - self.memory().check_bounds(ptr, size, false)?; + self.memory().check_bounds(ptr, size, InboundsCheck::Live)?; let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); // If we got here, we do some checking, *but* we leave the tag unchanged. if let Borrow::Shr(Some(_)) = ptr.tag { @@ -566,7 +566,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { ptr, place.layout.ty, new_bor); // Get the allocation. It might not be mutable, so we cannot use `get_mut`. - self.memory().check_bounds(ptr, size, false)?; + self.memory().check_bounds(ptr, size, InboundsCheck::Live)?; let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); // Update the stacks. if let Borrow::Shr(Some(_)) = new_bor { diff --git a/tests/compile-fail-fullmir/out_of_bounds_ptr_1.rs b/tests/compile-fail-fullmir/out_of_bounds_ptr_1.rs index 8dce7e578626..ce1c89a2a008 100644 --- a/tests/compile-fail-fullmir/out_of_bounds_ptr_1.rs +++ b/tests/compile-fail-fullmir/out_of_bounds_ptr_1.rs @@ -1,4 +1,4 @@ -// error-pattern: pointer computed at offset 5, outside bounds of allocation +// error-pattern: must be in-bounds and live at offset 5, but is outside bounds of allocation fn main() { let v = [0i8; 4]; let x = &v as *const i8;