Skip to content

Commit 706aa59

Browse files
Rollup merge of #97185 - RalfJung:number-validity, r=oli-obk
interpret/validity: separately control checking numbers for being init and non-ptr This lets Miri control this in a more fine-grained way. r? `@oli-obk`
2 parents 62569ed + 4bb152c commit 706aa59

20 files changed

+75
-54
lines changed

compiler/rustc_const_eval/src/interpret/machine.rs

+11-4
Original file line numberDiff line numberDiff line change
@@ -133,9 +133,11 @@ pub trait Machine<'mir, 'tcx>: Sized {
133133
/// Whether to enforce the validity invariant
134134
fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
135135

136-
/// Whether to enforce validity (e.g., initialization and not having ptr provenance)
137-
/// of integers and floats.
138-
fn enforce_number_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
136+
/// Whether to enforce integers and floats being initialized.
137+
fn enforce_number_init(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
138+
139+
/// Whether to enforce integers and floats not having provenance.
140+
fn enforce_number_no_provenance(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
139141

140142
/// Whether function calls should be [ABI](Abi)-checked.
141143
fn enforce_abi(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
@@ -453,7 +455,12 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
453455
}
454456

455457
#[inline(always)]
456-
fn enforce_number_validity(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
458+
fn enforce_number_init(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
459+
true
460+
}
461+
462+
#[inline(always)]
463+
fn enforce_number_no_provenance(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
457464
true
458465
}
459466

compiler/rustc_const_eval/src/interpret/memory.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -924,10 +924,15 @@ impl<'tcx, 'a, Tag: Provenance, Extra> AllocRef<'a, 'tcx, Tag, Extra> {
924924
self.read_scalar(alloc_range(offset, self.tcx.data_layout().pointer_size))
925925
}
926926

927-
pub fn check_bytes(&self, range: AllocRange, allow_uninit_and_ptr: bool) -> InterpResult<'tcx> {
927+
pub fn check_bytes(
928+
&self,
929+
range: AllocRange,
930+
allow_uninit: bool,
931+
allow_ptr: bool,
932+
) -> InterpResult<'tcx> {
928933
Ok(self
929934
.alloc
930-
.check_bytes(&self.tcx, self.range.subrange(range), allow_uninit_and_ptr)
935+
.check_bytes(&self.tcx, self.range.subrange(range), allow_uninit, allow_ptr)
931936
.map_err(|e| e.to_interp_error(self.alloc_id))?)
932937
}
933938
}

compiler/rustc_const_eval/src/interpret/validity.rs

+15-9
Original file line numberDiff line numberDiff line change
@@ -536,15 +536,21 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
536536
let value = self.read_scalar(value)?;
537537
// NOTE: Keep this in sync with the array optimization for int/float
538538
// types below!
539-
if M::enforce_number_validity(self.ecx) {
540-
// Integers/floats with number validity: Must be scalar bits, pointers are dangerous.
539+
if M::enforce_number_init(self.ecx) {
540+
try_validation!(
541+
value.check_init(),
542+
self.path,
543+
err_ub!(InvalidUninitBytes(..)) =>
544+
{ "{:x}", value } expected { "initialized bytes" }
545+
);
546+
}
547+
if M::enforce_number_no_provenance(self.ecx) {
541548
// As a special exception we *do* match on a `Scalar` here, since we truly want
542549
// to know its underlying representation (and *not* cast it to an integer).
543-
let is_bits =
544-
value.check_init().map_or(false, |v| matches!(v, Scalar::Int(..)));
545-
if !is_bits {
550+
let is_ptr = value.check_init().map_or(false, |v| matches!(v, Scalar::Ptr(..)));
551+
if is_ptr {
546552
throw_validation_failure!(self.path,
547-
{ "{:x}", value } expected { "initialized plain (non-pointer) bytes" }
553+
{ "{:x}", value } expected { "plain (non-pointer) bytes" }
548554
)
549555
}
550556
}
@@ -651,7 +657,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
651657
let size = scalar_layout.size(self.ecx);
652658
let is_full_range = match scalar_layout {
653659
ScalarAbi::Initialized { .. } => {
654-
if M::enforce_number_validity(self.ecx) {
660+
if M::enforce_number_init(self.ecx) {
655661
false // not "full" since uninit is not accepted
656662
} else {
657663
scalar_layout.is_always_valid(self.ecx)
@@ -910,10 +916,10 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
910916
return Ok(());
911917
};
912918

913-
let allow_uninit_and_ptr = !M::enforce_number_validity(self.ecx);
914919
match alloc.check_bytes(
915920
alloc_range(Size::ZERO, size),
916-
allow_uninit_and_ptr,
921+
/*allow_uninit*/ !M::enforce_number_init(self.ecx),
922+
/*allow_ptr*/ !M::enforce_number_no_provenance(self.ecx),
917923
) {
918924
// In the happy case, we needn't check anything else.
919925
Ok(()) => {}

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

+7-4
Original file line numberDiff line numberDiff line change
@@ -350,19 +350,22 @@ impl<Tag: Provenance, Extra> Allocation<Tag, Extra> {
350350
/// Reading and writing.
351351
impl<Tag: Provenance, Extra> Allocation<Tag, Extra> {
352352
/// Validates that `ptr.offset` and `ptr.offset + size` do not point to the middle of a
353-
/// relocation. If `allow_uninit_and_ptr` is `false`, also enforces that the memory in the
354-
/// given range contains neither relocations nor uninitialized bytes.
353+
/// relocation. If `allow_uninit`/`allow_ptr` is `false`, also enforces that the memory in the
354+
/// given range contains no uninitialized bytes/relocations.
355355
pub fn check_bytes(
356356
&self,
357357
cx: &impl HasDataLayout,
358358
range: AllocRange,
359-
allow_uninit_and_ptr: bool,
359+
allow_uninit: bool,
360+
allow_ptr: bool,
360361
) -> AllocResult {
361362
// Check bounds and relocations on the edges.
362363
self.get_bytes_with_uninit_and_ptr(cx, range)?;
363364
// Check uninit and ptr.
364-
if !allow_uninit_and_ptr {
365+
if !allow_uninit {
365366
self.check_init(range)?;
367+
}
368+
if !allow_ptr {
366369
self.check_relocations(cx, range)?;
367370
}
368371
Ok(())

src/test/ui/consts/const-err4.32bit.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
22
--> $DIR/const-err4.rs:9:11
33
|
44
LL | Boo = [unsafe { Foo { b: () }.a }; 4][3],
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized bytes
66
|
77
= 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.
88
= note: the raw bytes of the constant (size: 4, align: 4) {

src/test/ui/consts/const-err4.64bit.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
22
--> $DIR/const-err4.rs:9:11
33
|
44
LL | Boo = [unsafe { Foo { b: () }.a }; 4][3],
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized bytes
66
|
77
= 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.
88
= note: the raw bytes of the constant (size: 8, align: 8) {

src/test/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr

+9-9
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
22
--> $DIR/const-pointer-values-in-various-types.rs:26:5
33
|
44
LL | const I32_REF_USIZE_UNION: usize = unsafe { Nonsense { int_32_ref: &3 }.u };
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc3, but expected initialized plain (non-pointer) bytes
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc3, but expected plain (non-pointer) bytes
66
|
77
= 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.
88
= note: the raw bytes of the constant (size: 8, align: 8) {
@@ -47,7 +47,7 @@ error[E0080]: it is undefined behavior to use this value
4747
--> $DIR/const-pointer-values-in-various-types.rs:41:5
4848
|
4949
LL | const I32_REF_U64_UNION: u64 = unsafe { Nonsense { int_32_ref: &3 }.uint_64 };
50-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc19, but expected initialized plain (non-pointer) bytes
50+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc19, but expected plain (non-pointer) bytes
5151
|
5252
= 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.
5353
= note: the raw bytes of the constant (size: 8, align: 8) {
@@ -58,7 +58,7 @@ error[E0080]: it is undefined behavior to use this value
5858
--> $DIR/const-pointer-values-in-various-types.rs:44:5
5959
|
6060
LL | const I32_REF_U128_UNION: u128 = unsafe { Nonsense { int_32_ref: &3 }.uint_128 };
61-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes
61+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized bytes
6262
|
6363
= 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.
6464
= note: the raw bytes of the constant (size: 16, align: 8) {
@@ -102,7 +102,7 @@ error[E0080]: it is undefined behavior to use this value
102102
--> $DIR/const-pointer-values-in-various-types.rs:59:5
103103
|
104104
LL | const I32_REF_I64_UNION: i64 = unsafe { Nonsense { int_32_ref: &3 }.int_64 };
105-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc39, but expected initialized plain (non-pointer) bytes
105+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc39, but expected plain (non-pointer) bytes
106106
|
107107
= 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.
108108
= note: the raw bytes of the constant (size: 8, align: 8) {
@@ -113,7 +113,7 @@ error[E0080]: it is undefined behavior to use this value
113113
--> $DIR/const-pointer-values-in-various-types.rs:62:5
114114
|
115115
LL | const I32_REF_I128_UNION: i128 = unsafe { Nonsense { int_32_ref: &3 }.int_128 };
116-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes
116+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized bytes
117117
|
118118
= 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.
119119
= note: the raw bytes of the constant (size: 16, align: 8) {
@@ -135,7 +135,7 @@ error[E0080]: it is undefined behavior to use this value
135135
--> $DIR/const-pointer-values-in-various-types.rs:69:5
136136
|
137137
LL | const I32_REF_F64_UNION: f64 = unsafe { Nonsense { int_32_ref: &3 }.float_64 };
138-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc51, but expected initialized plain (non-pointer) bytes
138+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc51, but expected plain (non-pointer) bytes
139139
|
140140
= 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.
141141
= note: the raw bytes of the constant (size: 8, align: 8) {
@@ -201,7 +201,7 @@ error[E0080]: it is undefined behavior to use this value
201201
--> $DIR/const-pointer-values-in-various-types.rs:92:5
202202
|
203203
LL | const STR_U64_UNION: u64 = unsafe { Nonsense { stringy: "3" }.uint_64 };
204-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc72, but expected initialized plain (non-pointer) bytes
204+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc72, but expected plain (non-pointer) bytes
205205
|
206206
= 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.
207207
= note: the raw bytes of the constant (size: 8, align: 8) {
@@ -256,7 +256,7 @@ error[E0080]: it is undefined behavior to use this value
256256
--> $DIR/const-pointer-values-in-various-types.rs:111:5
257257
|
258258
LL | const STR_I64_UNION: i64 = unsafe { Nonsense { stringy: "3" }.int_64 };
259-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc87, but expected initialized plain (non-pointer) bytes
259+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc87, but expected plain (non-pointer) bytes
260260
|
261261
= 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.
262262
= note: the raw bytes of the constant (size: 8, align: 8) {
@@ -289,7 +289,7 @@ error[E0080]: it is undefined behavior to use this value
289289
--> $DIR/const-pointer-values-in-various-types.rs:122:5
290290
|
291291
LL | const STR_F64_UNION: f64 = unsafe { Nonsense { stringy: "3" }.float_64 };
292-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc96, but expected initialized plain (non-pointer) bytes
292+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc96, but expected plain (non-pointer) bytes
293293
|
294294
= 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.
295295
= note: the raw bytes of the constant (size: 8, align: 8) {

src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
22
--> $DIR/alloc_intrinsic_uninit.rs:8:1
33
|
44
LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) };
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered uninitialized bytes, but expected initialized bytes
66
|
77
= 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.
88
= note: the raw bytes of the constant (size: 4, align: 4) {

src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
22
--> $DIR/alloc_intrinsic_uninit.rs:8:1
33
|
44
LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) };
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered uninitialized bytes, but expected initialized bytes
66
|
77
= 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.
88
= note: the raw bytes of the constant (size: 8, align: 8) {

src/test/ui/consts/const-eval/ref_to_int_match.32bit.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
22
--> $DIR/ref_to_int_match.rs:25:1
33
|
44
LL | const BAR: Int = unsafe { Foo { r: &42 }.f };
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc3, but expected initialized plain (non-pointer) bytes
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc3, but expected plain (non-pointer) bytes
66
|
77
= 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.
88
= note: the raw bytes of the constant (size: 4, align: 4) {

src/test/ui/consts/const-eval/ref_to_int_match.64bit.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
22
--> $DIR/ref_to_int_match.rs:25:1
33
|
44
LL | const BAR: Int = unsafe { Foo { r: &42 }.f };
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc3, but expected initialized plain (non-pointer) bytes
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc3, but expected plain (non-pointer) bytes
66
|
77
= 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.
88
= note: the raw bytes of the constant (size: 8, align: 8) {

src/test/ui/consts/const-eval/ub-enum-overwrite.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ LL | | let p = if let E::A(x) = &mut e { x as *mut u8 } else { unreachable!(
88
... |
99
LL | | unsafe { *p }
1010
LL | | };
11-
| |__^ type validation failed: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes
11+
| |__^ type validation failed: encountered uninitialized bytes, but expected initialized bytes
1212
|
1313
= 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.
1414
= note: the raw bytes of the constant (size: 1, align: 1) {

0 commit comments

Comments
 (0)