const-eval: improve and actually test the errors when pointers might be outside the range of a scalar

This commit is contained in:
Ralf Jung 2025-09-22 19:46:30 +02:00
parent 29005cb128
commit 0a41add629
8 changed files with 49 additions and 21 deletions

View file

@ -479,11 +479,11 @@ const_eval_validation_never_val = {$front_matter}: encountered a value of the ne
const_eval_validation_null_box = {$front_matter}: encountered a 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_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})

View file

@ -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,
@ -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);
@ -826,6 +824,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
| MutableRefToImmutable
| MutableRefInConst
| NullFnPtr
| NonnullPtrMaybeNull
| NeverVal
| UnsafeCellInImmutable
| InvalidMetaSliceTooLarge { .. }

View file

@ -819,10 +819,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(());
}

View file

@ -499,10 +499,7 @@ pub enum ValidationErrorKind<'tcx> {
MutableRefInConst,
NullFnPtr,
NeverVal,
NullablePtrOutOfRange {
range: WrappingRange,
max_value: u128,
},
NonnullPtrMaybeNull,
PtrOutOfRange {
range: WrappingRange,
max_value: u128,

View file

@ -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() {}

View file

@ -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];
@ -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 };
@ -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`.

View file

@ -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;
@ -65,5 +65,14 @@ const UNALIGNED_READ: () = unsafe {
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() {}

View file

@ -103,7 +103,7 @@ LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
HEX_DUMP
}
error[E0080]: reading memory at ALLOC3[0x%..0x%], but memory is uninitialized at [0x%..0x%], and this operation requires initialized memory
error[E0080]: reading memory at ALLOC4[0x%..0x%], but memory is uninitialized at [0x%..0x%], and this operation requires initialized memory
--> $DIR/ub-ref-ptr.rs:49:41
|
LL | const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init };
@ -124,7 +124,7 @@ LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
HEX_DUMP
}
error[E0080]: reading memory at ALLOC4[0x%..0x%], but memory is uninitialized at [0x%..0x%], and this operation requires initialized memory
error[E0080]: reading memory at ALLOC5[0x%..0x%], but memory is uninitialized at [0x%..0x%], and this operation requires initialized memory
--> $DIR/ub-ref-ptr.rs:54:38
|
LL | const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init };
@ -162,6 +162,17 @@ error[E0080]: accessing memory based on pointer with alignment 1, but alignment
LL | ptr.read();
| ^^^^^^^^^^ evaluation of `UNALIGNED_READ` failed here
error: aborting due to 15 previous errors
error[E0080]: constructing invalid value: encountered a pointer with unknown absolute address, but expected something that is definitely greater or equal to 1000
--> $DIR/ub-ref-ptr.rs:74:1
|
LL | const INVALID_VALUE_PTR: High = unsafe { mem::transmute(&S) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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 16 previous errors
For more information about this error, try `rustc --explain E0080`.