about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2022-08-07 08:30:03 -0400
committerRalf Jung <post@ralfj.de>2022-08-07 09:54:40 -0400
commitbe6bb56ee0c88353a01675c4cc525020f1d3137a (patch)
treec049cd79befa17f6a8ac5e1ad7824bf9d1c1941a
parentcc71eef498a24af884c4ffa288101a73447bfc61 (diff)
downloadrust-be6bb56ee0c88353a01675c4cc525020f1d3137a.tar.gz
rust-be6bb56ee0c88353a01675c4cc525020f1d3137a.zip
add -Zextra-const-ub-checks to enable more UB checking in const-eval
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs10
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs4
-rw-r--r--compiler/rustc_session/src/options.rs2
-rw-r--r--src/test/rustdoc-ui/z-help.stdout1
-rw-r--r--src/test/ui/consts/extra-const-ub/detect-extra-ub.rs43
-rw-r--r--src/test/ui/consts/extra-const-ub/detect-extra-ub.stderr71
6 files changed, 131 insertions, 0 deletions
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index fc2e6652a3d..684877cae76 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -236,6 +236,16 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
 
     const PANIC_ON_ALLOC_FAIL: bool = false; // will be raised as a proper error
 
+    #[inline(always)]
+    fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
+        ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks
+    }
+
+    #[inline(always)]
+    fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
+        ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks
+    }
+
     fn load_mir(
         ecx: &InterpCx<'mir, 'tcx, Self>,
         instance: ty::InstanceDef<'tcx>,
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index 6f6717721fb..f1b1855c3ec 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -1005,6 +1005,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// It will error if the bits at the destination do not match the ones described by the layout.
     #[inline(always)]
     pub fn validate_operand(&self, op: &OpTy<'tcx, M::Provenance>) -> InterpResult<'tcx> {
+        // Note that we *could* actually be in CTFE here with `-Zextra-const-ub-checks`, but it's
+        // still correct to not use `ctfe_mode`: that mode is for validation of the final constant
+        // value, it rules out things like `UnsafeCell` in awkward places. It also can make checking
+        // recurse through references which, for now, we don't want here, either.
         self.validate_operand_internal(op, vec![], None, None)
     }
 }
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 1827f1c208d..0032dd7d113 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1310,6 +1310,8 @@ options! {
         "emit the bc module with thin LTO info (default: yes)"),
     export_executable_symbols: bool = (false, parse_bool, [TRACKED],
         "export symbols from executables, as if they were dynamic libraries"),
+    extra_const_ub_checks: bool = (false, parse_bool, [TRACKED],
+        "turns on more checks to detect const UB, which can be slow (default: no)"),
     #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::fewer_names` instead of this field"))]
     fewer_names: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \
diff --git a/src/test/rustdoc-ui/z-help.stdout b/src/test/rustdoc-ui/z-help.stdout
index 6dc41231559..236469ce979 100644
--- a/src/test/rustdoc-ui/z-help.stdout
+++ b/src/test/rustdoc-ui/z-help.stdout
@@ -38,6 +38,7 @@
     -Z                        emit-stack-sizes=val -- emit a section containing stack size metadata (default: no)
     -Z                           emit-thin-lto=val -- emit the bc module with thin LTO info (default: yes)
     -Z               export-executable-symbols=val -- export symbols from executables, as if they were dynamic libraries
+    -Z                   extra-const-ub-checks=val -- turns on more checks to detect const UB, which can be slow (default: no)
     -Z                             fewer-names=val -- reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) (default: no)
     -Z              force-unstable-if-unmarked=val -- force all crates to be `rustc_private` unstable (default: no)
     -Z                                    fuel=val -- set the optimization fuel quota for a crate
diff --git a/src/test/ui/consts/extra-const-ub/detect-extra-ub.rs b/src/test/ui/consts/extra-const-ub/detect-extra-ub.rs
new file mode 100644
index 00000000000..ebbe315b8f8
--- /dev/null
+++ b/src/test/ui/consts/extra-const-ub/detect-extra-ub.rs
@@ -0,0 +1,43 @@
+// compile-flags: -Zextra-const-ub-checks
+#![feature(const_ptr_read)]
+
+use std::mem::transmute;
+
+const INVALID_BOOL: () = unsafe {
+    let _x: bool = transmute(3u8);
+    //~^ ERROR: evaluation of constant value failed
+    //~| invalid value
+};
+
+const INVALID_PTR_IN_INT: () = unsafe {
+    let _x: usize = transmute(&3u8);
+    //~^ ERROR: evaluation of constant value failed
+    //~| invalid value
+};
+
+const INVALID_SLICE_TO_USIZE_TRANSMUTE: () = unsafe {
+    let x: &[u8] = &[0; 32];
+    let _x: (usize, usize) = transmute(x);
+    //~^ ERROR: evaluation of constant value failed
+    //~| invalid value
+};
+
+const UNALIGNED_PTR: () = unsafe {
+    let _x: &u32 = transmute(&[0u8; 4]);
+    //~^ ERROR: evaluation of constant value failed
+    //~| invalid value
+};
+
+const UNALIGNED_READ: () = {
+    INNER; //~ERROR any use of this value will cause an error
+    //~| previously accepted
+    // There is an error here but its span is in the standard library so we cannot match it...
+    // so we have this in a *nested* const, such that the *outer* const fails to use it.
+    const INNER: () = unsafe {
+        let x = &[0u8; 4];
+        let ptr = x.as_ptr().cast::<u32>();
+        ptr.read();
+    };
+};
+
+fn main() {}
diff --git a/src/test/ui/consts/extra-const-ub/detect-extra-ub.stderr b/src/test/ui/consts/extra-const-ub/detect-extra-ub.stderr
new file mode 100644
index 00000000000..66634f3dd56
--- /dev/null
+++ b/src/test/ui/consts/extra-const-ub/detect-extra-ub.stderr
@@ -0,0 +1,71 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/detect-extra-ub.rs:7:20
+   |
+LL |     let _x: bool = transmute(3u8);
+   |                    ^^^^^^^^^^^^^^ constructing invalid value: encountered 0x03, but expected a boolean
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/detect-extra-ub.rs:13:21
+   |
+LL |     let _x: usize = transmute(&3u8);
+   |                     ^^^^^^^^^^^^^^^ constructing invalid value: encountered (potentially part of) a pointer, but expected plain (non-pointer) bytes
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/detect-extra-ub.rs:20:30
+   |
+LL |     let _x: (usize, usize) = transmute(x);
+   |                              ^^^^^^^^^^^^ constructing invalid value at .0: encountered (potentially part of) a pointer, but expected plain (non-pointer) bytes
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/detect-extra-ub.rs:26:20
+   |
+LL |     let _x: &u32 = transmute(&[0u8; 4]);
+   |                    ^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 4 byte alignment but found 1)
+
+error[E0080]: evaluation of constant value failed
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+   |
+LL |         copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         accessing memory with alignment 1, but alignment 4 is required
+   |         inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+   |
+  ::: $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+LL |         unsafe { read(self) }
+   |                  ---------- inside `ptr::const_ptr::<impl *const u32>::read` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+  ::: $DIR/detect-extra-ub.rs:39:9
+   |
+LL |         ptr.read();
+   |         ---------- inside `INNER` at $DIR/detect-extra-ub.rs:39:9
+
+error: any use of this value will cause an error
+  --> $DIR/detect-extra-ub.rs:32:5
+   |
+LL | const UNALIGNED_READ: () = {
+   | ------------------------
+LL |     INNER;
+   |     ^^^^^ referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/detect-extra-ub.rs:32:5
+   |
+LL | const UNALIGNED_READ: () = {
+   | ------------------------
+LL |     INNER;
+   |     ^^^^^ referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+