Skip to content

Commit 8845123

Browse files
committed
Add a stable flag to control codegen UB checks
1 parent 0b475c7 commit 8845123

22 files changed

+67
-21
lines changed

compiler/rustc_interface/src/tests.rs

+1
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,7 @@ fn test_codegen_options_tracking_hash() {
607607
tracked!(profile_generate, SwitchWithOptPath::Enabled(None));
608608
tracked!(profile_use, Some(PathBuf::from("abc")));
609609
tracked!(relocation_model, Some(RelocModel::Pic));
610+
tracked!(sanitizer, Some(SanitizerSet::UNDEFINED));
610611
tracked!(soft_float, true);
611612
tracked!(split_debuginfo, Some(SplitDebuginfo::Packed));
612613
tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0));

compiler/rustc_mir_transform/src/check_alignment.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,17 @@ use rustc_middle::mir::{
99
};
1010
use rustc_middle::ty::{Ty, TyCtxt, TypeAndMut};
1111
use rustc_session::Session;
12+
use rustc_target::spec::SanitizerSet;
1213

1314
pub struct CheckAlignment;
1415

1516
impl<'tcx> MirPass<'tcx> for CheckAlignment {
1617
fn is_enabled(&self, sess: &Session) -> bool {
17-
sess.opts.debug_assertions
18+
sess.opts
19+
.cg
20+
.sanitizer
21+
.map(|san| san.contains(SanitizerSet::UNDEFINED))
22+
.unwrap_or(sess.opts.debug_assertions)
1823
}
1924

2025
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {

compiler/rustc_session/src/options.rs

+32-1
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,9 @@ mod desc {
372372
pub const parse_opt_panic_strategy: &str = parse_panic_strategy;
373373
pub const parse_oom_strategy: &str = "either `panic` or `abort`";
374374
pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
375-
pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, or `thread`";
375+
pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, `thread`, or `undefined`";
376+
pub const parse_sanitizers_stable: &str =
377+
"comma separated list of sanitizers: `none` or `undefined`";
376378
pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
377379
pub const parse_cfguard: &str =
378380
"either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
@@ -695,6 +697,7 @@ mod parse {
695697
"thread" => SanitizerSet::THREAD,
696698
"hwaddress" => SanitizerSet::HWADDRESS,
697699
"safestack" => SanitizerSet::SAFESTACK,
700+
"undefined" => SanitizerSet::UNDEFINED,
698701
_ => return false,
699702
}
700703
}
@@ -722,6 +725,32 @@ mod parse {
722725
}
723726
}
724727

728+
pub(crate) fn parse_sanitizers_stable(
729+
slot: &mut Option<SanitizerSet>,
730+
v: Option<&str>,
731+
) -> bool {
732+
if let Some(v) = v {
733+
let mut sanitizer = SanitizerSet::empty();
734+
let mut got_none = false;
735+
for s in v.split(',') {
736+
sanitizer |= match s {
737+
"none" => {
738+
got_none = true;
739+
SanitizerSet::empty()
740+
}
741+
"undefined" => SanitizerSet::UNDEFINED,
742+
_ => return false,
743+
}
744+
}
745+
if got_none {
746+
*slot = Some(SanitizerSet::empty());
747+
}
748+
} else {
749+
*slot = None;
750+
}
751+
true
752+
}
753+
725754
pub(crate) fn parse_strip(slot: &mut Strip, v: Option<&str>) -> bool {
726755
match v {
727756
Some("none") => *slot = Strip::None,
@@ -1320,6 +1349,8 @@ options! {
13201349
"print remarks for these optimization passes (space separated, or \"all\")"),
13211350
rpath: bool = (false, parse_bool, [UNTRACKED],
13221351
"set rpath values in libs/exes (default: no)"),
1352+
sanitizer: Option<SanitizerSet> = (None, parse_sanitizers_stable, [TRACKED],
1353+
"use a sanitizer"),
13231354
save_temps: bool = (false, parse_bool, [UNTRACKED],
13241355
"save all temporary output files during compilation (default: no)"),
13251356
soft_float: bool = (false, parse_bool, [TRACKED],

compiler/rustc_target/src/spec/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -906,6 +906,7 @@ bitflags::bitflags! {
906906
const KCFI = 1 << 8;
907907
const KERNELADDRESS = 1 << 9;
908908
const SAFESTACK = 1 << 10;
909+
const UNDEFINED = 1 << 11;
909910
}
910911
}
911912

@@ -926,6 +927,7 @@ impl SanitizerSet {
926927
SanitizerSet::SHADOWCALLSTACK => "shadow-call-stack",
927928
SanitizerSet::THREAD => "thread",
928929
SanitizerSet::HWADDRESS => "hwaddress",
930+
SanitizerSet::UNDEFINED => "undefined",
929931
_ => return None,
930932
})
931933
}
@@ -964,6 +966,7 @@ impl IntoIterator for SanitizerSet {
964966
SanitizerSet::HWADDRESS,
965967
SanitizerSet::KERNELADDRESS,
966968
SanitizerSet::SAFESTACK,
969+
SanitizerSet::UNDEFINED,
967970
]
968971
.iter()
969972
.copied()

src/doc/rustc/src/codegen-options/index.md

+11
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,17 @@ enabled. It takes one of the following values:
500500
* `y`, `yes`, `on`, `true` or no value: enable rpath.
501501
* `n`, `no`, `off` or `false`: disable rpath (the default).
502502

503+
## sanitizer
504+
505+
* `none`: disables all sanitizers
506+
* `undefined`
507+
508+
The only stable sanitizer is `undefined`. This flag does no do what clang/gcc's
509+
`-fsanitize=undefined` does, but it enables something generally equivalent in Rust:
510+
runtime checks for Undefined Behavior that do not require additional runtime state.
511+
512+
If not specified, `-Csanitizer=undefined` is automatically enabled by debug assertions.
513+
503514
## save-temps
504515

505516
This flag controls whether temporary files generated during compilation are

src/tools/miri/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -132,5 +132,5 @@ pub const MIRI_DEFAULT_ARGS: &[&str] = &[
132132
"-Zmir-emit-retag",
133133
"-Zmir-keep-place-mention",
134134
"-Zmir-opt-level=0",
135-
"-Zmir-enable-passes=-CheckAlignment",
135+
"-Csanitizer=none",
136136
];

src/tools/miri/tests/fail/unaligned_pointers/alignment.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
//@normalize-stderr-test: "\| +\^+" -> "| ^"
2-
//@compile-flags: -Cdebug-assertions=no
32

43
fn main() {
54
// No retry needed, this fails reliably.

src/tools/miri/tests/fail/unaligned_pointers/atomic_unaligned.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@compile-flags: -Zmiri-symbolic-alignment-check -Cdebug-assertions=no
1+
//@compile-flags: -Zmiri-symbolic-alignment-check
22
#![feature(core_intrinsics)]
33

44
fn main() {

src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.rs

-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
//@compile-flags: -Cdebug-assertions=no
2-
31
#[repr(transparent)]
42
struct HasDrop(u8);
53

src/tools/miri/tests/fail/unaligned_pointers/dyn_alignment.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// should find the bug even without validation and stacked borrows, but gets masked by optimizations
2-
//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -Zmir-opt-level=0 -Cdebug-assertions=no
2+
//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -Zmir-opt-level=0
33

44
#[repr(align(256))]
55
#[derive(Debug)]

src/tools/miri/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@compile-flags: -Zmiri-symbolic-alignment-check -Zmiri-permissive-provenance -Cdebug-assertions=no
1+
//@compile-flags: -Zmiri-symbolic-alignment-check -Zmiri-permissive-provenance
22
// With the symbolic alignment check, even with intptrcast and without
33
// validation, we want to be *sure* to catch bugs that arise from pointers being
44
// insufficiently aligned. The only way to achieve that is not to let programs

src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// This should fail even without validation/SB
2-
//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -Cdebug-assertions=no
2+
//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows
33

44
#![allow(dead_code, unused_variables)]
55

src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr1.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// This should fail even without validation or Stacked Borrows.
2-
//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -Cdebug-assertions=no
2+
//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows
33

44
fn main() {
55
// Try many times as this might work by chance.

src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr2.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// This should fail even without validation or Stacked Borrows.
2-
//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -Cdebug-assertions=no
2+
//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows
33

44
fn main() {
55
// No retry needed, this fails reliably.

src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr3.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// This should fail even without validation or Stacked Borrows.
2-
//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -Cdebug-assertions=no
2+
//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows
33

44
fn main() {
55
// Try many times as this might work by chance.

src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr4.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// This should fail even without validation or Stacked Borrows.
2-
//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -Cdebug-assertions=no
2+
//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows
33

44
fn main() {
55
// Make sure we notice when a u16 is loaded at offset 1 into a u8 allocation.

src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// This should fail even without validation or Stacked Borrows.
2-
//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -Cdebug-assertions=no
2+
//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows
33
use std::ptr;
44

55
fn main() {

src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// This should fail even without validation
22
// Some optimizations remove ZST accesses, thus masking this UB.
3-
//@compile-flags: -Zmir-opt-level=0 -Zmiri-disable-validation -Cdebug-assertions=no
3+
//@compile-flags: -Zmir-opt-level=0 -Zmiri-disable-validation
44

55
fn main() {
66
// Try many times as this might work by chance.

src/tools/miri/tests/pass/disable-alignment-check.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//@revisions: stack tree
22
//@[tree]compile-flags: -Zmiri-tree-borrows
3-
//@compile-flags: -Zmiri-disable-alignment-check -Cdebug-assertions=no
3+
//@compile-flags: -Zmiri-disable-alignment-check
44

55
fn main() {
66
let mut x = [0u8; 20];

tests/assembly/static-relocation-model.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
// revisions: x64 A64 ppc64le
22
// assembly-output: emit-asm
3+
// compile-flags: -Csanitizer=none
34
// [x64] compile-flags: --target x86_64-unknown-linux-gnu -Crelocation-model=static
45
// [x64] needs-llvm-components: x86
56
// [A64] compile-flags: --target aarch64-unknown-linux-gnu -Crelocation-model=static
67
// [A64] needs-llvm-components: aarch64
78
// [ppc64le] compile-flags: --target powerpc64le-unknown-linux-gnu -Crelocation-model=static
89
// [ppc64le] needs-llvm-components: powerpc
9-
// ignore-debug: alignment checks insert panics that we don't have a lang item for
1010

1111
#![feature(no_core, lang_items)]
1212
#![no_core]

tests/codegen/issues/issue-37945.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// compile-flags: -O -Zmerge-functions=disabled
22
// ignore-32bit LLVM has a bug with them
3-
// ignore-debug
43

54
// Check that LLVM understands that `Iter` pointer is not null. Issue #37945.
65

tests/codegen/virtual-function-elimination.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
// compile-flags: -Zvirtual-function-elimination -Clto -O -Csymbol-mangling-version=v0
1+
// compile-flags: -Zvirtual-function-elimination -Clto -O -Csymbol-mangling-version=v0 -Csanitizer=none
22
// ignore-32bit
3-
// ignore-debug
43

54
// CHECK: @vtable.0 = {{.*}}, !type ![[TYPE0:[0-9]+]], !vcall_visibility ![[VCALL_VIS0:[0-9]+]]
65
// CHECK: @vtable.1 = {{.*}}, !type ![[TYPE1:[0-9]+]], !vcall_visibility ![[VCALL_VIS0:[0-9]+]]

0 commit comments

Comments
 (0)