1
Fork 0

more precise error for 'based on misaligned pointer' case

This commit is contained in:
Ralf Jung 2023-09-26 16:25:05 +02:00
parent cbf47a17d2
commit e24835c6e0
31 changed files with 112 additions and 91 deletions

View file

@ -390,15 +390,6 @@ pub struct LiveDrop<'tcx> {
pub dropped_at: Option<Span>,
}
#[derive(LintDiagnostic)]
#[diag(const_eval_align_check_failed)]
pub struct AlignmentCheckFailed {
pub has: u64,
pub required: u64,
#[subdiagnostic]
pub frames: Vec<FrameNote>,
}
#[derive(Diagnostic)]
#[diag(const_eval_error, code = "E0080")]
pub struct ConstEvalError {
@ -568,9 +559,10 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
builder.set_arg("bad_pointer_message", bad_pointer_message(msg, handler));
}
AlignmentCheckFailed(Misalignment { required, has }) => {
AlignmentCheckFailed(Misalignment { required, has }, msg) => {
builder.set_arg("required", required.bytes());
builder.set_arg("has", has.bytes());
builder.set_arg("msg", format!("{msg:?}"));
}
WriteToReadOnly(alloc) | DerefFunctionPointer(alloc) | DerefVTablePointer(alloc) => {
builder.set_arg("allocation", alloc);

View file

@ -21,8 +21,8 @@ use rustc_target::abi::{Align, HasDataLayout, Size};
use crate::fluent_generated as fluent;
use super::{
alloc_range, AllocBytes, AllocId, AllocMap, AllocRange, Allocation, CheckInAllocMsg,
GlobalAlloc, InterpCx, InterpResult, Machine, MayLeak, Misalignment, Pointer,
alloc_range, AllocBytes, AllocId, AllocMap, AllocRange, Allocation, CheckAlignMsg,
CheckInAllocMsg, GlobalAlloc, InterpCx, InterpResult, Machine, MayLeak, Misalignment, Pointer,
PointerArithmetic, Provenance, Scalar,
};
@ -425,7 +425,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
// Must be aligned.
if M::enforce_alignment(self) && align.bytes() > 1 {
self.check_misalign(Self::offset_misalignment(addr, align))?;
self.check_misalign(
Self::offset_misalignment(addr, align),
CheckAlignMsg::AccessedPtr,
)?;
}
None
}
@ -449,7 +452,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// Test align. Check this last; if both bounds and alignment are violated
// we want the error to be about the bounds.
if M::enforce_alignment(self) && align.bytes() > 1 {
self.check_misalign(self.alloc_misalignment(ptr, offset, align, alloc_align))?;
self.check_misalign(
self.alloc_misalignment(ptr, offset, align, alloc_align),
CheckAlignMsg::AccessedPtr,
)?;
}
// We can still be zero-sized in this branch, in which case we have to
@ -460,9 +466,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
#[inline(always)]
pub(super) fn check_misalign(&self, misaligned: Option<Misalignment>) -> InterpResult<'tcx> {
pub(super) fn check_misalign(
&self,
misaligned: Option<Misalignment>,
msg: CheckAlignMsg,
) -> InterpResult<'tcx> {
if let Some(misaligned) = misaligned {
throw_ub!(AlignmentCheckFailed(misaligned))
throw_ub!(AlignmentCheckFailed(misaligned, msg))
}
Ok(())
}

View file

@ -15,9 +15,9 @@ use rustc_middle::ty::Ty;
use rustc_target::abi::{Abi, Align, FieldIdx, HasDataLayout, Size, FIRST_VARIANT};
use super::{
alloc_range, mir_assign_valid_types, AllocId, AllocRef, AllocRefMut, ImmTy, Immediate,
InterpCx, InterpResult, Machine, MemoryKind, Misalignment, OffsetMode, OpTy, Operand, Pointer,
PointerArithmetic, Projectable, Provenance, Readable, Scalar,
alloc_range, mir_assign_valid_types, AllocId, AllocRef, AllocRefMut, CheckAlignMsg, ImmTy,
Immediate, InterpCx, InterpResult, Machine, MemoryKind, Misalignment, OffsetMode, OpTy,
Operand, Pointer, PointerArithmetic, Projectable, Provenance, Readable, Scalar,
};
#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
@ -461,7 +461,7 @@ where
// We check alignment separately, and *after* checking everything else.
// If an access is both OOB and misaligned, we want to see the bounds error.
let a = self.get_ptr_alloc(mplace.ptr(), size, Align::ONE)?;
self.check_misalign(mplace.mplace.misaligned)?;
self.check_misalign(mplace.mplace.misaligned, CheckAlignMsg::BasedOn)?;
Ok(a)
}
@ -477,7 +477,7 @@ where
// We check alignment separately, and raise that error *after* checking everything else.
// If an access is both OOB and misaligned, we want to see the bounds error.
// However we have to call `check_misalign` first to make the borrow checker happy.
let misalign_err = self.check_misalign(mplace.mplace.misaligned);
let misalign_err = self.check_misalign(mplace.mplace.misaligned, CheckAlignMsg::BasedOn);
let a = self.get_ptr_alloc_mut(mplace.ptr(), size, Align::ONE)?;
misalign_err?;
Ok(a)
@ -881,8 +881,8 @@ where
dest_size,
/*nonoverlapping*/ true,
)?;
self.check_misalign(src.mplace.misaligned)?;
self.check_misalign(dest.mplace.misaligned)?;
self.check_misalign(src.mplace.misaligned, CheckAlignMsg::BasedOn)?;
self.check_misalign(dest.mplace.misaligned, CheckAlignMsg::BasedOn)?;
Ok(())
}

View file

@ -385,7 +385,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
CheckInAllocMsg::InboundsTest, // will anyway be replaced by validity message
),
self.path,
Ub(AlignmentCheckFailed(Misalignment { required, has })) => UnalignedPtr {
Ub(AlignmentCheckFailed(Misalignment { required, has }, _msg)) => UnalignedPtr {
ptr_kind,
required_bytes: required.bytes(),
found_bytes: has.bytes()