Skip to content

Commit 392ba5f

Browse files
authoredAug 12, 2022
Rollup merge of #100229 - RalfJung:extra-const-ub-checks, r=lcnr
add -Zextra-const-ub-checks to enable more UB checking in const-eval Cc #99923 r? `@oli-obk`
2 parents 51eed00 + 2bd9479 commit 392ba5f

File tree

8 files changed

+145
-12
lines changed

8 files changed

+145
-12
lines changed
 

‎compiler/rustc_const_eval/src/const_eval/machine.rs

+10
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,16 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
236236

237237
const PANIC_ON_ALLOC_FAIL: bool = false; // will be raised as a proper error
238238

239+
#[inline(always)]
240+
fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
241+
ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks
242+
}
243+
244+
#[inline(always)]
245+
fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
246+
ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks
247+
}
248+
239249
fn load_mir(
240250
ecx: &InterpCx<'mir, 'tcx, Self>,
241251
instance: ty::InstanceDef<'tcx>,

‎compiler/rustc_const_eval/src/interpret/machine.rs

-12
Original file line numberDiff line numberDiff line change
@@ -436,24 +436,12 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
436436
type AllocExtra = ();
437437
type FrameExtra = ();
438438

439-
#[inline(always)]
440-
fn enforce_alignment(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
441-
// We do not check for alignment to avoid having to carry an `Align`
442-
// in `ConstValue::ByRef`.
443-
false
444-
}
445-
446439
#[inline(always)]
447440
fn force_int_for_alignment_check(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
448441
// We do not support `force_int`.
449442
false
450443
}
451444

452-
#[inline(always)]
453-
fn enforce_validity(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
454-
false // for now, we don't enforce validity
455-
}
456-
457445
#[inline(always)]
458446
fn enforce_number_init(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
459447
true

‎compiler/rustc_const_eval/src/interpret/validity.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1005,6 +1005,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
10051005
/// It will error if the bits at the destination do not match the ones described by the layout.
10061006
#[inline(always)]
10071007
pub fn validate_operand(&self, op: &OpTy<'tcx, M::Provenance>) -> InterpResult<'tcx> {
1008+
// Note that we *could* actually be in CTFE here with `-Zextra-const-ub-checks`, but it's
1009+
// still correct to not use `ctfe_mode`: that mode is for validation of the final constant
1010+
// value, it rules out things like `UnsafeCell` in awkward places. It also can make checking
1011+
// recurse through references which, for now, we don't want here, either.
10081012
self.validate_operand_internal(op, vec![], None, None)
10091013
}
10101014
}

‎compiler/rustc_mir_transform/src/const_prop.rs

+12
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,18 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
183183

184184
type MemoryKind = !;
185185

186+
#[inline(always)]
187+
fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
188+
// We do not check for alignment to avoid having to carry an `Align`
189+
// in `ConstValue::ByRef`.
190+
false
191+
}
192+
193+
#[inline(always)]
194+
fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
195+
false // for now, we don't enforce validity
196+
}
197+
186198
fn load_mir(
187199
_ecx: &InterpCx<'mir, 'tcx, Self>,
188200
_instance: ty::InstanceDef<'tcx>,

‎compiler/rustc_session/src/options.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1310,6 +1310,8 @@ options! {
13101310
"emit the bc module with thin LTO info (default: yes)"),
13111311
export_executable_symbols: bool = (false, parse_bool, [TRACKED],
13121312
"export symbols from executables, as if they were dynamic libraries"),
1313+
extra_const_ub_checks: bool = (false, parse_bool, [TRACKED],
1314+
"turns on more checks to detect const UB, which can be slow (default: no)"),
13131315
#[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::fewer_names` instead of this field"))]
13141316
fewer_names: Option<bool> = (None, parse_opt_bool, [TRACKED],
13151317
"reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \

‎src/test/rustdoc-ui/z-help.stdout

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
-Z emit-stack-sizes=val -- emit a section containing stack size metadata (default: no)
3939
-Z emit-thin-lto=val -- emit the bc module with thin LTO info (default: yes)
4040
-Z export-executable-symbols=val -- export symbols from executables, as if they were dynamic libraries
41+
-Z extra-const-ub-checks=val -- turns on more checks to detect const UB, which can be slow (default: no)
4142
-Z fewer-names=val -- reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) (default: no)
4243
-Z force-unstable-if-unmarked=val -- force all crates to be `rustc_private` unstable (default: no)
4344
-Z fuel=val -- set the optimization fuel quota for a crate
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// revisions: no_flag with_flag
2+
// [no_flag] check-pass
3+
// [with_flag] compile-flags: -Zextra-const-ub-checks
4+
#![feature(const_ptr_read)]
5+
6+
use std::mem::transmute;
7+
8+
const INVALID_BOOL: () = unsafe {
9+
let _x: bool = transmute(3u8);
10+
//[with_flag]~^ ERROR: evaluation of constant value failed
11+
//[with_flag]~| invalid value
12+
};
13+
14+
const INVALID_PTR_IN_INT: () = unsafe {
15+
let _x: usize = transmute(&3u8);
16+
//[with_flag]~^ ERROR: evaluation of constant value failed
17+
//[with_flag]~| invalid value
18+
};
19+
20+
const INVALID_SLICE_TO_USIZE_TRANSMUTE: () = unsafe {
21+
let x: &[u8] = &[0; 32];
22+
let _x: (usize, usize) = transmute(x);
23+
//[with_flag]~^ ERROR: evaluation of constant value failed
24+
//[with_flag]~| invalid value
25+
};
26+
27+
const UNALIGNED_PTR: () = unsafe {
28+
let _x: &u32 = transmute(&[0u8; 4]);
29+
//[with_flag]~^ ERROR: evaluation of constant value failed
30+
//[with_flag]~| invalid value
31+
};
32+
33+
const UNALIGNED_READ: () = {
34+
INNER; //[with_flag]~ERROR any use of this value will cause an error
35+
//[with_flag]~| previously accepted
36+
// There is an error here but its span is in the standard library so we cannot match it...
37+
// so we have this in a *nested* const, such that the *outer* const fails to use it.
38+
const INNER: () = unsafe {
39+
let x = &[0u8; 4];
40+
let ptr = x.as_ptr().cast::<u32>();
41+
ptr.read();
42+
};
43+
};
44+
45+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
error[E0080]: evaluation of constant value failed
2+
--> $DIR/detect-extra-ub.rs:9:20
3+
|
4+
LL | let _x: bool = transmute(3u8);
5+
| ^^^^^^^^^^^^^^ constructing invalid value: encountered 0x03, but expected a boolean
6+
7+
error[E0080]: evaluation of constant value failed
8+
--> $DIR/detect-extra-ub.rs:15:21
9+
|
10+
LL | let _x: usize = transmute(&3u8);
11+
| ^^^^^^^^^^^^^^^ constructing invalid value: encountered (potentially part of) a pointer, but expected plain (non-pointer) bytes
12+
13+
error[E0080]: evaluation of constant value failed
14+
--> $DIR/detect-extra-ub.rs:22:30
15+
|
16+
LL | let _x: (usize, usize) = transmute(x);
17+
| ^^^^^^^^^^^^ constructing invalid value at .0: encountered (potentially part of) a pointer, but expected plain (non-pointer) bytes
18+
19+
error[E0080]: evaluation of constant value failed
20+
--> $DIR/detect-extra-ub.rs:28:20
21+
|
22+
LL | let _x: &u32 = transmute(&[0u8; 4]);
23+
| ^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 4 byte alignment but found 1)
24+
25+
error[E0080]: evaluation of constant value failed
26+
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
27+
|
28+
LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
29+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
30+
| |
31+
| accessing memory with alignment 1, but alignment 4 is required
32+
| inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
33+
|
34+
::: $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
35+
|
36+
LL | unsafe { read(self) }
37+
| ---------- inside `ptr::const_ptr::<impl *const u32>::read` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
38+
|
39+
::: $DIR/detect-extra-ub.rs:41:9
40+
|
41+
LL | ptr.read();
42+
| ---------- inside `INNER` at $DIR/detect-extra-ub.rs:41:9
43+
44+
error: any use of this value will cause an error
45+
--> $DIR/detect-extra-ub.rs:34:5
46+
|
47+
LL | const UNALIGNED_READ: () = {
48+
| ------------------------
49+
LL | INNER;
50+
| ^^^^^ referenced constant has errors
51+
|
52+
= note: `#[deny(const_err)]` on by default
53+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
54+
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
55+
56+
error: aborting due to 6 previous errors
57+
58+
For more information about this error, try `rustc --explain E0080`.
59+
Future incompatibility report: Future breakage diagnostic:
60+
error: any use of this value will cause an error
61+
--> $DIR/detect-extra-ub.rs:34:5
62+
|
63+
LL | const UNALIGNED_READ: () = {
64+
| ------------------------
65+
LL | INNER;
66+
| ^^^^^ referenced constant has errors
67+
|
68+
= note: `#[deny(const_err)]` on by default
69+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
70+
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
71+

0 commit comments

Comments
 (0)
Please sign in to comment.