Skip to content

Commit be6bb56

Browse files
committed
add -Zextra-const-ub-checks to enable more UB checking in const-eval
1 parent cc71eef commit be6bb56

File tree

6 files changed

+131
-0
lines changed

6 files changed

+131
-0
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/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_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,43 @@
1+
// compile-flags: -Zextra-const-ub-checks
2+
#![feature(const_ptr_read)]
3+
4+
use std::mem::transmute;
5+
6+
const INVALID_BOOL: () = unsafe {
7+
let _x: bool = transmute(3u8);
8+
//~^ ERROR: evaluation of constant value failed
9+
//~| invalid value
10+
};
11+
12+
const INVALID_PTR_IN_INT: () = unsafe {
13+
let _x: usize = transmute(&3u8);
14+
//~^ ERROR: evaluation of constant value failed
15+
//~| invalid value
16+
};
17+
18+
const INVALID_SLICE_TO_USIZE_TRANSMUTE: () = unsafe {
19+
let x: &[u8] = &[0; 32];
20+
let _x: (usize, usize) = transmute(x);
21+
//~^ ERROR: evaluation of constant value failed
22+
//~| invalid value
23+
};
24+
25+
const UNALIGNED_PTR: () = unsafe {
26+
let _x: &u32 = transmute(&[0u8; 4]);
27+
//~^ ERROR: evaluation of constant value failed
28+
//~| invalid value
29+
};
30+
31+
const UNALIGNED_READ: () = {
32+
INNER; //~ERROR any use of this value will cause an error
33+
//~| previously accepted
34+
// There is an error here but its span is in the standard library so we cannot match it...
35+
// so we have this in a *nested* const, such that the *outer* const fails to use it.
36+
const INNER: () = unsafe {
37+
let x = &[0u8; 4];
38+
let ptr = x.as_ptr().cast::<u32>();
39+
ptr.read();
40+
};
41+
};
42+
43+
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:7: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:13: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:20: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:26: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:39:9
40+
|
41+
LL | ptr.read();
42+
| ---------- inside `INNER` at $DIR/detect-extra-ub.rs:39:9
43+
44+
error: any use of this value will cause an error
45+
--> $DIR/detect-extra-ub.rs:32: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:32: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)