interpret: better error message for out-of-bounds pointer arithmetic and accesses

This commit is contained in:
Ralf Jung
2025-04-30 16:52:25 +02:00
parent 427288b3ce
commit 00f25a8e1c
81 changed files with 202 additions and 213 deletions

View File

@@ -349,7 +349,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// Check that the memory between them is dereferenceable at all, starting from the
// origin pointer: `dist` is `a - b`, so it is based on `b`.
self.check_ptr_access_signed(b, dist, CheckInAllocMsg::OffsetFromTest)
self.check_ptr_access_signed(b, dist, CheckInAllocMsg::Dereferenceable)
.map_err_kind(|_| {
// This could mean they point to different allocations, or they point to the same allocation
// but not the entire range between the pointers is in-bounds.
@@ -373,7 +373,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
self.check_ptr_access_signed(
a,
dist.checked_neg().unwrap(), // i64::MIN is impossible as no allocation can be that large
CheckInAllocMsg::OffsetFromTest,
CheckInAllocMsg::Dereferenceable,
)
.map_err_kind(|_| {
// Make the error more specific.
@@ -652,7 +652,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
offset_bytes: i64,
) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>> {
// The offset must be in bounds starting from `ptr`.
self.check_ptr_access_signed(ptr, offset_bytes, CheckInAllocMsg::PointerArithmeticTest)?;
self.check_ptr_access_signed(
ptr,
offset_bytes,
CheckInAllocMsg::InboundsPointerArithmetic,
)?;
// This also implies that there is no overflow, so we are done.
interp_ok(ptr.wrapping_signed_offset(offset_bytes, self))
}

View File

@@ -351,7 +351,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
kind = "static_mem"
)
}
None => err_ub!(PointerUseAfterFree(alloc_id, CheckInAllocMsg::MemoryAccessTest)),
None => err_ub!(PointerUseAfterFree(alloc_id, CheckInAllocMsg::MemoryAccess)),
})
.into();
};
@@ -414,10 +414,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
self,
ptr,
size,
CheckInAllocMsg::MemoryAccessTest,
CheckInAllocMsg::MemoryAccess,
|this, alloc_id, offset, prov| {
let (size, align) = this
.get_live_alloc_size_and_align(alloc_id, CheckInAllocMsg::MemoryAccessTest)?;
let (size, align) =
this.get_live_alloc_size_and_align(alloc_id, CheckInAllocMsg::MemoryAccess)?;
interp_ok((size, align, (alloc_id, offset, prov)))
},
)
@@ -613,7 +613,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
}
Some(GlobalAlloc::Function { .. }) => throw_ub!(DerefFunctionPointer(id)),
Some(GlobalAlloc::VTable(..)) => throw_ub!(DerefVTablePointer(id)),
None => throw_ub!(PointerUseAfterFree(id, CheckInAllocMsg::MemoryAccessTest)),
None => throw_ub!(PointerUseAfterFree(id, CheckInAllocMsg::MemoryAccess)),
Some(GlobalAlloc::Static(def_id)) => {
assert!(self.tcx.is_static(def_id));
// Thread-local statics do not have a constant address. They *must* be accessed via
@@ -707,7 +707,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
self,
ptr,
size_i64,
CheckInAllocMsg::MemoryAccessTest,
CheckInAllocMsg::MemoryAccess,
|this, alloc_id, offset, prov| {
let alloc = this.get_alloc_raw(alloc_id)?;
interp_ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc)))
@@ -809,7 +809,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
self,
ptr,
size_i64,
CheckInAllocMsg::MemoryAccessTest,
CheckInAllocMsg::MemoryAccess,
|this, alloc_id, offset, prov| {
let (alloc, machine) = this.get_alloc_raw_mut(alloc_id)?;
interp_ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc, machine)))
@@ -1615,7 +1615,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
err_ub!(DanglingIntPointer {
addr: offset,
inbounds_size: size,
msg: CheckInAllocMsg::InboundsTest
msg: CheckInAllocMsg::Dereferenceable
})
})
.into()

View File

@@ -510,7 +510,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
self.ecx.check_ptr_access(
place.ptr(),
size,
CheckInAllocMsg::InboundsTest, // will anyway be replaced by validity message
CheckInAllocMsg::Dereferenceable, // will anyway be replaced by validity message
),
self.path,
Ub(DanglingIntPointer { addr: 0, .. }) => NullPtr { ptr_kind },