Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions compiler/rustc_const_eval/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -476,14 +476,20 @@ const_eval_validation_invalid_vtable_trait = {$front_matter}: wrong trait in wid
const_eval_validation_mutable_ref_in_const = {$front_matter}: encountered mutable reference in `const` value
const_eval_validation_mutable_ref_to_immutable = {$front_matter}: encountered mutable reference or box pointing to read-only memory
const_eval_validation_never_val = {$front_matter}: encountered a value of the never type `!`
const_eval_validation_null_box = {$front_matter}: encountered a null box
const_eval_validation_null_box = {$front_matter}: encountered a {$maybe ->
[true] maybe-null
*[false] null
} box
const_eval_validation_null_fn_ptr = {$front_matter}: encountered a null function pointer
const_eval_validation_null_ref = {$front_matter}: encountered a null reference
const_eval_validation_nullable_ptr_out_of_range = {$front_matter}: encountered a potentially null pointer, but expected something that cannot possibly fail to be {$in_range}
const_eval_validation_null_ref = {$front_matter}: encountered a {$maybe ->
[true] maybe-null
*[false] null
} reference
const_eval_validation_nonnull_ptr_out_of_range = {$front_matter}: encountered a maybe-null pointer, but expected something that is definitely non-zero
const_eval_validation_out_of_range = {$front_matter}: encountered {$value}, but expected something {$in_range}
const_eval_validation_partial_pointer = {$front_matter}: encountered a partial pointer or a mix of pointers
const_eval_validation_pointer_as_int = {$front_matter}: encountered a pointer, but {$expected}
const_eval_validation_ptr_out_of_range = {$front_matter}: encountered a pointer, but expected something that cannot possibly fail to be {$in_range}
const_eval_validation_ptr_out_of_range = {$front_matter}: encountered a pointer with unknown absolute address, but expected something that is definitely {$in_range}
const_eval_validation_ref_to_uninhabited = {$front_matter}: encountered a reference pointing to uninhabited type {$ty}
const_eval_validation_unaligned_box = {$front_matter}: encountered an unaligned box (required {$required_bytes} byte alignment but found {$found_bytes})
const_eval_validation_unaligned_ref = {$front_matter}: encountered an unaligned reference (required {$required_bytes} byte alignment but found {$found_bytes})
Expand Down
17 changes: 9 additions & 8 deletions compiler/rustc_const_eval/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -668,7 +668,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
MutableRefInConst => const_eval_validation_mutable_ref_in_const,
NullFnPtr => const_eval_validation_null_fn_ptr,
NeverVal => const_eval_validation_never_val,
NullablePtrOutOfRange { .. } => const_eval_validation_nullable_ptr_out_of_range,
NonnullPtrMaybeNull { .. } => const_eval_validation_nonnull_ptr_out_of_range,
PtrOutOfRange { .. } => const_eval_validation_ptr_out_of_range,
OutOfRange { .. } => const_eval_validation_out_of_range,
UnsafeCellInImmutable => const_eval_validation_unsafe_cell,
Expand Down Expand Up @@ -696,8 +696,8 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
}
UnalignedPtr { ptr_kind: PointerKind::Box, .. } => const_eval_validation_unaligned_box,

NullPtr { ptr_kind: PointerKind::Box } => const_eval_validation_null_box,
NullPtr { ptr_kind: PointerKind::Ref(_) } => const_eval_validation_null_ref,
NullPtr { ptr_kind: PointerKind::Box, .. } => const_eval_validation_null_box,
NullPtr { ptr_kind: PointerKind::Ref(_), .. } => const_eval_validation_null_ref,
DanglingPtrNoProvenance { ptr_kind: PointerKind::Box, .. } => {
const_eval_validation_dangling_box_no_provenance
}
Expand Down Expand Up @@ -804,9 +804,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
| InvalidFnPtr { value } => {
err.arg("value", value);
}
NullablePtrOutOfRange { range, max_value } | PtrOutOfRange { range, max_value } => {
add_range_arg(range, max_value, err)
}
PtrOutOfRange { range, max_value } => add_range_arg(range, max_value, err),
OutOfRange { range, max_value, value } => {
err.arg("value", value);
add_range_arg(range, max_value, err);
Expand All @@ -822,10 +820,13 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
err.arg("vtable_dyn_type", vtable_dyn_type.to_string());
err.arg("expected_dyn_type", expected_dyn_type.to_string());
}
NullPtr { .. }
| MutableRefToImmutable
NullPtr { maybe, .. } => {
err.arg("maybe", maybe);
}
MutableRefToImmutable
| MutableRefInConst
| NullFnPtr
| NonnullPtrMaybeNull
| NeverVal
| UnsafeCellInImmutable
| InvalidMetaSliceTooLarge { .. }
Expand Down
18 changes: 11 additions & 7 deletions compiler/rustc_const_eval/src/interpret/validity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
CheckInAllocMsg::Dereferenceable, // will anyway be replaced by validity message
),
self.path,
Ub(DanglingIntPointer { addr: 0, .. }) => NullPtr { ptr_kind },
Ub(DanglingIntPointer { addr: 0, .. }) => NullPtr { ptr_kind, maybe: false },
Ub(DanglingIntPointer { addr: i, .. }) => DanglingPtrNoProvenance {
ptr_kind,
// FIXME this says "null pointer" when null but we need translate
Expand All @@ -538,8 +538,10 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
);
// Make sure this is non-null. We checked dereferenceability above, but if `size` is zero
// that does not imply non-null.
if self.ecx.scalar_may_be_null(Scalar::from_maybe_pointer(place.ptr(), self.ecx))? {
throw_validation_failure!(self.path, NullPtr { ptr_kind })
let scalar = Scalar::from_maybe_pointer(place.ptr(), self.ecx);
if self.ecx.scalar_may_be_null(scalar)? {
let maybe = !M::Provenance::OFFSET_IS_ADDR && matches!(scalar, Scalar::Ptr(..));
throw_validation_failure!(self.path, NullPtr { ptr_kind, maybe })
}
// Do not allow references to uninhabited types.
if place.layout.is_uninhabited() {
Expand Down Expand Up @@ -757,6 +759,11 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
} else {
// Otherwise (for standalone Miri), we have to still check it to be non-null.
if self.ecx.scalar_may_be_null(scalar)? {
let maybe =
!M::Provenance::OFFSET_IS_ADDR && matches!(scalar, Scalar::Ptr(..));
// This can't be a "maybe-null" pointer since the check for this being
// a fn ptr at all already ensures that the pointer is inbounds.
assert!(!maybe);
throw_validation_failure!(self.path, NullFnPtr);
}
}
Expand Down Expand Up @@ -819,10 +826,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
if start == 1 && end == max_value {
// Only null is the niche. So make sure the ptr is NOT null.
if self.ecx.scalar_may_be_null(scalar)? {
throw_validation_failure!(
self.path,
NullablePtrOutOfRange { range: valid_range, max_value }
)
throw_validation_failure!(self.path, NonnullPtrMaybeNull)
} else {
return interp_ok(());
}
Expand Down
7 changes: 3 additions & 4 deletions compiler/rustc_middle/src/mir/interpret/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -499,10 +499,7 @@ pub enum ValidationErrorKind<'tcx> {
MutableRefInConst,
NullFnPtr,
NeverVal,
NullablePtrOutOfRange {
range: WrappingRange,
max_value: u128,
},
NonnullPtrMaybeNull,
PtrOutOfRange {
range: WrappingRange,
max_value: u128,
Expand Down Expand Up @@ -544,6 +541,8 @@ pub enum ValidationErrorKind<'tcx> {
},
NullPtr {
ptr_kind: PointerKind,
/// Records whether this pointer is definitely null or just may be null.
maybe: bool,
},
DanglingPtrNoProvenance {
ptr_kind: PointerKind,
Expand Down
2 changes: 1 addition & 1 deletion src/tools/compiletest/src/runtest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2655,7 +2655,7 @@ impl<'test> TestCx<'test> {

// The alloc-id appears in pretty-printed allocations.
normalized = static_regex!(
r"╾─*a(lloc)?([0-9]+)(\+0x[0-9]+)?(<imm>)?( \([0-9]+ ptr bytes\))?─*╼"
r"╾─*a(lloc)?([0-9]+)(\+0x[0-9a-f]+)?(<imm>)?( \([0-9]+ ptr bytes\))?─*╼"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type_id7 test uncovered that our alloc ID normalization regex doesn't properly handle hex offsets.

)
.replace_all(&normalized, |caps: &Captures<'_>| {
// Renumber the captured index.
Expand Down
4 changes: 4 additions & 0 deletions tests/ui/consts/const-eval/ub-nonnull.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,8 @@ const NULL_FAT_PTR: NonNull<dyn Send> = unsafe {
mem::transmute((0_usize, meta))
};

static S: u32 = 0; // just a static to construct a maybe-null pointer off of
const MAYBE_NULL_PTR: NonNull<()> = unsafe { mem::transmute((&raw const S).wrapping_add(4)) };
//~^ ERROR invalid value

fn main() {}
17 changes: 14 additions & 3 deletions tests/ui/consts/const-eval/ub-nonnull.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) };
HEX_DUMP
}

error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by 255 bytes, but got ALLOC1 which is only 1 byte from the end of the allocation
error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by 255 bytes, but got ALLOC2 which is only 1 byte from the end of the allocation
--> $DIR/ub-nonnull.rs:22:29
|
LL | let out_of_bounds_ptr = &ptr[255];
Expand Down Expand Up @@ -37,7 +37,7 @@ LL | const NULL_USIZE: NonZero<usize> = unsafe { mem::transmute(0usize) };
HEX_DUMP
}

error[E0080]: reading memory at ALLOC2[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory
error[E0080]: reading memory at ALLOC3[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory
--> $DIR/ub-nonnull.rs:36:38
|
LL | const UNINIT: NonZero<u8> = unsafe { MaybeUninit { uninit: () }.init };
Expand Down Expand Up @@ -80,6 +80,17 @@ LL | const NULL_FAT_PTR: NonNull<dyn Send> = unsafe {
HEX_DUMP
}

error: aborting due to 8 previous errors
error[E0080]: constructing invalid value: encountered a maybe-null pointer, but expected something that is definitely non-zero
--> $DIR/ub-nonnull.rs:61:1
|
LL | const MAYBE_NULL_PTR: NonNull<()> = unsafe { mem::transmute((&raw const S).wrapping_add(4)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
|
= note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
HEX_DUMP
}

error: aborting due to 9 previous errors

For more information about this error, try `rustc --explain E0080`.
23 changes: 21 additions & 2 deletions tests/ui/consts/const-eval/ub-ref-ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//@ normalize-stderr: "([0-9a-f][0-9a-f] |__ |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼ )+ *│.*" -> "HEX_DUMP"
//@ dont-require-annotations: NOTE
//@ normalize-stderr: "0x[0-9](\.\.|\])" -> "0x%$1"

#![feature(rustc_attrs)]
#![allow(invalid_value)]

use std::mem;
Expand All @@ -27,6 +27,11 @@ const NULL: &u16 = unsafe { mem::transmute(0usize) };
const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
//~^ ERROR invalid value

const MAYBE_NULL_BOX: Box<()> = unsafe { mem::transmute({
//~^ ERROR maybe-null
let ref_ = &0u8;
(ref_ as *const u8).wrapping_add(10)
}) };

// It is very important that we reject this: We do promote `&(4 * REF_AS_USIZE)`,
// but that would fail to compile; so we ended up breaking user code that would
Expand Down Expand Up @@ -57,13 +62,27 @@ const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
//~^ ERROR invalid value
const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
//~^ ERROR invalid value

const MAYBE_NULL_FN_PTR: fn() = unsafe { mem::transmute({
//~^ ERROR invalid value
fn fun() {}
let ptr = fun as fn();
(ptr as *const u8).wrapping_add(10)
}) };

const UNALIGNED_READ: () = unsafe {
let x = &[0u8; 4];
let ptr = x.as_ptr().cast::<u32>();
ptr.read(); //~ ERROR accessing memory
};

// Check the general case of a pointer value not falling into the scalar valid range.
#[rustc_layout_scalar_valid_range_start(1000)]
pub struct High {
pointer: *const (),
}
static S: u32 = 0; // just a static to construct a pointer with unknown absolute address
const INVALID_VALUE_PTR: High = unsafe { mem::transmute(&S) };
//~^ ERROR invalid value


fn main() {}
Loading
Loading