const validation: better error for maybe-null references
This commit is contained in:
parent
0a41add629
commit
8328c3dada
9 changed files with 108 additions and 29 deletions
|
|
@ -476,9 +476,15 @@ 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_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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -820,8 +820,10 @@ 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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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() {
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -541,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,
|
||||
|
|
|
|||
|
|
@ -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\))?─*╼"
|
||||
)
|
||||
.replace_all(&normalized, |caps: &Captures<'_>| {
|
||||
// Renumber the captured index.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -57,7 +62,12 @@ 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];
|
||||
|
|
|
|||
|
|
@ -42,8 +42,19 @@ LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
|
|||
HEX_DUMP
|
||||
}
|
||||
|
||||
error[E0080]: constructing invalid value: encountered a maybe-null box
|
||||
--> $DIR/ub-ref-ptr.rs:30:1
|
||||
|
|
||||
LL | const MAYBE_NULL_BOX: Box<()> = unsafe { mem::transmute({
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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[E0080]: unable to turn pointer into integer
|
||||
--> $DIR/ub-ref-ptr.rs:34:1
|
||||
--> $DIR/ub-ref-ptr.rs:39:1
|
||||
|
|
||||
LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `REF_AS_USIZE` failed here
|
||||
|
|
@ -52,7 +63,7 @@ LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
|
|||
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
|
||||
|
||||
error[E0080]: unable to turn pointer into integer
|
||||
--> $DIR/ub-ref-ptr.rs:37:39
|
||||
--> $DIR/ub-ref-ptr.rs:42:39
|
||||
|
|
||||
LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `REF_AS_USIZE_SLICE` failed here
|
||||
|
|
@ -61,13 +72,13 @@ LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
|
|||
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
|
||||
|
||||
note: erroneous constant encountered
|
||||
--> $DIR/ub-ref-ptr.rs:37:38
|
||||
--> $DIR/ub-ref-ptr.rs:42:38
|
||||
|
|
||||
LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0080]: unable to turn pointer into integer
|
||||
--> $DIR/ub-ref-ptr.rs:40:86
|
||||
--> $DIR/ub-ref-ptr.rs:45:86
|
||||
|
|
||||
LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^ evaluation of `REF_AS_USIZE_BOX_SLICE` failed here
|
||||
|
|
@ -76,13 +87,13 @@ LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[us
|
|||
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
|
||||
|
||||
note: erroneous constant encountered
|
||||
--> $DIR/ub-ref-ptr.rs:40:85
|
||||
--> $DIR/ub-ref-ptr.rs:45:85
|
||||
|
|
||||
LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0080]: constructing invalid value: encountered a dangling reference (0x539[noalloc] has no provenance)
|
||||
--> $DIR/ub-ref-ptr.rs:43:1
|
||||
--> $DIR/ub-ref-ptr.rs:48:1
|
||||
|
|
||||
LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
|
||||
|
|
@ -93,7 +104,7 @@ LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
|
|||
}
|
||||
|
||||
error[E0080]: constructing invalid value: encountered a dangling box (0x539[noalloc] has no provenance)
|
||||
--> $DIR/ub-ref-ptr.rs:46:1
|
||||
--> $DIR/ub-ref-ptr.rs:51:1
|
||||
|
|
||||
LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
|
||||
|
|
@ -103,8 +114,8 @@ LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
|
|||
HEX_DUMP
|
||||
}
|
||||
|
||||
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
|
||||
error[E0080]: reading memory at ALLOC6[0x%..0x%], but memory is uninitialized at [0x%..0x%], and this operation requires initialized memory
|
||||
--> $DIR/ub-ref-ptr.rs:54:41
|
||||
|
|
||||
LL | const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `UNINIT_PTR` failed here
|
||||
|
|
@ -114,7 +125,7 @@ LL | const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init };
|
|||
}
|
||||
|
||||
error[E0080]: constructing invalid value: encountered null pointer, but expected a function pointer
|
||||
--> $DIR/ub-ref-ptr.rs:52:1
|
||||
--> $DIR/ub-ref-ptr.rs:57:1
|
||||
|
|
||||
LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
|
||||
|
|
@ -124,8 +135,8 @@ LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
|
|||
HEX_DUMP
|
||||
}
|
||||
|
||||
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
|
||||
error[E0080]: reading memory at ALLOC7[0x%..0x%], but memory is uninitialized at [0x%..0x%], and this operation requires initialized memory
|
||||
--> $DIR/ub-ref-ptr.rs:59:38
|
||||
|
|
||||
LL | const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `UNINIT_FN_PTR` failed here
|
||||
|
|
@ -135,7 +146,7 @@ LL | const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init };
|
|||
}
|
||||
|
||||
error[E0080]: constructing invalid value: encountered 0xd[noalloc], but expected a function pointer
|
||||
--> $DIR/ub-ref-ptr.rs:56:1
|
||||
--> $DIR/ub-ref-ptr.rs:61:1
|
||||
|
|
||||
LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
|
||||
|
|
@ -145,8 +156,8 @@ LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
|
|||
HEX_DUMP
|
||||
}
|
||||
|
||||
error[E0080]: constructing invalid value: encountered ALLOC2<imm>, but expected a function pointer
|
||||
--> $DIR/ub-ref-ptr.rs:58:1
|
||||
error[E0080]: constructing invalid value: encountered ALLOC3<imm>, but expected a function pointer
|
||||
--> $DIR/ub-ref-ptr.rs:63:1
|
||||
|
|
||||
LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
|
||||
|
|
@ -156,14 +167,25 @@ LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
|
|||
HEX_DUMP
|
||||
}
|
||||
|
||||
error[E0080]: constructing invalid value: encountered ALLOC4+0xa, but expected a function pointer
|
||||
--> $DIR/ub-ref-ptr.rs:65:1
|
||||
|
|
||||
LL | const MAYBE_NULL_FN_PTR: fn() = unsafe { mem::transmute({
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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[E0080]: accessing memory based on pointer with alignment 1, but alignment 4 is required
|
||||
--> $DIR/ub-ref-ptr.rs:65:5
|
||||
--> $DIR/ub-ref-ptr.rs:75:5
|
||||
|
|
||||
LL | ptr.read();
|
||||
| ^^^^^^^^^^ evaluation of `UNALIGNED_READ` failed here
|
||||
|
||||
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
|
||||
--> $DIR/ub-ref-ptr.rs:84:1
|
||||
|
|
||||
LL | const INVALID_VALUE_PTR: High = unsafe { mem::transmute(&S) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
|
||||
|
|
@ -173,6 +195,6 @@ LL | const INVALID_VALUE_PTR: High = unsafe { mem::transmute(&S) };
|
|||
HEX_DUMP
|
||||
}
|
||||
|
||||
error: aborting due to 16 previous errors
|
||||
error: aborting due to 18 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
|
|
|
|||
16
tests/ui/consts/const_transmute_type_id7.rs
Normal file
16
tests/ui/consts/const_transmute_type_id7.rs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
//! Ensure a decent error message for maybe-null references.
|
||||
//! (see <https://github.com/rust-lang/rust/issues/146748>)
|
||||
|
||||
// Strip out raw byte dumps to make comparison platform-independent:
|
||||
//@ normalize-stderr: "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
|
||||
//@ normalize-stderr: "([0-9a-f][0-9a-f] |╾─*A(LLOC)?[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼ )+ *│.*" -> "HEX_DUMP"
|
||||
|
||||
#![feature(const_trait_impl, const_cmp)]
|
||||
|
||||
use std::any::TypeId;
|
||||
use std::mem::transmute;
|
||||
|
||||
const A: [&(); 16 / size_of::<*const ()>()] = unsafe { transmute(TypeId::of::<i32>()) };
|
||||
//~^ERROR: maybe-null
|
||||
|
||||
fn main() {}
|
||||
14
tests/ui/consts/const_transmute_type_id7.stderr
Normal file
14
tests/ui/consts/const_transmute_type_id7.stderr
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
error[E0080]: constructing invalid value at [0]: encountered a maybe-null reference
|
||||
--> $DIR/const_transmute_type_id7.rs:13:1
|
||||
|
|
||||
LL | const A: [&(); 16 / size_of::<*const ()>()] = unsafe { transmute(TypeId::of::<i32>()) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue