From b1ebf002c38241da4f6f3e8357a662a6e5797c35 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 1 Aug 2023 17:11:00 +0200 Subject: don't UB on dangling ptr deref, instead check inbounds on projections --- .../miri/tests/fail/unaligned_pointers/drop_in_place.rs | 2 +- .../tests/fail/unaligned_pointers/drop_in_place.stderr | 4 ++-- .../tests/fail/unaligned_pointers/dyn_alignment.stderr | 4 ++-- .../tests/fail/unaligned_pointers/reference_to_packed.rs | 9 ++++----- .../fail/unaligned_pointers/reference_to_packed.stderr | 13 +++++++++---- .../fail/unaligned_pointers/unaligned_ptr_addr_of.rs | 14 -------------- .../fail/unaligned_pointers/unaligned_ptr_addr_of.stderr | 16 ---------------- .../fail/unaligned_pointers/unaligned_ref_addr_of.rs | 12 ++++++++++++ .../fail/unaligned_pointers/unaligned_ref_addr_of.stderr | 15 +++++++++++++++ 9 files changed, 45 insertions(+), 44 deletions(-) delete mode 100644 src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs delete mode 100644 src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.stderr create mode 100644 src/tools/miri/tests/fail/unaligned_pointers/unaligned_ref_addr_of.rs create mode 100644 src/tools/miri/tests/fail/unaligned_pointers/unaligned_ref_addr_of.stderr (limited to 'src/tools/miri/tests/fail/unaligned_pointers') diff --git a/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.rs b/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.rs index d8cab68ac5d..d71d5954a40 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.rs +++ b/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.rs @@ -13,7 +13,7 @@ struct PartialDrop { b: u8, } -//@error-in-other-file: /alignment 2 is required/ +//@error-in-other-file: /required 2 byte alignment/ fn main() { unsafe { // Create an unaligned pointer diff --git a/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.stderr b/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.stderr index ef20b43c118..db35a20ee22 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required +error: Undefined Behavior: constructing invalid value: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN) --> RUSTLIB/core/src/ptr/mod.rs:LL:CC | LL | pub unsafe fn drop_in_place(to_drop: *mut T) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/unaligned_pointers/dyn_alignment.stderr b/src/tools/miri/tests/fail/unaligned_pointers/dyn_alignment.stderr index 503721b9551..cfb43ae891f 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/dyn_alignment.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/dyn_alignment.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: constructing invalid value: encountered an unaligned reference (required 256 byte alignment but found $ALIGN) +error: Undefined Behavior: constructing invalid value: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN) --> $DIR/dyn_alignment.rs:LL:CC | LL | let _ptr = &*ptr; - | ^^^^^ constructing invalid value: encountered an unaligned reference (required 256 byte alignment but found $ALIGN) + | ^^^^^ constructing invalid value: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.rs b/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.rs index 4a8cf405ae2..b9d29d775ab 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.rs +++ b/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.rs @@ -1,5 +1,5 @@ -// This should fail even without validation/SB -//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -Cdebug-assertions=no +// This should fail even without SB +//@compile-flags: -Zmiri-disable-stacked-borrows -Cdebug-assertions=no #![allow(dead_code, unused_variables)] @@ -12,15 +12,14 @@ struct Foo { } unsafe fn raw_to_ref<'a, T>(x: *const T) -> &'a T { - mem::transmute(x) + mem::transmute(x) //~ERROR: required 4 byte alignment } fn main() { // Try many times as this might work by chance. for _ in 0..20 { let foo = Foo { x: 42, y: 99 }; - // There seem to be implicit reborrows, which make the error already appear here - let p: &i32 = unsafe { raw_to_ref(ptr::addr_of!(foo.x)) }; //~ERROR: alignment 4 is required + let p: &i32 = unsafe { raw_to_ref(ptr::addr_of!(foo.x)) }; let i = *p; } } diff --git a/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.stderr b/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.stderr index 7c246706dba..fb588854b2a 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.stderr @@ -1,13 +1,18 @@ -error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required +error: Undefined Behavior: constructing invalid value: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN) --> $DIR/reference_to_packed.rs:LL:CC | -LL | let p: &i32 = unsafe { raw_to_ref(ptr::addr_of!(foo.x)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required +LL | mem::transmute(x) + | ^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/reference_to_packed.rs:LL:CC + = note: inside `raw_to_ref::<'_, i32>` at $DIR/reference_to_packed.rs:LL:CC +note: inside `main` + --> $DIR/reference_to_packed.rs:LL:CC + | +LL | let p: &i32 = unsafe { raw_to_ref(ptr::addr_of!(foo.x)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs deleted file mode 100644 index b414b905472..00000000000 --- a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs +++ /dev/null @@ -1,14 +0,0 @@ -// This should fail even without validation or Stacked Borrows. -//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -Cdebug-assertions=no -use std::ptr; - -fn main() { - // Try many times as this might work by chance. - for _ in 0..20 { - let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. - let x = &x[0] as *const _ as *const u32; - // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. - // The deref is UB even if we just put the result into a raw pointer. - let _x = unsafe { ptr::addr_of!(*x) }; //~ ERROR: memory with alignment 2, but alignment 4 is required - } -} diff --git a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.stderr b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.stderr deleted file mode 100644 index 2d8b1bf7450..00000000000 --- a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required - --> $DIR/unaligned_ptr_addr_of.rs:LL:CC - | -LL | let _x = unsafe { ptr::addr_of!(*x) }; - | ^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `main` at RUSTLIB/core/src/ptr/mod.rs:LL:CC - = note: this error originates in the macro `ptr::addr_of` (in Nightly builds, run with -Z macro-backtrace for more info) - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ref_addr_of.rs b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ref_addr_of.rs new file mode 100644 index 00000000000..470420acd50 --- /dev/null +++ b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ref_addr_of.rs @@ -0,0 +1,12 @@ +// This should fail even without Stacked Borrows. +//@compile-flags: -Zmiri-disable-stacked-borrows -Cdebug-assertions=no + +fn main() { + // Try many times as this might work by chance. + for _ in 0..20 { + let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. + let x = &x[0] as *const _ as *const u32; + // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. + let _x = unsafe { &*x }; //~ ERROR: required 4 byte alignment + } +} diff --git a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ref_addr_of.stderr b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ref_addr_of.stderr new file mode 100644 index 00000000000..e47226ecdc7 --- /dev/null +++ b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ref_addr_of.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: constructing invalid value: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN) + --> $DIR/unaligned_ref_addr_of.rs:LL:CC + | +LL | let _x = unsafe { &*x }; + | ^^^ constructing invalid value: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at $DIR/unaligned_ref_addr_of.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + -- cgit 1.4.1-3-g733a5 From f3f9b795bdaccd8284baba295810e87646754c28 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 Sep 2023 15:12:18 +0200 Subject: place evaluation: require the original pointer to be aligned if an access happens --- compiler/rustc_abi/src/lib.rs | 1 + .../src/const_eval/eval_queries.rs | 6 +- compiler/rustc_const_eval/src/errors.rs | 7 +- compiler/rustc_const_eval/src/interpret/memory.rs | 92 ++++++---- compiler/rustc_const_eval/src/interpret/operand.rs | 60 +++---- compiler/rustc_const_eval/src/interpret/place.rs | 191 +++++++++------------ .../rustc_const_eval/src/interpret/projection.rs | 1 + compiler/rustc_const_eval/src/interpret/step.rs | 10 +- .../rustc_const_eval/src/interpret/validity.rs | 16 +- compiler/rustc_middle/src/mir/interpret/error.rs | 9 +- compiler/rustc_middle/src/mir/interpret/mod.rs | 2 +- src/tools/miri/src/helpers.rs | 5 +- src/tools/miri/src/shims/unix/fs.rs | 2 +- src/tools/miri/src/shims/unix/linux/sync.rs | 2 +- src/tools/miri/src/shims/windows/sync.rs | 4 +- .../field_requires_parent_struct_alignment2.rs | 30 ++++ .../field_requires_parent_struct_alignment2.stderr | 20 +++ .../generic_const_exprs/issue-80742.rs | 1 + .../generic_const_exprs/issue-80742.stderr | 4 +- tests/ui/consts/const-deref-ptr.rs | 1 + tests/ui/consts/const-eval/raw-pointer-ub.rs | 11 ++ tests/ui/consts/const-eval/raw-pointer-ub.stderr | 10 +- 22 files changed, 266 insertions(+), 219 deletions(-) create mode 100644 src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.rs create mode 100644 src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.stderr (limited to 'src/tools/miri/tests/fail/unaligned_pointers') diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 45b3e76cca6..494ab451560 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -681,6 +681,7 @@ impl fmt::Display for AlignFromBytesError { impl Align { pub const ONE: Align = Align { pow2: 0 }; + // LLVM has a maximal supported alignment of 2^29, we inherit that. pub const MAX: Align = Align { pow2: 29 }; #[inline] diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 4adfbe336af..6b612c34837 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -1,3 +1,5 @@ +use std::mem; + use either::{Left, Right}; use rustc_hir::def::DefKind; @@ -73,9 +75,9 @@ fn eval_body_using_ecx<'mir, 'tcx>( None => InternKind::Constant, } }; - ecx.machine.check_alignment = CheckAlignment::No; // interning doesn't need to respect alignment + let check_alignment = mem::replace(&mut ecx.machine.check_alignment, CheckAlignment::No); // interning doesn't need to respect alignment intern_const_alloc_recursive(ecx, intern_kind, &ret)?; - // we leave alignment checks off, since this `ecx` will not be used for further evaluation anyway + ecx.machine.check_alignment = check_alignment; debug!("eval_body_using_ecx done: {:?}", ret); Ok(ret) diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 96575c31c08..6214ce0f511 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -5,8 +5,9 @@ use rustc_errors::{ use rustc_hir::ConstContext; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::mir::interpret::{ - CheckInAllocMsg, ExpectedKind, InterpError, InvalidMetaKind, InvalidProgramInfo, PointerKind, - ResourceExhaustionInfo, UndefinedBehaviorInfo, UnsupportedOpInfo, ValidationErrorInfo, + CheckInAllocMsg, ExpectedKind, InterpError, InvalidMetaKind, InvalidProgramInfo, Misalignment, + PointerKind, ResourceExhaustionInfo, UndefinedBehaviorInfo, UnsupportedOpInfo, + ValidationErrorInfo, }; use rustc_middle::ty::{self, Ty}; use rustc_span::Span; @@ -567,7 +568,7 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { builder.set_arg("bad_pointer_message", bad_pointer_message(msg, handler)); } - AlignmentCheckFailed { required, has } => { + AlignmentCheckFailed(Misalignment { required, has }) => { builder.set_arg("required", required.bytes()); builder.set_arg("has", has.bytes()); } diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index edd8c540226..4322c39f0ac 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -22,8 +22,8 @@ use crate::fluent_generated as fluent; use super::{ alloc_range, AllocBytes, AllocId, AllocMap, AllocRange, Allocation, CheckInAllocMsg, - GlobalAlloc, InterpCx, InterpResult, Machine, MayLeak, Pointer, PointerArithmetic, Provenance, - Scalar, + GlobalAlloc, InterpCx, InterpResult, Machine, MayLeak, Misalignment, Pointer, + PointerArithmetic, Provenance, Scalar, }; #[derive(Debug, PartialEq, Copy, Clone)] @@ -372,7 +372,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.check_and_deref_ptr( ptr, size, - M::enforce_alignment(self).then_some(align), + align, CheckInAllocMsg::MemoryAccessTest, |alloc_id, offset, prov| { let (size, align) = self @@ -382,9 +382,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ) } - /// Check if the given pointer points to live memory of given `size` and `align` - /// (ignoring `M::enforce_alignment`). The caller can control the error message for the - /// out-of-bounds case. + /// Check if the given pointer points to live memory of given `size` and `align`. + /// The caller can control the error message for the out-of-bounds case. #[inline(always)] pub fn check_ptr_access_align( &self, @@ -393,7 +392,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { align: Align, msg: CheckInAllocMsg, ) -> InterpResult<'tcx> { - self.check_and_deref_ptr(ptr, size, Some(align), msg, |alloc_id, _, _| { + self.check_and_deref_ptr(ptr, size, align, msg, |alloc_id, _, _| { let (size, align) = self.get_live_alloc_size_and_align(alloc_id, msg)?; Ok((size, align, ())) })?; @@ -402,15 +401,14 @@ 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. + /// checking is offloaded to a helper closure. /// /// If this returns `None`, the size is 0; it can however return `Some` even for size 0. fn check_and_deref_ptr( &self, ptr: Pointer>, size: Size, - align: Option, + align: Align, msg: CheckInAllocMsg, alloc_size: impl FnOnce( AllocId, @@ -426,9 +424,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { throw_ub!(DanglingIntPointer(addr, msg)); } // Must be aligned. - if let Some(align) = align { - self.check_offset_align(addr, align)?; - } + self.check_misalign(Self::offset_misalignment(addr, align))?; None } Ok((alloc_id, offset, prov)) => { @@ -450,18 +446,7 @@ 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 let Some(align) = align { - if M::use_addr_for_alignment_check(self) { - // `use_addr_for_alignment_check` can only be true if `OFFSET_IS_ADDR` is true. - self.check_offset_align(ptr.addr().bytes(), align)?; - } else { - // Check allocation alignment and offset alignment. - if alloc_align.bytes() < align.bytes() { - throw_ub!(AlignmentCheckFailed { has: alloc_align, required: align }); - } - self.check_offset_align(offset.bytes(), align)?; - } - } + self.check_misalign(self.alloc_misalignment(ptr, offset, align, alloc_align))?; // We can still be zero-sized in this branch, in which case we have to // return `None`. @@ -470,16 +455,59 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }) } - fn check_offset_align(&self, offset: u64, align: Align) -> InterpResult<'tcx> { + #[inline(always)] + pub(super) fn check_misalign(&self, misaligned: Option) -> InterpResult<'tcx> { + if M::enforce_alignment(self) { + if let Some(misaligned) = misaligned { + throw_ub!(AlignmentCheckFailed(misaligned)) + } + } + Ok(()) + } + + #[must_use] + fn offset_misalignment(offset: u64, align: Align) -> Option { if offset % align.bytes() == 0 { - Ok(()) + None } else { // The biggest power of two through which `offset` is divisible. let offset_pow2 = 1 << offset.trailing_zeros(); - throw_ub!(AlignmentCheckFailed { - has: Align::from_bytes(offset_pow2).unwrap(), - required: align - }); + Some(Misalignment { has: Align::from_bytes(offset_pow2).unwrap(), required: align }) + } + } + + #[must_use] + fn alloc_misalignment( + &self, + ptr: Pointer>, + offset: Size, + align: Align, + alloc_align: Align, + ) -> Option { + if M::use_addr_for_alignment_check(self) { + // `use_addr_for_alignment_check` can only be true if `OFFSET_IS_ADDR` is true. + Self::offset_misalignment(ptr.addr().bytes(), align) + } else { + // Check allocation alignment and offset alignment. + if alloc_align.bytes() < align.bytes() { + Some(Misalignment { has: alloc_align, required: align }) + } else { + Self::offset_misalignment(offset.bytes(), align) + } + } + } + + pub(super) fn is_ptr_misaligned( + &self, + ptr: Pointer>, + align: Align, + ) -> Option { + match self.ptr_try_get_alloc_id(ptr) { + Err(addr) => Self::offset_misalignment(addr, align), + Ok((alloc_id, offset, _prov)) => { + let (_size, alloc_align, _kind) = self.get_alloc_info(alloc_id); + self.alloc_misalignment(ptr, offset, align, alloc_align) + } } } } @@ -597,7 +625,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let ptr_and_alloc = self.check_and_deref_ptr( ptr, size, - M::enforce_alignment(self).then_some(align), + align, CheckInAllocMsg::MemoryAccessTest, |alloc_id, offset, prov| { let alloc = self.get_alloc_raw(alloc_id)?; diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 0f259f6c1a2..99424518ad4 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -10,7 +10,7 @@ use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter}; use rustc_middle::ty::{ConstInt, Ty, TyCtxt}; use rustc_middle::{mir, ty}; -use rustc_target::abi::{self, Abi, Align, HasDataLayout, Size}; +use rustc_target::abi::{self, Abi, HasDataLayout, Size}; use super::{ alloc_range, from_known_layout, mir_assign_valid_types, AllocId, Frame, InterpCx, InterpResult, @@ -44,12 +44,16 @@ impl From> for Immediate { } impl Immediate { - pub fn from_pointer(ptr: Pointer, cx: &impl HasDataLayout) -> Self { - Immediate::Scalar(Scalar::from_pointer(ptr, cx)) - } - - pub fn from_maybe_pointer(ptr: Pointer>, cx: &impl HasDataLayout) -> Self { - Immediate::Scalar(Scalar::from_maybe_pointer(ptr, cx)) + pub fn new_pointer_with_meta( + ptr: Pointer>, + meta: MemPlaceMeta, + cx: &impl HasDataLayout, + ) -> Self { + let ptr = Scalar::from_maybe_pointer(ptr, cx); + match meta { + MemPlaceMeta::None => Immediate::from(ptr), + MemPlaceMeta::Meta(meta) => Immediate::ScalarPair(ptr, meta), + } } pub fn new_slice(ptr: Pointer>, len: u64, cx: &impl HasDataLayout) -> Self { @@ -328,14 +332,6 @@ pub(super) enum Operand { pub struct OpTy<'tcx, Prov: Provenance = AllocId> { op: Operand, // Keep this private; it helps enforce invariants. pub layout: TyAndLayout<'tcx>, - /// rustc does not have a proper way to represent the type of a field of a `repr(packed)` struct: - /// it needs to have a different alignment than the field type would usually have. - /// So we represent this here with a separate field that "overwrites" `layout.align`. - /// This means `layout.align` should never be used for an `OpTy`! - /// `None` means "alignment does not matter since this is a by-value operand" - /// (`Operand::Immediate`); this field is only relevant for `Operand::Indirect`. - /// Also CTFE ignores alignment anyway, so this is for Miri only. - pub align: Option, } impl std::fmt::Debug for OpTy<'_, Prov> { @@ -351,18 +347,14 @@ impl std::fmt::Debug for OpTy<'_, Prov> { impl<'tcx, Prov: Provenance> From> for OpTy<'tcx, Prov> { #[inline(always)] fn from(val: ImmTy<'tcx, Prov>) -> Self { - OpTy { op: Operand::Immediate(val.imm), layout: val.layout, align: None } + OpTy { op: Operand::Immediate(val.imm), layout: val.layout } } } impl<'tcx, Prov: Provenance> From> for OpTy<'tcx, Prov> { #[inline(always)] fn from(mplace: MPlaceTy<'tcx, Prov>) -> Self { - OpTy { - op: Operand::Indirect(*mplace.mplace()), - layout: mplace.layout, - align: Some(mplace.align), - } + OpTy { op: Operand::Indirect(*mplace.mplace()), layout: mplace.layout } } } @@ -635,7 +627,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { throw_inval!(ConstPropNonsense); } } - Ok(OpTy { op, layout, align: Some(layout.align.abi) }) + Ok(OpTy { op, layout }) } /// Every place can be read from, so we can turn them into an operand. @@ -650,16 +642,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Right((frame, local, offset)) => { debug_assert!(place.layout.is_sized()); // only sized locals can ever be `Place::Local`. let base = self.local_to_op(&self.stack()[frame], local, None)?; - let mut field = match offset { + Ok(match offset { Some(offset) => base.offset(offset, place.layout, self)?, None => { // In the common case this hasn't been projected. debug_assert_eq!(place.layout, base.layout); base } - }; - field.align = Some(place.align); - Ok(field) + }) } } } @@ -747,27 +737,23 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }) }; let layout = from_known_layout(self.tcx, self.param_env, layout, || self.layout_of(ty))?; - let op = match val_val { + let imm = match val_val { mir::ConstValue::Indirect { alloc_id, offset } => { // We rely on mutability being set correctly in that allocation to prevent writes // where none should happen. let ptr = self.global_base_pointer(Pointer::new(alloc_id, offset))?; - Operand::Indirect(MemPlace::from_ptr(ptr.into())) + return Ok(self.ptr_to_mplace(ptr.into(), layout).into()); } - mir::ConstValue::Scalar(x) => Operand::Immediate(adjust_scalar(x)?.into()), - mir::ConstValue::ZeroSized => Operand::Immediate(Immediate::Uninit), + mir::ConstValue::Scalar(x) => adjust_scalar(x)?.into(), + mir::ConstValue::ZeroSized => Immediate::Uninit, mir::ConstValue::Slice { data, meta } => { // We rely on mutability being set correctly in `data` to prevent writes // where none should happen. let ptr = Pointer::new(self.tcx.reserve_and_set_memory_alloc(data), Size::ZERO); - Operand::Immediate(Immediate::new_slice( - self.global_base_pointer(ptr)?.into(), - meta, - self, - )) + Immediate::new_slice(self.global_base_pointer(ptr)?.into(), meta, self) } }; - Ok(OpTy { op, layout, align: Some(layout.align.abi) }) + Ok(OpTy { op: Operand::Immediate(imm), layout }) } } @@ -780,6 +766,6 @@ mod size_asserts { static_assert_size!(Immediate, 48); static_assert_size!(ImmTy<'_>, 64); static_assert_size!(Operand, 56); - static_assert_size!(OpTy<'_>, 80); + static_assert_size!(OpTy<'_>, 72); // tidy-alphabetical-end } diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index f48417f207a..240613bdff6 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -16,7 +16,7 @@ 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, OffsetMode, OpTy, Operand, Pointer, + InterpCx, InterpResult, Machine, MemoryKind, Misalignment, OffsetMode, OpTy, Operand, Pointer, PointerArithmetic, Projectable, Provenance, Readable, Scalar, }; @@ -57,19 +57,11 @@ pub(super) struct MemPlace { /// Must not be present for sized types, but can be missing for unsized types /// (e.g., `extern type`). pub meta: MemPlaceMeta, + /// Stores whether this place was created based on a sufficiently aligned pointer. + misaligned: Option, } impl MemPlace { - #[inline(always)] - pub fn from_ptr(ptr: Pointer>) -> Self { - MemPlace { ptr, meta: MemPlaceMeta::None } - } - - #[inline(always)] - pub fn from_ptr_with_meta(ptr: Pointer>, meta: MemPlaceMeta) -> Self { - MemPlace { ptr, meta } - } - /// Adjust the provenance of the main pointer (metadata is unaffected). pub fn map_provenance(self, f: impl FnOnce(Option) -> Option) -> Self { MemPlace { ptr: self.ptr.map_provenance(f), ..self } @@ -78,12 +70,7 @@ impl MemPlace { /// Turn a mplace into a (thin or wide) pointer, as a reference, pointing to the same space. #[inline] pub fn to_ref(self, cx: &impl HasDataLayout) -> Immediate { - match self.meta { - MemPlaceMeta::None => Immediate::from(Scalar::from_maybe_pointer(self.ptr, cx)), - MemPlaceMeta::Meta(meta) => { - Immediate::ScalarPair(Scalar::from_maybe_pointer(self.ptr, cx), meta) - } - } + Immediate::new_pointer_with_meta(self.ptr, self.meta, cx) } #[inline] @@ -108,7 +95,7 @@ impl MemPlace { } OffsetMode::Wrapping => self.ptr.wrapping_offset(offset, ecx), }; - Ok(MemPlace { ptr, meta }) + Ok(MemPlace { ptr, meta, misaligned: self.misaligned }) } } @@ -117,11 +104,6 @@ impl MemPlace { pub struct MPlaceTy<'tcx, Prov: Provenance = AllocId> { mplace: MemPlace, pub layout: TyAndLayout<'tcx>, - /// rustc does not have a proper way to represent the type of a field of a `repr(packed)` struct: - /// it needs to have a different alignment than the field type would usually have. - /// So we represent this here with a separate field that "overwrites" `layout.align`. - /// This means `layout.align` should never be used for a `MPlaceTy`! - pub align: Align, } impl std::fmt::Debug for MPlaceTy<'_, Prov> { @@ -143,25 +125,7 @@ impl<'tcx, Prov: Provenance> MPlaceTy<'tcx, Prov> { assert!(layout.is_zst()); let align = layout.align.abi; let ptr = Pointer::from_addr_invalid(align.bytes()); // no provenance, absolute address - MPlaceTy { mplace: MemPlace { ptr, meta: MemPlaceMeta::None }, layout, align } - } - - #[inline] - pub fn from_aligned_ptr(ptr: Pointer>, layout: TyAndLayout<'tcx>) -> Self { - MPlaceTy { mplace: MemPlace::from_ptr(ptr), layout, align: layout.align.abi } - } - - #[inline] - pub fn from_aligned_ptr_with_meta( - ptr: Pointer>, - layout: TyAndLayout<'tcx>, - meta: MemPlaceMeta, - ) -> Self { - MPlaceTy { - mplace: MemPlace::from_ptr_with_meta(ptr, meta), - layout, - align: layout.align.abi, - } + MPlaceTy { mplace: MemPlace { ptr, meta: MemPlaceMeta::None, misaligned: None }, layout } } /// Adjust the provenance of the main pointer (metadata is unaffected). @@ -204,11 +168,7 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for MPlaceTy<'tcx, Prov> { layout: TyAndLayout<'tcx>, ecx: &InterpCx<'mir, 'tcx, M>, ) -> InterpResult<'tcx, Self> { - Ok(MPlaceTy { - mplace: self.mplace.offset_with_meta_(offset, mode, meta, ecx)?, - align: self.align.restrict_for_offset(offset), - layout, - }) + Ok(MPlaceTy { mplace: self.mplace.offset_with_meta_(offset, mode, meta, ecx)?, layout }) } fn to_op<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>( @@ -239,11 +199,6 @@ pub(super) enum Place { pub struct PlaceTy<'tcx, Prov: Provenance = AllocId> { place: Place, // Keep this private; it helps enforce invariants. pub layout: TyAndLayout<'tcx>, - /// rustc does not have a proper way to represent the type of a field of a `repr(packed)` struct: - /// it needs to have a different alignment than the field type would usually have. - /// So we represent this here with a separate field that "overwrites" `layout.align`. - /// This means `layout.align` should never be used for a `PlaceTy`! - pub align: Align, } impl std::fmt::Debug for PlaceTy<'_, Prov> { @@ -259,7 +214,7 @@ impl std::fmt::Debug for PlaceTy<'_, Prov> { impl<'tcx, Prov: Provenance> From> for PlaceTy<'tcx, Prov> { #[inline(always)] fn from(mplace: MPlaceTy<'tcx, Prov>) -> Self { - PlaceTy { place: Place::Ptr(mplace.mplace), layout: mplace.layout, align: mplace.align } + PlaceTy { place: Place::Ptr(mplace.mplace), layout: mplace.layout } } } @@ -275,7 +230,7 @@ impl<'tcx, Prov: Provenance> PlaceTy<'tcx, Prov> { &self, ) -> Either, (usize, mir::Local, Option)> { match self.place { - Place::Ptr(mplace) => Left(MPlaceTy { mplace, layout: self.layout, align: self.align }), + Place::Ptr(mplace) => Left(MPlaceTy { mplace, layout: self.layout }), Place::Local { frame, local, offset } => Right((frame, local, offset)), } } @@ -332,11 +287,7 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for PlaceTy<'tcx, Prov> { .offset(old_offset.unwrap_or(Size::ZERO).bytes(), offset.bytes())?, ); - PlaceTy { - place: Place::Local { frame, local, offset: Some(new_offset) }, - align: self.align.restrict_for_offset(offset), - layout, - } + PlaceTy { place: Place::Local { frame, local, offset: Some(new_offset) }, layout } } }) } @@ -354,9 +305,7 @@ impl<'tcx, Prov: Provenance> OpTy<'tcx, Prov> { #[inline(always)] pub fn as_mplace_or_imm(&self) -> Either, ImmTy<'tcx, Prov>> { match self.op() { - Operand::Indirect(mplace) => { - Left(MPlaceTy { mplace: *mplace, layout: self.layout, align: self.align.unwrap() }) - } + Operand::Indirect(mplace) => Left(MPlaceTy { mplace: *mplace, layout: self.layout }), Operand::Immediate(imm) => Right(ImmTy::from_immediate(*imm, self.layout)), } } @@ -377,7 +326,7 @@ impl<'tcx, Prov: Provenance> OpTy<'tcx, Prov> { pub trait Writeable<'tcx, Prov: Provenance>: Projectable<'tcx, Prov> { fn as_mplace_or_local( &self, - ) -> Either, (usize, mir::Local, Option, Align, TyAndLayout<'tcx>)>; + ) -> Either, (usize, mir::Local, Option, TyAndLayout<'tcx>)>; fn force_mplace<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>( &self, @@ -389,10 +338,9 @@ impl<'tcx, Prov: Provenance> Writeable<'tcx, Prov> for PlaceTy<'tcx, Prov> { #[inline(always)] fn as_mplace_or_local( &self, - ) -> Either, (usize, mir::Local, Option, Align, TyAndLayout<'tcx>)> - { + ) -> Either, (usize, mir::Local, Option, TyAndLayout<'tcx>)> { self.as_mplace_or_local() - .map_right(|(frame, local, offset)| (frame, local, offset, self.align, self.layout)) + .map_right(|(frame, local, offset)| (frame, local, offset, self.layout)) } #[inline(always)] @@ -408,8 +356,7 @@ impl<'tcx, Prov: Provenance> Writeable<'tcx, Prov> for MPlaceTy<'tcx, Prov> { #[inline(always)] fn as_mplace_or_local( &self, - ) -> Either, (usize, mir::Local, Option, Align, TyAndLayout<'tcx>)> - { + ) -> Either, (usize, mir::Local, Option, TyAndLayout<'tcx>)> { Left(self.clone()) } @@ -428,6 +375,25 @@ where Prov: Provenance, M: Machine<'mir, 'tcx, Provenance = Prov>, { + pub fn ptr_with_meta_to_mplace( + &self, + ptr: Pointer>, + meta: MemPlaceMeta, + layout: TyAndLayout<'tcx>, + ) -> MPlaceTy<'tcx, M::Provenance> { + let misaligned = self.is_ptr_misaligned(ptr, layout.align.abi); + MPlaceTy { mplace: MemPlace { ptr, meta, misaligned }, layout } + } + + pub fn ptr_to_mplace( + &self, + ptr: Pointer>, + layout: TyAndLayout<'tcx>, + ) -> MPlaceTy<'tcx, M::Provenance> { + assert!(layout.is_sized()); + self.ptr_with_meta_to_mplace(ptr, MemPlaceMeta::None, layout) + } + /// Take a value, which represents a (thin or wide) reference, and make it a place. /// Alignment is just based on the type. This is the inverse of `mplace_to_ref()`. /// @@ -449,7 +415,8 @@ where // `ref_to_mplace` is called on raw pointers even if they don't actually get dereferenced; // we hence can't call `size_and_align_of` since that asserts more validity than we want. - Ok(MPlaceTy::from_aligned_ptr_with_meta(ptr.to_pointer(self)?, layout, meta)) + let ptr = ptr.to_pointer(self)?; + Ok(self.ptr_with_meta_to_mplace(ptr, meta, layout)) } /// Turn a mplace into a (thin or wide) mutable raw pointer, pointing to the same space. @@ -491,8 +458,11 @@ where let (size, _align) = self .size_and_align_of_mplace(&mplace)? .unwrap_or((mplace.layout.size, mplace.layout.align.abi)); - // Due to packed places, only `mplace.align` matters. - self.get_ptr_alloc(mplace.ptr(), size, mplace.align) + // 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)?; + Ok(a) } #[inline] @@ -504,8 +474,13 @@ where let (size, _align) = self .size_and_align_of_mplace(&mplace)? .unwrap_or((mplace.layout.size, mplace.layout.align.abi)); - // Due to packed places, only `mplace.align` matters. - self.get_ptr_alloc_mut(mplace.ptr(), size, mplace.align) + // 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 a = self.get_ptr_alloc_mut(mplace.ptr(), size, Align::ONE)?; + misalign_err?; + Ok(a) } /// Converts a repr(simd) place into a place where `place_index` accesses the SIMD elements. @@ -520,8 +495,8 @@ where let (len, e_ty) = mplace.layout.ty.simd_size_and_type(*self.tcx); let array = Ty::new_array(self.tcx.tcx, e_ty, len); let layout = self.layout_of(array)?; - assert_eq!(layout.size, mplace.layout.size); - Ok((MPlaceTy { layout, ..*mplace }, len)) + let mplace = mplace.transmute(layout, self)?; + Ok((mplace, len)) } /// Converts a repr(simd) place into a place where `place_index` accesses the SIMD elements. @@ -557,7 +532,7 @@ where Operand::Indirect(mplace) => Place::Ptr(*mplace), } }; - Ok(PlaceTy { place, layout, align: layout.align.abi }) + Ok(PlaceTy { place, layout }) } /// Computes a place. You should only use this if you intend to write into this @@ -647,7 +622,7 @@ where // See if we can avoid an allocation. This is the counterpart to `read_immediate_raw`, // but not factored as a separate function. let mplace = match dest.as_mplace_or_local() { - Right((frame, local, offset, align, layout)) => { + Right((frame, local, offset, layout)) => { if offset.is_some() { // This has been projected to a part of this local. We could have complicated // logic to still keep this local as an `Operand`... but it's much easier to @@ -688,7 +663,7 @@ where } Operand::Indirect(mplace) => { // The local is in memory, go on below. - MPlaceTy { mplace: *mplace, align, layout } + MPlaceTy { mplace: *mplace, layout } } } } @@ -697,7 +672,7 @@ where }; // This is already in memory, write there. - self.write_immediate_to_mplace_no_validate(src, mplace.layout, mplace.align, mplace.mplace) + self.write_immediate_to_mplace_no_validate(src, mplace.layout, mplace.mplace) } /// Write an immediate to memory. @@ -707,7 +682,6 @@ where &mut self, value: Immediate, layout: TyAndLayout<'tcx>, - align: Align, dest: MemPlace, ) -> InterpResult<'tcx> { // Note that it is really important that the type here is the right one, and matches the @@ -716,9 +690,7 @@ where // wrong type. let tcx = *self.tcx; - let Some(mut alloc) = - self.get_place_alloc_mut(&MPlaceTy { mplace: dest, layout, align })? - else { + let Some(mut alloc) = self.get_place_alloc_mut(&MPlaceTy { mplace: dest, layout })? else { // zero-sized access return Ok(()); }; @@ -736,9 +708,6 @@ where alloc.write_scalar(alloc_range(Size::ZERO, size), scalar) } Immediate::ScalarPair(a_val, b_val) => { - // We checked `ptr_align` above, so all fields will have the alignment they need. - // We would anyway check against `ptr_align.restrict_for_offset(b_offset)`, - // which `ptr.offset(b_offset)` cannot possibly fail to satisfy. let Abi::ScalarPair(a, b) = layout.abi else { span_bug!( self.cur_span(), @@ -767,7 +736,7 @@ where ) -> InterpResult<'tcx> { let mplace = match dest.as_mplace_or_local() { Left(mplace) => mplace, - Right((frame, local, offset, align, layout)) => { + Right((frame, local, offset, layout)) => { if offset.is_some() { // This has been projected to a part of this local. We could have complicated // logic to still keep this local as an `Operand`... but it's much easier to @@ -783,7 +752,7 @@ where } Operand::Indirect(mplace) => { // The local is in memory, go on below. - MPlaceTy { mplace: *mplace, layout, align } + MPlaceTy { mplace: *mplace, layout } } } } @@ -876,7 +845,6 @@ where self.write_immediate_to_mplace_no_validate( *src_val, src.layout(), - dest_mem.align, dest_mem.mplace, ) }; @@ -903,14 +871,19 @@ where // type does not have Scalar/ScalarPair layout. // (Or as the `Assign` docs put it, assignments "not producing primitives" must be // non-overlapping.) + // We check alignment separately, and *after* checking everything else. + // If an access is both OOB and misaligned, we want to see the bounds error. self.mem_copy( src.ptr(), - src.align, + Align::ONE, dest.ptr(), - dest.align, + Align::ONE, dest_size, /*nonoverlapping*/ true, - ) + )?; + self.check_misalign(src.mplace.misaligned)?; + self.check_misalign(dest.mplace.misaligned)?; + Ok(()) } /// Ensures that a place is in memory, and returns where it is. @@ -944,7 +917,6 @@ where self.write_immediate_to_mplace_no_validate( local_val, local_layout, - local_layout.align.abi, mplace.mplace, )?; } @@ -974,7 +946,7 @@ where Place::Ptr(mplace) => mplace, }; // Return with the original layout and align, so that the caller can go on - Ok(MPlaceTy { mplace, layout: place.layout, align: place.align }) + Ok(MPlaceTy { mplace, layout: place.layout }) } pub fn allocate_dyn( @@ -987,7 +959,7 @@ where span_bug!(self.cur_span(), "cannot allocate space for `extern` type, size is not known") }; let ptr = self.allocate_ptr(size, align, kind)?; - Ok(MPlaceTy::from_aligned_ptr_with_meta(ptr.into(), layout, meta)) + Ok(self.ptr_with_meta_to_mplace(ptr.into(), meta, layout)) } pub fn allocate( @@ -999,7 +971,7 @@ where self.allocate_dyn(layout, kind, MemPlaceMeta::None) } - /// Returns a wide MPlace of type `&'static [mut] str` to a new 1-aligned allocation. + /// Returns a wide MPlace of type `str` to a new 1-aligned allocation. pub fn allocate_str( &mut self, str: &str, @@ -1008,15 +980,8 @@ where ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { let ptr = self.allocate_bytes_ptr(str.as_bytes(), Align::ONE, kind, mutbl)?; let meta = Scalar::from_target_usize(u64::try_from(str.len()).unwrap(), self); - let mplace = MemPlace { ptr: ptr.into(), meta: MemPlaceMeta::Meta(meta) }; - - let ty = Ty::new_ref( - self.tcx.tcx, - self.tcx.lifetimes.re_static, - ty::TypeAndMut { ty: self.tcx.types.str_, mutbl }, - ); - let layout = self.layout_of(ty).unwrap(); - Ok(MPlaceTy { mplace, layout, align: layout.align.abi }) + let layout = self.layout_of(self.tcx.types.str_).unwrap(); + Ok(self.ptr_with_meta_to_mplace(ptr.into(), MemPlaceMeta::Meta(meta), layout)) } /// Writes the aggregate to the destination. @@ -1055,7 +1020,7 @@ where let _ = self.tcx.global_alloc(raw.alloc_id); let ptr = self.global_base_pointer(Pointer::from(raw.alloc_id))?; let layout = self.layout_of(raw.ty)?; - Ok(MPlaceTy::from_aligned_ptr(ptr.into(), layout)) + Ok(self.ptr_to_mplace(ptr.into(), layout)) } /// Turn a place with a `dyn Trait` type into a place with the actual dynamic type. @@ -1071,12 +1036,10 @@ where let vtable = mplace.meta().unwrap_meta().to_pointer(self)?; let (ty, _) = self.get_ptr_vtable(vtable)?; let layout = self.layout_of(ty)?; - - let mplace = MPlaceTy { - mplace: MemPlace { meta: MemPlaceMeta::None, ..mplace.mplace }, - layout, - align: layout.align.abi, - }; + // This is a kind of transmute, from a place with unsized type and metadata to + // a place with sized type and no metadata. + let mplace = + MPlaceTy { mplace: MemPlace { meta: MemPlaceMeta::None, ..mplace.mplace }, layout }; Ok((mplace, vtable)) } @@ -1108,10 +1071,10 @@ mod size_asserts { use super::*; use rustc_data_structures::static_assert_size; // tidy-alphabetical-start - static_assert_size!(MemPlace, 40); + static_assert_size!(MemPlace, 48); static_assert_size!(MemPlaceMeta, 24); static_assert_size!(MPlaceTy<'_>, 64); - static_assert_size!(Place, 40); + static_assert_size!(Place, 48); static_assert_size!(PlaceTy<'_>, 64); // tidy-alphabetical-end } diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index f5666787fcd..6694c43c992 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -267,6 +267,7 @@ where let len = base.len(self)?; let field_layout = base.layout().field(self, 0); // Ensure that all the offsets are in-bounds once, up-front. + debug!("project_array_fields: {base:?} {len}"); base.offset(len * stride, self.layout_of(self.tcx.types.unit).unwrap(), self)?; // Create the iterator. Ok(ArrayIterator { base, range: 0..len, stride, field_layout, _phantom: PhantomData }) diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 07b5f5ffe21..90b30cca95c 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -7,6 +7,7 @@ use either::Either; use rustc_middle::mir; use rustc_middle::mir::interpret::{InterpResult, Scalar}; use rustc_middle::ty::layout::LayoutOf; +use rustc_target::abi::Align; use super::{ImmTy, InterpCx, Machine, Projectable}; use crate::util; @@ -206,15 +207,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let elem_size = first.layout.size; let first_ptr = first.ptr(); let rest_ptr = first_ptr.offset(elem_size, self)?; - // For the alignment of `rest_ptr`, we crucially do *not* use `first.align` as - // that place might be more aligned than its type mandates (a `u8` array could - // be 4-aligned if it sits at the right spot in a struct). We have to also factor - // in element size. + // No alignment requirement since `copy_op` above already checked it. self.mem_copy_repeatedly( first_ptr, - dest.align, + Align::ONE, rest_ptr, - dest.align.restrict_for_offset(elem_size), + Align::ONE, elem_size, length - 1, /*nonoverlapping:*/ true, diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index c72c855aad2..b8cc4e8007e 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -13,14 +13,14 @@ use rustc_ast::Mutability; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_middle::mir::interpret::{ - ExpectedKind, InterpError, InvalidMetaKind, PointerKind, ValidationErrorInfo, + ExpectedKind, InterpError, InvalidMetaKind, Misalignment, PointerKind, ValidationErrorInfo, ValidationErrorKind, ValidationErrorKind::*, }; use rustc_middle::ty; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_span::symbol::{sym, Symbol}; use rustc_target::abi::{ - Abi, FieldIdx, Scalar as ScalarAbi, Size, VariantIdx, Variants, WrappingRange, + Abi, Align, FieldIdx, Scalar as ScalarAbi, Size, VariantIdx, Variants, WrappingRange, }; use std::hash::Hash; @@ -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 { required, has }) => UnalignedPtr { + Ub(AlignmentCheckFailed(Misalignment { required, has })) => UnalignedPtr { ptr_kind, required_bytes: required.bytes(), found_bytes: has.bytes() @@ -781,14 +781,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> // Optimization: we just check the entire range at once. // NOTE: Keep this in sync with the handling of integer and float // types above, in `visit_primitive`. - // In run-time mode, we accept pointers in here. This is actually more - // permissive than a per-element check would be, e.g., we accept - // a &[u8] that contains a pointer even though bytewise checking would - // reject it. However, that's good: We don't inherently want - // to reject those pointers, we just do not have the machinery to - // talk about parts of a pointer. - // We also accept uninit, for consistency with the slow path. - let alloc = self.ecx.get_ptr_alloc(mplace.ptr(), size, mplace.align)?.expect("we already excluded size 0"); + // No need for an alignment check here, this is not an actual memory access. + let alloc = self.ecx.get_ptr_alloc(mplace.ptr(), size, Align::ONE)?.expect("we already excluded size 0"); match alloc.get_bytes_strip_provenance() { // In the happy case, we needn't check anything else. diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 360b2032c52..9083c6b3cda 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -261,6 +261,13 @@ pub struct ScalarSizeMismatch { pub data_size: u64, } +/// Information about a misaligned pointer. +#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)] +pub struct Misalignment { + pub has: Align, + pub required: Align, +} + macro_rules! impl_into_diagnostic_arg_through_debug { ($($ty:ty),*$(,)?) => {$( impl IntoDiagnosticArg for $ty { @@ -322,7 +329,7 @@ pub enum UndefinedBehaviorInfo<'tcx> { /// Using an integer as a pointer in the wrong way. DanglingIntPointer(u64, CheckInAllocMsg), /// Used a pointer with bad alignment. - AlignmentCheckFailed { required: Align, has: Align }, + AlignmentCheckFailed(Misalignment), /// Writing to read-only memory. WriteToReadOnly(AllocId), /// Trying to access the data behind a function pointer. diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index d21f82f04f6..42d58264186 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -144,7 +144,7 @@ use crate::ty::{self, Instance, Ty, TyCtxt}; pub use self::error::{ struct_error, BadBytesAccess, CheckInAllocMsg, ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, ExpectedKind, InterpError, InterpErrorInfo, - InterpResult, InvalidMetaKind, InvalidProgramInfo, MachineStopType, PointerKind, + InterpResult, InvalidMetaKind, InvalidProgramInfo, MachineStopType, Misalignment, PointerKind, ReportedErrorInfo, ResourceExhaustionInfo, ScalarSizeMismatch, UndefinedBehaviorInfo, UnsupportedOpInfo, ValidationErrorInfo, ValidationErrorKind, }; diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 55591938043..b01dd288c55 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -697,10 +697,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> { let this = self.eval_context_ref(); let ptr = this.read_pointer(op)?; - - let mplace = MPlaceTy::from_aligned_ptr(ptr, layout); - - Ok(mplace) + Ok(this.ptr_to_mplace(ptr, layout)) } /// Calculates the MPlaceTy given the offset and layout of an access on an operand diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index 1014a61b75e..5403d05a895 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -1370,7 +1370,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ("d_reclen", size.into()), ("d_type", file_type.into()), ], - &MPlaceTy::from_aligned_ptr(entry, dirent64_layout), + &this.ptr_to_mplace(entry, dirent64_layout), )?; let name_ptr = entry.offset(Size::from_bytes(d_name_offset), this)?; diff --git a/src/tools/miri/src/shims/unix/linux/sync.rs b/src/tools/miri/src/shims/unix/linux/sync.rs index 48ffaee56c7..17803b52baf 100644 --- a/src/tools/miri/src/shims/unix/linux/sync.rs +++ b/src/tools/miri/src/shims/unix/linux/sync.rs @@ -34,7 +34,7 @@ pub fn futex<'tcx>( let thread = this.get_active_thread(); // This is a vararg function so we have to bring our own type for this pointer. - let addr = MPlaceTy::from_aligned_ptr(addr, this.machine.layouts.i32); + let addr = this.ptr_to_mplace(addr, this.machine.layouts.i32); let addr_usize = addr.ptr().addr().bytes(); let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG"); diff --git a/src/tools/miri/src/shims/windows/sync.rs b/src/tools/miri/src/shims/windows/sync.rs index c8c8173aa51..5e46404e7f1 100644 --- a/src/tools/miri/src/shims/windows/sync.rs +++ b/src/tools/miri/src/shims/windows/sync.rs @@ -322,8 +322,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let layout = this.machine.layouts.uint(size).unwrap(); let futex_val = this - .read_scalar_atomic(&MPlaceTy::from_aligned_ptr(ptr, layout), AtomicReadOrd::Relaxed)?; - let compare_val = this.read_scalar(&MPlaceTy::from_aligned_ptr(compare, layout))?; + .read_scalar_atomic(&this.ptr_to_mplace(ptr, layout), AtomicReadOrd::Relaxed)?; + let compare_val = this.read_scalar(&this.ptr_to_mplace(compare, layout))?; if futex_val == compare_val { // If the values are the same, we have to block. diff --git a/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.rs b/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.rs new file mode 100644 index 00000000000..80a1a5dba54 --- /dev/null +++ b/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.rs @@ -0,0 +1,30 @@ +/// This tests that when a field sits at a well-aligned offset, accessing the field +/// requires high alignment even if the field type has lower alignment requirements. + +#[repr(C, align(16))] +#[derive(Default, Copy, Clone)] +pub struct Aligned { + _pad: [u8; 11], + packed: Packed, +} +#[repr(packed)] +#[derive(Default, Copy, Clone)] +pub struct Packed { + _pad: [u8; 5], + x: u8, +} + +unsafe fn foo(x: *const Aligned) -> u8 { + unsafe { (*x).packed.x } //~ERROR: accessing memory with alignment 1, but alignment 16 is required +} + +fn main() { + unsafe { + let mem = [Aligned::default(); 16]; + let odd_ptr = std::ptr::addr_of!(mem).cast::().add(1); + // `odd_ptr` is now not aligned enough for `Aligned`. + // If accessing the nested field `packed.x` can exploit that it is at offset 16 + // in a 16-aligned struct, this has to be UB. + foo(odd_ptr.cast()); + } +} diff --git a/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.stderr b/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.stderr new file mode 100644 index 00000000000..421c16880db --- /dev/null +++ b/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required + --> $DIR/field_requires_parent_struct_alignment2.rs:LL:CC + | +LL | unsafe { (*x).packed.x } + | ^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `foo` at $DIR/field_requires_parent_struct_alignment2.rs:LL:CC +note: inside `main` + --> $DIR/field_requires_parent_struct_alignment2.rs:LL:CC + | +LL | foo(odd_ptr.cast()); + | ^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/ui/const-generics/generic_const_exprs/issue-80742.rs b/tests/ui/const-generics/generic_const_exprs/issue-80742.rs index 6b2a0153f51..5f612780f39 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-80742.rs +++ b/tests/ui/const-generics/generic_const_exprs/issue-80742.rs @@ -3,6 +3,7 @@ // failure-status: 101 // normalize-stderr-test "note: .*\n\n" -> "" // normalize-stderr-test "thread 'rustc' panicked.*\n" -> "" +// normalize-stderr-test "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: " // rustc-env:RUST_BACKTRACE=0 // This test used to cause an ICE in rustc_mir::interpret::step::eval_rvalue_into_place diff --git a/tests/ui/const-generics/generic_const_exprs/issue-80742.stderr b/tests/ui/const-generics/generic_const_exprs/issue-80742.stderr index 00b8a397702..9b66fc502b7 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-80742.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-80742.stderr @@ -1,9 +1,9 @@ -error: internal compiler error: compiler/rustc_const_eval/src/interpret/step.rs:274:21: SizeOf MIR operator called for unsized type dyn Debug +error: internal compiler error: compiler/rustc_const_eval/src/interpret/step.rs:LL:CC: SizeOf MIR operator called for unsized type dyn Debug --> $SRC_DIR/core/src/mem/mod.rs:LL:COL Box query stack during panic: -#0 [eval_to_allocation_raw] const-evaluating + checking `::{constant#0}` +#0 [eval_to_allocation_raw] const-evaluating + checking `::{constant#0}` #1 [eval_to_valtree] evaluating type-level constant end of query stack error: aborting due to previous error diff --git a/tests/ui/consts/const-deref-ptr.rs b/tests/ui/consts/const-deref-ptr.rs index 4aca75e3a17..2607d4de229 100644 --- a/tests/ui/consts/const-deref-ptr.rs +++ b/tests/ui/consts/const-deref-ptr.rs @@ -3,5 +3,6 @@ fn main() { static C: u64 = unsafe {*(0xdeadbeef as *const u64)}; //~^ ERROR could not evaluate static initializer + //~| dangling pointer println!("{}", C); } diff --git a/tests/ui/consts/const-eval/raw-pointer-ub.rs b/tests/ui/consts/const-eval/raw-pointer-ub.rs index e53865309eb..e6d60414a3f 100644 --- a/tests/ui/consts/const-eval/raw-pointer-ub.rs +++ b/tests/ui/consts/const-eval/raw-pointer-ub.rs @@ -26,6 +26,17 @@ const MISALIGNED_COPY: () = unsafe { // The actual error points into the implementation of `copy_to_nonoverlapping`. }; +const MISALIGNED_FIELD: () = unsafe { + #[repr(align(16))] + struct Aligned(f32); + + let mem = [0f32; 8]; + let ptr = mem.as_ptr().cast::(); + // Accessing an f32 field but we still require the alignment of the pointer type. + let _val = (*ptr).0; //~ERROR: evaluation of constant value failed + //~^NOTE: accessing memory with alignment 4, but alignment 16 is required +}; + const OOB: () = unsafe { let mem = [0u32; 1]; let ptr = mem.as_ptr().cast::(); diff --git a/tests/ui/consts/const-eval/raw-pointer-ub.stderr b/tests/ui/consts/const-eval/raw-pointer-ub.stderr index 5055e0f881a..13e9b0d9dfe 100644 --- a/tests/ui/consts/const-eval/raw-pointer-ub.stderr +++ b/tests/ui/consts/const-eval/raw-pointer-ub.stderr @@ -26,11 +26,17 @@ LL | y.copy_to_nonoverlapping(&mut z, 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0080]: evaluation of constant value failed - --> $DIR/raw-pointer-ub.rs:32:16 + --> $DIR/raw-pointer-ub.rs:36:16 + | +LL | let _val = (*ptr).0; + | ^^^^^^^^ accessing memory with alignment 4, but alignment 16 is required + +error[E0080]: evaluation of constant value failed + --> $DIR/raw-pointer-ub.rs:43:16 | LL | let _val = *ptr; | ^^^^ memory access failed: allocN has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0080`. -- cgit 1.4.1-3-g733a5 From e24835c6e000da747b8a96ce77974783f4a9ce11 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 26 Sep 2023 16:25:05 +0200 Subject: more precise error for 'based on misaligned pointer' case --- compiler/rustc_const_eval/messages.ftl | 8 ++++++-- compiler/rustc_const_eval/src/errors.rs | 12 ++---------- compiler/rustc_const_eval/src/interpret/memory.rs | 22 ++++++++++++++++------ compiler/rustc_const_eval/src/interpret/place.rs | 14 +++++++------- .../rustc_const_eval/src/interpret/validity.rs | 2 +- compiler/rustc_middle/src/mir/interpret/error.rs | 15 ++++++++++++--- compiler/rustc_middle/src/mir/interpret/mod.rs | 11 ++++++----- src/tools/miri/tests/fail/const-ub-checks.stderr | 2 +- .../fail/dangling_pointers/out_of_bounds_read.rs | 8 ++++++++ .../dangling_pointers/out_of_bounds_read.stderr | 21 +++++++++++++++++++++ .../fail/dangling_pointers/out_of_bounds_read1.rs | 5 ----- .../dangling_pointers/out_of_bounds_read1.stderr | 21 --------------------- .../fail/dangling_pointers/out_of_bounds_read2.rs | 5 ----- .../dangling_pointers/out_of_bounds_read2.stderr | 21 --------------------- .../fail/dangling_pointers/out_of_bounds_write.rs | 7 +++++++ .../dangling_pointers/out_of_bounds_write.stderr | 21 +++++++++++++++++++++ .../tests/fail/unaligned_pointers/alignment.stderr | 4 ++-- .../field_requires_parent_struct_alignment.rs | 2 +- .../field_requires_parent_struct_alignment.stderr | 4 ++-- .../field_requires_parent_struct_alignment2.rs | 2 +- .../field_requires_parent_struct_alignment2.stderr | 4 ++-- .../intptrcast_alignment_check.rs | 2 +- .../intptrcast_alignment_check.stderr | 4 ++-- .../fail/unaligned_pointers/unaligned_ptr1.rs | 2 +- .../fail/unaligned_pointers/unaligned_ptr1.stderr | 4 ++-- .../fail/unaligned_pointers/unaligned_ptr2.rs | 2 +- .../fail/unaligned_pointers/unaligned_ptr2.stderr | 4 ++-- .../fail/unaligned_pointers/unaligned_ptr3.stderr | 4 ++-- .../fail/unaligned_pointers/unaligned_ptr4.stderr | 4 ++-- .../unaligned_pointers/unaligned_ptr_zst.stderr | 4 ++-- tests/ui/consts/const-eval/raw-pointer-ub.rs | 6 +++--- tests/ui/consts/const-eval/raw-pointer-ub.stderr | 6 +++--- tests/ui/consts/const-eval/ub-ref-ptr.stderr | 2 +- 33 files changed, 138 insertions(+), 117 deletions(-) create mode 100644 src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.rs create mode 100644 src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.stderr delete mode 100644 src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read1.rs delete mode 100644 src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read1.stderr delete mode 100644 src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read2.rs delete mode 100644 src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read2.stderr create mode 100644 src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.rs create mode 100644 src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.stderr (limited to 'src/tools/miri/tests/fail/unaligned_pointers') diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 20e0529991b..f926da464e1 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -1,11 +1,15 @@ const_eval_address_space_full = there are no more free addresses in the address space -const_eval_align_check_failed = accessing memory with alignment {$has}, but alignment {$required} is required + const_eval_align_offset_invalid_align = `align_offset` called with non-power-of-two align: {$target_align} const_eval_alignment_check_failed = - accessing memory with alignment {$has}, but alignment {$required} is required + {$msg -> + [AccessedPtr] accessing memory + *[other] accessing memory based on pointer + } with alignment {$has}, but alignment {$required} is required + const_eval_already_reported = an error has already been reported elsewhere (this should not usually be printed) const_eval_assume_false = diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 6214ce0f511..cc8f3387238 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -390,15 +390,6 @@ pub struct LiveDrop<'tcx> { pub dropped_at: Option, } -#[derive(LintDiagnostic)] -#[diag(const_eval_align_check_failed)] -pub struct AlignmentCheckFailed { - pub has: u64, - pub required: u64, - #[subdiagnostic] - pub frames: Vec, -} - #[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); diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 8b9f0ce9421..e31f4f1f697 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -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) -> InterpResult<'tcx> { + pub(super) fn check_misalign( + &self, + misaligned: Option, + msg: CheckAlignMsg, + ) -> InterpResult<'tcx> { if let Some(misaligned) = misaligned { - throw_ub!(AlignmentCheckFailed(misaligned)) + throw_ub!(AlignmentCheckFailed(misaligned, msg)) } Ok(()) } diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 240613bdff6..182da84312e 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -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(()) } diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index b8cc4e8007e..f734783af64 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -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() diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 9083c6b3cda..44b22e2d383 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -216,7 +216,7 @@ pub enum InvalidProgramInfo<'tcx> { } /// Details of why a pointer had to be in-bounds. -#[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)] +#[derive(Debug, Copy, Clone)] pub enum CheckInAllocMsg { /// We are access memory. MemoryAccessTest, @@ -228,7 +228,16 @@ pub enum CheckInAllocMsg { InboundsTest, } -#[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)] +/// Details of which pointer is not aligned. +#[derive(Debug, Copy, Clone)] +pub enum CheckAlignMsg { + /// The accessed pointer did not have proper alignment. + AccessedPtr, + /// The access ocurred with a place that was based on a misaligned pointer. + BasedOn, +} + +#[derive(Debug, Copy, Clone)] pub enum InvalidMetaKind { /// Size of a `[T]` is too big SliceTooBig, @@ -329,7 +338,7 @@ pub enum UndefinedBehaviorInfo<'tcx> { /// Using an integer as a pointer in the wrong way. DanglingIntPointer(u64, CheckInAllocMsg), /// Used a pointer with bad alignment. - AlignmentCheckFailed(Misalignment), + AlignmentCheckFailed(Misalignment, CheckAlignMsg), /// Writing to read-only memory. WriteToReadOnly(AllocId), /// Trying to access the data behind a function pointer. diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 42d58264186..e360fb3eaaf 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -142,11 +142,12 @@ use crate::ty::GenericArgKind; use crate::ty::{self, Instance, Ty, TyCtxt}; pub use self::error::{ - struct_error, BadBytesAccess, CheckInAllocMsg, ErrorHandled, EvalToAllocationRawResult, - EvalToConstValueResult, EvalToValTreeResult, ExpectedKind, InterpError, InterpErrorInfo, - InterpResult, InvalidMetaKind, InvalidProgramInfo, MachineStopType, Misalignment, PointerKind, - ReportedErrorInfo, ResourceExhaustionInfo, ScalarSizeMismatch, UndefinedBehaviorInfo, - UnsupportedOpInfo, ValidationErrorInfo, ValidationErrorKind, + struct_error, BadBytesAccess, CheckAlignMsg, CheckInAllocMsg, ErrorHandled, + EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, ExpectedKind, + InterpError, InterpErrorInfo, InterpResult, InvalidMetaKind, InvalidProgramInfo, + MachineStopType, Misalignment, PointerKind, ReportedErrorInfo, ResourceExhaustionInfo, + ScalarSizeMismatch, UndefinedBehaviorInfo, UnsupportedOpInfo, ValidationErrorInfo, + ValidationErrorKind, }; pub use self::value::Scalar; diff --git a/src/tools/miri/tests/fail/const-ub-checks.stderr b/src/tools/miri/tests/fail/const-ub-checks.stderr index d2b9018cd4b..29acc642c14 100644 --- a/src/tools/miri/tests/fail/const-ub-checks.stderr +++ b/src/tools/miri/tests/fail/const-ub-checks.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-ub-checks.rs:LL:CC | LL | ptr.read(); - | ^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | ^^^^^^^^^^ accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required note: erroneous constant encountered --> $DIR/const-ub-checks.rs:LL:CC diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.rs b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.rs new file mode 100644 index 00000000000..f6b8a1ad55b --- /dev/null +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.rs @@ -0,0 +1,8 @@ +#![feature(pointer_byte_offsets)] + +fn main() { + let v: Vec = vec![1, 2]; + // This read is also misaligned. We make sure that the OOB message has priority. + let x = unsafe { *v.as_ptr().wrapping_byte_add(5) }; //~ ERROR: out-of-bounds + panic!("this should never print: {}", x); +} diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.stderr b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.stderr new file mode 100644 index 00000000000..38d691f4c01 --- /dev/null +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.stderr @@ -0,0 +1,21 @@ +error: Undefined Behavior: memory access failed: ALLOC has size 4, so pointer to 2 bytes starting at offset 5 is out-of-bounds + --> $DIR/out_of_bounds_read.rs:LL:CC + | +LL | let x = unsafe { *v.as_ptr().wrapping_byte_add(5) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC has size 4, so pointer to 2 bytes starting at offset 5 is out-of-bounds + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: ALLOC was allocated here: + --> $DIR/out_of_bounds_read.rs:LL:CC + | +LL | let v: Vec = vec![1, 2]; + | ^^^^^^^^^^ + = note: BACKTRACE (of the first span): + = note: inside `main` at $DIR/out_of_bounds_read.rs:LL:CC + = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read1.rs b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read1.rs deleted file mode 100644 index 58a64eecace..00000000000 --- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read1.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn main() { - let v: Vec = vec![1, 2]; - let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR: out-of-bounds - panic!("this should never print: {}", x); -} diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read1.stderr b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read1.stderr deleted file mode 100644 index 46af23c74ad..00000000000 --- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read1.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error: Undefined Behavior: memory access failed: ALLOC has size 2, so pointer to 1 byte starting at offset 5 is out-of-bounds - --> $DIR/out_of_bounds_read1.rs:LL:CC - | -LL | let x = unsafe { *v.as_ptr().wrapping_offset(5) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC has size 2, so pointer to 1 byte starting at offset 5 is out-of-bounds - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information -help: ALLOC was allocated here: - --> $DIR/out_of_bounds_read1.rs:LL:CC - | -LL | let v: Vec = vec![1, 2]; - | ^^^^^^^^^^ - = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/out_of_bounds_read1.rs:LL:CC - = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read2.rs b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read2.rs deleted file mode 100644 index 58a64eecace..00000000000 --- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read2.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn main() { - let v: Vec = vec![1, 2]; - let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR: out-of-bounds - panic!("this should never print: {}", x); -} diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read2.stderr b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read2.stderr deleted file mode 100644 index 9babf50da59..00000000000 --- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read2.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error: Undefined Behavior: memory access failed: ALLOC has size 2, so pointer to 1 byte starting at offset 5 is out-of-bounds - --> $DIR/out_of_bounds_read2.rs:LL:CC - | -LL | let x = unsafe { *v.as_ptr().wrapping_offset(5) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC has size 2, so pointer to 1 byte starting at offset 5 is out-of-bounds - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information -help: ALLOC was allocated here: - --> $DIR/out_of_bounds_read2.rs:LL:CC - | -LL | let v: Vec = vec![1, 2]; - | ^^^^^^^^^^ - = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/out_of_bounds_read2.rs:LL:CC - = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.rs b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.rs new file mode 100644 index 00000000000..4ead91744c8 --- /dev/null +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.rs @@ -0,0 +1,7 @@ +#![feature(pointer_byte_offsets)] + +fn main() { + let mut v: Vec = vec![1, 2]; + // This read is also misaligned. We make sure that the OOB message has priority. + unsafe { *v.as_mut_ptr().wrapping_byte_add(5) = 0 }; //~ ERROR: out-of-bounds +} diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.stderr b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.stderr new file mode 100644 index 00000000000..9669614d47f --- /dev/null +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.stderr @@ -0,0 +1,21 @@ +error: Undefined Behavior: memory access failed: ALLOC has size 4, so pointer to 2 bytes starting at offset 5 is out-of-bounds + --> $DIR/out_of_bounds_write.rs:LL:CC + | +LL | unsafe { *v.as_mut_ptr().wrapping_byte_add(5) = 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC has size 4, so pointer to 2 bytes starting at offset 5 is out-of-bounds + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: ALLOC was allocated here: + --> $DIR/out_of_bounds_write.rs:LL:CC + | +LL | let mut v: Vec = vec![1, 2]; + | ^^^^^^^^^^ + = note: BACKTRACE (of the first span): + = note: inside `main` at $DIR/out_of_bounds_write.rs:LL:CC + = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/unaligned_pointers/alignment.stderr b/src/tools/miri/tests/fail/unaligned_pointers/alignment.stderr index bbebe3b89fd..5fdec1dc74c 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/alignment.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/alignment.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required +error: Undefined Behavior: accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required --> $DIR/alignment.rs:LL:CC | LL | *(x_ptr as *mut u32) = 42; *(x_ptr.add(1) as *mut u32) = 42; - | ^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | ^ accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment.rs b/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment.rs index fa1812adc29..114ab5479b4 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment.rs +++ b/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment.rs @@ -8,7 +8,7 @@ pub struct S { } unsafe fn foo(x: *const S) -> u8 { - unsafe { (*x).x } //~ERROR: accessing memory with alignment 1, but alignment 4 is required + unsafe { (*x).x } //~ERROR: based on pointer with alignment 1, but alignment 4 is required } fn main() { diff --git a/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment.stderr b/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment.stderr index 0f030a6e27c..2ffbc2a434e 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required +error: Undefined Behavior: accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required --> $DIR/field_requires_parent_struct_alignment.rs:LL:CC | LL | unsafe { (*x).x } - | ^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | ^^^^^^ accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.rs b/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.rs index 80a1a5dba54..8459c64ed2d 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.rs +++ b/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.rs @@ -15,7 +15,7 @@ pub struct Packed { } unsafe fn foo(x: *const Aligned) -> u8 { - unsafe { (*x).packed.x } //~ERROR: accessing memory with alignment 1, but alignment 16 is required + unsafe { (*x).packed.x } //~ERROR: based on pointer with alignment 1, but alignment 16 is required } fn main() { diff --git a/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.stderr b/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.stderr index 421c16880db..6d96c62545a 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required +error: Undefined Behavior: accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required --> $DIR/field_requires_parent_struct_alignment2.rs:LL:CC | LL | unsafe { (*x).packed.x } - | ^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | ^^^^^^^^^^^^^ accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs b/src/tools/miri/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs index ed43e552506..11f63839122 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs +++ b/src/tools/miri/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs @@ -12,6 +12,6 @@ fn main() { // Manually make sure the pointer is properly aligned. let base_addr_aligned = if base_addr % 2 == 0 { base_addr } else { base_addr + 1 }; let u16_ptr = base_addr_aligned as *mut u16; - unsafe { *u16_ptr = 2 }; //~ERROR: memory with alignment 1, but alignment 2 is required + unsafe { *u16_ptr = 2 }; //~ERROR: with alignment 1, but alignment 2 is required println!("{:?}", x); } diff --git a/src/tools/miri/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr b/src/tools/miri/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr index 392495a386d..9342b269993 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required +error: Undefined Behavior: accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required --> $DIR/intptrcast_alignment_check.rs:LL:CC | LL | unsafe { *u16_ptr = 2 }; - | ^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | ^^^^^^^^^^^^ accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required | = help: this usually indicates that your program performed an invalid operation and caused Undefined Behavior = help: but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives diff --git a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr1.rs b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr1.rs index 921bcd6ce24..9c72781ee05 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr1.rs +++ b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr1.rs @@ -7,6 +7,6 @@ fn main() { let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. let x = &x[0] as *const _ as *const u32; // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. - let _x = unsafe { *x }; //~ERROR: memory with alignment 2, but alignment 4 is required + let _x = unsafe { *x }; //~ERROR: with alignment 2, but alignment 4 is required } } diff --git a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr1.stderr b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr1.stderr index 49292be9cd1..daebabf4557 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr1.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required +error: Undefined Behavior: accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required --> $DIR/unaligned_ptr1.rs:LL:CC | LL | let _x = unsafe { *x }; - | ^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | ^^ accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr2.rs b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr2.rs index 8f597659f73..ac3062773de 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr2.rs +++ b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr2.rs @@ -8,5 +8,5 @@ fn main() { let x = (x.as_ptr() as *const u8).wrapping_offset(3) as *const u32; // This must fail because alignment is violated: the offset is not sufficiently aligned. // Also make the offset not a power of 2, that used to ICE. - let _x = unsafe { *x }; //~ERROR: memory with alignment 1, but alignment 4 is required + let _x = unsafe { *x }; //~ERROR: with alignment 1, but alignment 4 is required } diff --git a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr2.stderr b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr2.stderr index e75482f723b..38902e693dc 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr2.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required +error: Undefined Behavior: accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required --> $DIR/unaligned_ptr2.rs:LL:CC | LL | let _x = unsafe { *x }; - | ^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | ^^ accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr3.stderr b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr3.stderr index 50dd4fdfc89..36a13b63319 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr3.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr3.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required +error: Undefined Behavior: accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required --> $DIR/unaligned_ptr3.rs:LL:CC | LL | let _x = unsafe { *x }; - | ^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | ^^ accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr4.stderr b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr4.stderr index 182f3e0f876..8d7a62c3850 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr4.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr4.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required +error: Undefined Behavior: accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required --> $DIR/unaligned_ptr4.rs:LL:CC | LL | let _val = unsafe { *ptr }; - | ^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | ^^^^ accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_zst.stderr b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_zst.stderr index aa0cbe1623b..7481179f26a 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_zst.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_zst.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required +error: Undefined Behavior: accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required --> $DIR/unaligned_ptr_zst.rs:LL:CC | LL | let _x = unsafe { *x }; - | ^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | ^^ accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/ui/consts/const-eval/raw-pointer-ub.rs b/tests/ui/consts/const-eval/raw-pointer-ub.rs index e6d60414a3f..2d09b5494c6 100644 --- a/tests/ui/consts/const-eval/raw-pointer-ub.rs +++ b/tests/ui/consts/const-eval/raw-pointer-ub.rs @@ -7,14 +7,14 @@ const MISALIGNED_LOAD: () = unsafe { let mem = [0u32; 8]; let ptr = mem.as_ptr().byte_add(1); let _val = *ptr; //~ERROR: evaluation of constant value failed - //~^NOTE: accessing memory with alignment 1, but alignment 4 is required + //~^NOTE: based on pointer with alignment 1, but alignment 4 is required }; const MISALIGNED_STORE: () = unsafe { let mut mem = [0u32; 8]; let ptr = mem.as_mut_ptr().byte_add(1); *ptr = 0; //~ERROR: evaluation of constant value failed - //~^NOTE: accessing memory with alignment 1, but alignment 4 is required + //~^NOTE: based on pointer with alignment 1, but alignment 4 is required }; const MISALIGNED_COPY: () = unsafe { @@ -34,7 +34,7 @@ const MISALIGNED_FIELD: () = unsafe { let ptr = mem.as_ptr().cast::(); // Accessing an f32 field but we still require the alignment of the pointer type. let _val = (*ptr).0; //~ERROR: evaluation of constant value failed - //~^NOTE: accessing memory with alignment 4, but alignment 16 is required + //~^NOTE: based on pointer with alignment 4, but alignment 16 is required }; const OOB: () = unsafe { diff --git a/tests/ui/consts/const-eval/raw-pointer-ub.stderr b/tests/ui/consts/const-eval/raw-pointer-ub.stderr index 13e9b0d9dfe..663d49f21b4 100644 --- a/tests/ui/consts/const-eval/raw-pointer-ub.stderr +++ b/tests/ui/consts/const-eval/raw-pointer-ub.stderr @@ -2,13 +2,13 @@ error[E0080]: evaluation of constant value failed --> $DIR/raw-pointer-ub.rs:9:16 | LL | let _val = *ptr; - | ^^^^ accessing memory with alignment 1, but alignment 4 is required + | ^^^^ accessing memory based on pointer with alignment 1, but alignment 4 is required error[E0080]: evaluation of constant value failed --> $DIR/raw-pointer-ub.rs:16:5 | LL | *ptr = 0; - | ^^^^^^^^ accessing memory with alignment 1, but alignment 4 is required + | ^^^^^^^^ accessing memory based on pointer with alignment 1, but alignment 4 is required error[E0080]: evaluation of constant value failed --> $SRC_DIR/core/src/intrinsics.rs:LL:COL @@ -29,7 +29,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/raw-pointer-ub.rs:36:16 | LL | let _val = (*ptr).0; - | ^^^^^^^^ accessing memory with alignment 4, but alignment 16 is required + | ^^^^^^^^ accessing memory based on pointer with alignment 4, but alignment 16 is required error[E0080]: evaluation of constant value failed --> $DIR/raw-pointer-ub.rs:43:16 diff --git a/tests/ui/consts/const-eval/ub-ref-ptr.stderr b/tests/ui/consts/const-eval/ub-ref-ptr.stderr index 6d5c36cea7d..2144d147108 100644 --- a/tests/ui/consts/const-eval/ub-ref-ptr.stderr +++ b/tests/ui/consts/const-eval/ub-ref-ptr.stderr @@ -151,7 +151,7 @@ LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; error[E0080]: evaluation of constant value failed --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL | - = note: accessing memory with alignment 1, but alignment 4 is required + = note: accessing memory based on pointer with alignment 1, but alignment 4 is required | note: inside `std::ptr::read::` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL -- cgit 1.4.1-3-g733a5