properly track why we checked whether a pointer is in-bounds
also simplify the in-bounds checking in Miri's borrow trackers
This commit is contained in:
parent
7d5886504c
commit
8496292dda
44 changed files with 130 additions and 122 deletions
|
@ -282,7 +282,7 @@ const_eval_pointer_out_of_bounds =
|
|||
*[many] bytes
|
||||
} starting at offset {$ptr_offset} is out-of-bounds
|
||||
const_eval_pointer_use_after_free =
|
||||
pointer to {$allocation} was dereferenced after this allocation got freed
|
||||
{$bad_pointer_message}: {$alloc_id} has been freed, so this pointer is dangling
|
||||
const_eval_ptr_as_bytes_1 =
|
||||
this code performed an operation that depends on the underlying bytes representing a pointer
|
||||
const_eval_ptr_as_bytes_2 =
|
||||
|
|
|
@ -492,7 +492,7 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
|
|||
InvalidMeta(InvalidMetaKind::SliceTooBig) => const_eval_invalid_meta_slice,
|
||||
InvalidMeta(InvalidMetaKind::TooBig) => const_eval_invalid_meta,
|
||||
UnterminatedCString(_) => const_eval_unterminated_c_string,
|
||||
PointerUseAfterFree(_) => const_eval_pointer_use_after_free,
|
||||
PointerUseAfterFree(_, _) => const_eval_pointer_use_after_free,
|
||||
PointerOutOfBounds { ptr_size: Size::ZERO, .. } => const_eval_zst_pointer_out_of_bounds,
|
||||
PointerOutOfBounds { .. } => const_eval_pointer_out_of_bounds,
|
||||
DanglingIntPointer(0, _) => const_eval_dangling_null_pointer,
|
||||
|
@ -545,8 +545,10 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
|
|||
UnterminatedCString(ptr) | InvalidFunctionPointer(ptr) | InvalidVTablePointer(ptr) => {
|
||||
builder.set_arg("pointer", ptr);
|
||||
}
|
||||
PointerUseAfterFree(allocation) => {
|
||||
builder.set_arg("allocation", allocation);
|
||||
PointerUseAfterFree(alloc_id, msg) => {
|
||||
builder
|
||||
.set_arg("alloc_id", alloc_id)
|
||||
.set_arg("bad_pointer_message", bad_pointer_message(msg, handler));
|
||||
}
|
||||
PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, ptr_size, msg } => {
|
||||
builder
|
||||
|
|
|
@ -317,7 +317,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
kind = "static_mem"
|
||||
)
|
||||
}
|
||||
None => err_ub!(PointerUseAfterFree(alloc_id)),
|
||||
None => err_ub!(PointerUseAfterFree(alloc_id, CheckInAllocMsg::MemoryAccessTest)),
|
||||
}
|
||||
.into());
|
||||
};
|
||||
|
@ -380,7 +380,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
M::enforce_alignment(self),
|
||||
CheckInAllocMsg::MemoryAccessTest,
|
||||
|alloc_id, offset, prov| {
|
||||
let (size, align) = self.get_live_alloc_size_and_align(alloc_id)?;
|
||||
let (size, align) = self
|
||||
.get_live_alloc_size_and_align(alloc_id, CheckInAllocMsg::MemoryAccessTest)?;
|
||||
Ok((size, align, (alloc_id, offset, prov)))
|
||||
},
|
||||
)
|
||||
|
@ -404,7 +405,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
CheckAlignment::Error,
|
||||
msg,
|
||||
|alloc_id, _, _| {
|
||||
let (size, align) = self.get_live_alloc_size_and_align(alloc_id)?;
|
||||
let (size, align) = self.get_live_alloc_size_and_align(alloc_id, msg)?;
|
||||
Ok((size, align, ()))
|
||||
},
|
||||
)?;
|
||||
|
@ -414,7 +415,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
/// Low-level helper function to check if a ptr is in-bounds and potentially return a reference
|
||||
/// to the allocation it points to. Supports both shared and mutable references, as the actual
|
||||
/// checking is offloaded to a helper closure. `align` defines whether and which alignment check
|
||||
/// is done. Returns `None` for size 0, and otherwise `Some` of what `alloc_size` returned.
|
||||
/// is done.
|
||||
///
|
||||
/// If this returns `None`, the size is 0; it can however return `Some` even for size 0.
|
||||
fn check_and_deref_ptr<T>(
|
||||
&self,
|
||||
ptr: Pointer<Option<M::Provenance>>,
|
||||
|
@ -515,7 +518,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
}
|
||||
Some(GlobalAlloc::Function(..)) => throw_ub!(DerefFunctionPointer(id)),
|
||||
Some(GlobalAlloc::VTable(..)) => throw_ub!(DerefVTablePointer(id)),
|
||||
None => throw_ub!(PointerUseAfterFree(id)),
|
||||
None => throw_ub!(PointerUseAfterFree(id, CheckInAllocMsg::MemoryAccessTest)),
|
||||
Some(GlobalAlloc::Static(def_id)) => {
|
||||
assert!(self.tcx.is_static(def_id));
|
||||
assert!(!self.tcx.is_thread_local_static(def_id));
|
||||
|
@ -761,11 +764,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Obtain the size and alignment of a live allocation.
|
||||
pub fn get_live_alloc_size_and_align(&self, id: AllocId) -> InterpResult<'tcx, (Size, Align)> {
|
||||
/// Obtain the size and alignment of a *live* allocation.
|
||||
fn get_live_alloc_size_and_align(
|
||||
&self,
|
||||
id: AllocId,
|
||||
msg: CheckInAllocMsg,
|
||||
) -> InterpResult<'tcx, (Size, Align)> {
|
||||
let (size, align, kind) = self.get_alloc_info(id);
|
||||
if matches!(kind, AllocKind::Dead) {
|
||||
throw_ub!(PointerUseAfterFree(id))
|
||||
throw_ub!(PointerUseAfterFree(id, msg))
|
||||
}
|
||||
Ok((size, align))
|
||||
}
|
||||
|
|
|
@ -224,8 +224,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
|
||||
Len(place) => {
|
||||
let src = self.eval_place(place)?;
|
||||
let op = self.place_to_op(&src)?;
|
||||
let len = op.len(self)?;
|
||||
let len = src.len(self)?;
|
||||
self.write_scalar(Scalar::from_target_usize(len, self), &dest)?;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue