Skip to content

Commit ec378dc

Browse files
authored
Rollup merge of #146969 - RalfJung:maybe-null-errors, r=oli-obk
const-eval: better wording for errors involving maybe-null pointers Fixes #146748 r? ``@oli-obk``
2 parents 24e19c9 + 8328c3d commit ec378dc

File tree

11 files changed

+153
-46
lines changed

11 files changed

+153
-46
lines changed

compiler/rustc_const_eval/messages.ftl

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -476,14 +476,20 @@ const_eval_validation_invalid_vtable_trait = {$front_matter}: wrong trait in wid
476476
const_eval_validation_mutable_ref_in_const = {$front_matter}: encountered mutable reference in `const` value
477477
const_eval_validation_mutable_ref_to_immutable = {$front_matter}: encountered mutable reference or box pointing to read-only memory
478478
const_eval_validation_never_val = {$front_matter}: encountered a value of the never type `!`
479-
const_eval_validation_null_box = {$front_matter}: encountered a null box
479+
const_eval_validation_null_box = {$front_matter}: encountered a {$maybe ->
480+
[true] maybe-null
481+
*[false] null
482+
} box
480483
const_eval_validation_null_fn_ptr = {$front_matter}: encountered a null function pointer
481-
const_eval_validation_null_ref = {$front_matter}: encountered a null reference
482-
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}
484+
const_eval_validation_null_ref = {$front_matter}: encountered a {$maybe ->
485+
[true] maybe-null
486+
*[false] null
487+
} reference
488+
const_eval_validation_nonnull_ptr_out_of_range = {$front_matter}: encountered a maybe-null pointer, but expected something that is definitely non-zero
483489
const_eval_validation_out_of_range = {$front_matter}: encountered {$value}, but expected something {$in_range}
484490
const_eval_validation_partial_pointer = {$front_matter}: encountered a partial pointer or a mix of pointers
485491
const_eval_validation_pointer_as_int = {$front_matter}: encountered a pointer, but {$expected}
486-
const_eval_validation_ptr_out_of_range = {$front_matter}: encountered a pointer, but expected something that cannot possibly fail to be {$in_range}
492+
const_eval_validation_ptr_out_of_range = {$front_matter}: encountered a pointer with unknown absolute address, but expected something that is definitely {$in_range}
487493
const_eval_validation_ref_to_uninhabited = {$front_matter}: encountered a reference pointing to uninhabited type {$ty}
488494
const_eval_validation_unaligned_box = {$front_matter}: encountered an unaligned box (required {$required_bytes} byte alignment but found {$found_bytes})
489495
const_eval_validation_unaligned_ref = {$front_matter}: encountered an unaligned reference (required {$required_bytes} byte alignment but found {$found_bytes})

compiler/rustc_const_eval/src/errors.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -668,7 +668,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
668668
MutableRefInConst => const_eval_validation_mutable_ref_in_const,
669669
NullFnPtr => const_eval_validation_null_fn_ptr,
670670
NeverVal => const_eval_validation_never_val,
671-
NullablePtrOutOfRange { .. } => const_eval_validation_nullable_ptr_out_of_range,
671+
NonnullPtrMaybeNull { .. } => const_eval_validation_nonnull_ptr_out_of_range,
672672
PtrOutOfRange { .. } => const_eval_validation_ptr_out_of_range,
673673
OutOfRange { .. } => const_eval_validation_out_of_range,
674674
UnsafeCellInImmutable => const_eval_validation_unsafe_cell,
@@ -696,8 +696,8 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
696696
}
697697
UnalignedPtr { ptr_kind: PointerKind::Box, .. } => const_eval_validation_unaligned_box,
698698

699-
NullPtr { ptr_kind: PointerKind::Box } => const_eval_validation_null_box,
700-
NullPtr { ptr_kind: PointerKind::Ref(_) } => const_eval_validation_null_ref,
699+
NullPtr { ptr_kind: PointerKind::Box, .. } => const_eval_validation_null_box,
700+
NullPtr { ptr_kind: PointerKind::Ref(_), .. } => const_eval_validation_null_ref,
701701
DanglingPtrNoProvenance { ptr_kind: PointerKind::Box, .. } => {
702702
const_eval_validation_dangling_box_no_provenance
703703
}
@@ -804,9 +804,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
804804
| InvalidFnPtr { value } => {
805805
err.arg("value", value);
806806
}
807-
NullablePtrOutOfRange { range, max_value } | PtrOutOfRange { range, max_value } => {
808-
add_range_arg(range, max_value, err)
809-
}
807+
PtrOutOfRange { range, max_value } => add_range_arg(range, max_value, err),
810808
OutOfRange { range, max_value, value } => {
811809
err.arg("value", value);
812810
add_range_arg(range, max_value, err);
@@ -822,10 +820,13 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
822820
err.arg("vtable_dyn_type", vtable_dyn_type.to_string());
823821
err.arg("expected_dyn_type", expected_dyn_type.to_string());
824822
}
825-
NullPtr { .. }
826-
| MutableRefToImmutable
823+
NullPtr { maybe, .. } => {
824+
err.arg("maybe", maybe);
825+
}
826+
MutableRefToImmutable
827827
| MutableRefInConst
828828
| NullFnPtr
829+
| NonnullPtrMaybeNull
829830
| NeverVal
830831
| UnsafeCellInImmutable
831832
| InvalidMetaSliceTooLarge { .. }

compiler/rustc_const_eval/src/interpret/validity.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
511511
CheckInAllocMsg::Dereferenceable, // will anyway be replaced by validity message
512512
),
513513
self.path,
514-
Ub(DanglingIntPointer { addr: 0, .. }) => NullPtr { ptr_kind },
514+
Ub(DanglingIntPointer { addr: 0, .. }) => NullPtr { ptr_kind, maybe: false },
515515
Ub(DanglingIntPointer { addr: i, .. }) => DanglingPtrNoProvenance {
516516
ptr_kind,
517517
// 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> {
538538
);
539539
// Make sure this is non-null. We checked dereferenceability above, but if `size` is zero
540540
// that does not imply non-null.
541-
if self.ecx.scalar_may_be_null(Scalar::from_maybe_pointer(place.ptr(), self.ecx))? {
542-
throw_validation_failure!(self.path, NullPtr { ptr_kind })
541+
let scalar = Scalar::from_maybe_pointer(place.ptr(), self.ecx);
542+
if self.ecx.scalar_may_be_null(scalar)? {
543+
let maybe = !M::Provenance::OFFSET_IS_ADDR && matches!(scalar, Scalar::Ptr(..));
544+
throw_validation_failure!(self.path, NullPtr { ptr_kind, maybe })
543545
}
544546
// Do not allow references to uninhabited types.
545547
if place.layout.is_uninhabited() {
@@ -757,6 +759,11 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
757759
} else {
758760
// Otherwise (for standalone Miri), we have to still check it to be non-null.
759761
if self.ecx.scalar_may_be_null(scalar)? {
762+
let maybe =
763+
!M::Provenance::OFFSET_IS_ADDR && matches!(scalar, Scalar::Ptr(..));
764+
// This can't be a "maybe-null" pointer since the check for this being
765+
// a fn ptr at all already ensures that the pointer is inbounds.
766+
assert!(!maybe);
760767
throw_validation_failure!(self.path, NullFnPtr);
761768
}
762769
}
@@ -819,10 +826,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
819826
if start == 1 && end == max_value {
820827
// Only null is the niche. So make sure the ptr is NOT null.
821828
if self.ecx.scalar_may_be_null(scalar)? {
822-
throw_validation_failure!(
823-
self.path,
824-
NullablePtrOutOfRange { range: valid_range, max_value }
825-
)
829+
throw_validation_failure!(self.path, NonnullPtrMaybeNull)
826830
} else {
827831
return interp_ok(());
828832
}

compiler/rustc_middle/src/mir/interpret/error.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -499,10 +499,7 @@ pub enum ValidationErrorKind<'tcx> {
499499
MutableRefInConst,
500500
NullFnPtr,
501501
NeverVal,
502-
NullablePtrOutOfRange {
503-
range: WrappingRange,
504-
max_value: u128,
505-
},
502+
NonnullPtrMaybeNull,
506503
PtrOutOfRange {
507504
range: WrappingRange,
508505
max_value: u128,
@@ -544,6 +541,8 @@ pub enum ValidationErrorKind<'tcx> {
544541
},
545542
NullPtr {
546543
ptr_kind: PointerKind,
544+
/// Records whether this pointer is definitely null or just may be null.
545+
maybe: bool,
547546
},
548547
DanglingPtrNoProvenance {
549548
ptr_kind: PointerKind,

src/tools/compiletest/src/runtest.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2663,7 +2663,7 @@ impl<'test> TestCx<'test> {
26632663

26642664
// The alloc-id appears in pretty-printed allocations.
26652665
normalized = static_regex!(
2666-
r"╾─*a(lloc)?([0-9]+)(\+0x[0-9]+)?(<imm>)?( \([0-9]+ ptr bytes\))?─*╼"
2666+
r"╾─*a(lloc)?([0-9]+)(\+0x[0-9a-f]+)?(<imm>)?( \([0-9]+ ptr bytes\))?─*╼"
26672667
)
26682668
.replace_all(&normalized, |caps: &Captures<'_>| {
26692669
// Renumber the captured index.

tests/ui/consts/const-eval/ub-nonnull.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,8 @@ const NULL_FAT_PTR: NonNull<dyn Send> = unsafe {
5757
mem::transmute((0_usize, meta))
5858
};
5959

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

tests/ui/consts/const-eval/ub-nonnull.stderr

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) };
99
HEX_DUMP
1010
}
1111

12-
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
12+
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
1313
--> $DIR/ub-nonnull.rs:22:29
1414
|
1515
LL | let out_of_bounds_ptr = &ptr[255];
@@ -37,7 +37,7 @@ LL | const NULL_USIZE: NonZero<usize> = unsafe { mem::transmute(0usize) };
3737
HEX_DUMP
3838
}
3939

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

83-
error: aborting due to 8 previous errors
83+
error[E0080]: constructing invalid value: encountered a maybe-null pointer, but expected something that is definitely non-zero
84+
--> $DIR/ub-nonnull.rs:61:1
85+
|
86+
LL | const MAYBE_NULL_PTR: NonNull<()> = unsafe { mem::transmute((&raw const S).wrapping_add(4)) };
87+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
88+
|
89+
= 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.
90+
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
91+
HEX_DUMP
92+
}
93+
94+
error: aborting due to 9 previous errors
8495

8596
For more information about this error, try `rustc --explain E0080`.

tests/ui/consts/const-eval/ub-ref-ptr.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
//@ normalize-stderr: "([0-9a-f][0-9a-f] |__ |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼ )+ *│.*" -> "HEX_DUMP"
55
//@ dont-require-annotations: NOTE
66
//@ normalize-stderr: "0x[0-9](\.\.|\])" -> "0x%$1"
7-
7+
#![feature(rustc_attrs)]
88
#![allow(invalid_value)]
99

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

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

3136
// It is very important that we reject this: We do promote `&(4 * REF_AS_USIZE)`,
3237
// but that would fail to compile; so we ended up breaking user code that would
@@ -57,13 +62,27 @@ const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
5762
//~^ ERROR invalid value
5863
const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
5964
//~^ ERROR invalid value
60-
65+
const MAYBE_NULL_FN_PTR: fn() = unsafe { mem::transmute({
66+
//~^ ERROR invalid value
67+
fn fun() {}
68+
let ptr = fun as fn();
69+
(ptr as *const u8).wrapping_add(10)
70+
}) };
6171

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

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

6988
fn main() {}

0 commit comments

Comments
 (0)