Skip to content

Commit e60d847

Browse files
committed
sanitizers: Add stable and unstable sanitizers
Add suppport for separating sanitizers support in stable and unstable for supported targets.
1 parent 83d0a94 commit e60d847

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+415
-176
lines changed

compiler/rustc_interface/src/tests.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,7 @@ fn test_codegen_options_tracking_hash() {
624624
tracked!(profile_generate, SwitchWithOptPath::Enabled(None));
625625
tracked!(profile_use, Some(PathBuf::from("abc")));
626626
tracked!(relocation_model, Some(RelocModel::Pic));
627+
tracked!(sanitizer, SanitizerSet::ADDRESS);
627628
tracked!(soft_float, true);
628629
tracked!(split_debuginfo, Some(SplitDebuginfo::Packed));
629630
tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0));

compiler/rustc_session/src/options.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1520,6 +1520,8 @@ options! {
15201520
"output remarks for these optimization passes (space separated, or \"all\")"),
15211521
rpath: bool = (false, parse_bool, [UNTRACKED],
15221522
"set rpath values in libs/exes (default: no)"),
1523+
sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
1524+
"use a sanitizer"),
15231525
save_temps: bool = (false, parse_bool, [UNTRACKED],
15241526
"save all temporary output files during compilation (default: no)"),
15251527
soft_float: bool = (false, parse_bool, [TRACKED],

compiler/rustc_session/src/session.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1173,7 +1173,23 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
11731173
}
11741174

11751175
// Sanitizers can only be used on platforms that we know have working sanitizer codegen.
1176-
let supported_sanitizers = sess.target.options.supported_sanitizers;
1176+
let supported_stable_sanitizers = sess.target.options.supported_sanitizers.stable_sanitizers();
1177+
let unsupported_sanitizers = sess.opts.cg.sanitizer - supported_stable_sanitizers;
1178+
match unsupported_sanitizers.into_iter().count() {
1179+
0 => {}
1180+
1 => {
1181+
sess.dcx()
1182+
.emit_err(errors::SanitizerNotSupported { us: unsupported_sanitizers.to_string() });
1183+
}
1184+
_ => {
1185+
sess.dcx().emit_err(errors::SanitizersNotSupported {
1186+
us: unsupported_sanitizers.to_string(),
1187+
});
1188+
}
1189+
}
1190+
// Allow both stable and unstable sanitizers to be used as an unstable option for backwards
1191+
// compatibility until they are all stabilized.
1192+
let supported_sanitizers = sess.target.options.supported_sanitizers.supported_sanitizers();
11771193
let unsupported_sanitizers = sess.opts.unstable_opts.sanitizer - supported_sanitizers;
11781194
match unsupported_sanitizers.into_iter().count() {
11791195
0 => {}
@@ -1188,7 +1204,8 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
11881204
}
11891205
}
11901206
// Cannot mix and match sanitizers.
1191-
let mut sanitizer_iter = sess.opts.unstable_opts.sanitizer.into_iter();
1207+
let mut sanitizer_iter =
1208+
sess.opts.cg.sanitizer.into_iter().chain(sess.opts.unstable_opts.sanitizer.into_iter());
11921209
if let (Some(first), Some(second)) = (sanitizer_iter.next(), sanitizer_iter.next()) {
11931210
sess.dcx().emit_err(errors::CannotMixAndMatchSanitizers {
11941211
first: first.to_string(),

compiler/rustc_target/src/spec/base/android.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::spec::{base, SanitizerSet, TargetOptions, TlsModel};
1+
use crate::spec::{base, SanitizerSet, SanitizerSupport, TargetOptions, TlsModel};
22

33
pub fn opts() -> TargetOptions {
44
let mut base = base::linux::opts();
@@ -7,7 +7,8 @@ pub fn opts() -> TargetOptions {
77
base.default_dwarf_version = 2;
88
base.tls_model = TlsModel::Emulated;
99
base.has_thread_local = false;
10-
base.supported_sanitizers = SanitizerSet::ADDRESS;
10+
base.supported_sanitizers =
11+
SanitizerSupport { stable: SanitizerSet::empty(), unstable: SanitizerSet::ADDRESS };
1112
// This is for backward compatibility, see https://github.com/rust-lang/rust/issues/49867
1213
// for context. (At that time, there was no `-C force-unwind-tables`, so the only solution
1314
// was to always emit `uwtable`).

compiler/rustc_target/src/spec/mod.rs

Lines changed: 83 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1290,6 +1290,43 @@ impl ToJson for SanitizerSet {
12901290
}
12911291
}
12921292

1293+
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
1294+
pub struct SanitizerSupport {
1295+
pub stable: SanitizerSet,
1296+
pub unstable: SanitizerSet,
1297+
}
1298+
1299+
impl SanitizerSupport {
1300+
/// Returns the set of stable sanitizers.
1301+
pub fn stable_sanitizers(&self) -> SanitizerSet {
1302+
self.stable
1303+
}
1304+
1305+
/// Returns the set of supported sanitizers.
1306+
pub fn supported_sanitizers(&self) -> SanitizerSet {
1307+
self.stable | self.unstable
1308+
}
1309+
1310+
/// Returns the set of unstable sanitizers.
1311+
pub fn unstable_sanitizers(&self) -> SanitizerSet {
1312+
self.unstable
1313+
}
1314+
1315+
/// Returns the set of unsupported sanitizers.
1316+
pub fn unsupported_sanitizers(&self) -> SanitizerSet {
1317+
SanitizerSet::empty() - (self.stable | self.unstable)
1318+
}
1319+
}
1320+
1321+
impl ToJson for SanitizerSupport {
1322+
fn to_json(&self) -> Json {
1323+
let mut object = serde_json::Map::new();
1324+
object.insert("stable".to_string(), self.stable.to_json());
1325+
object.insert("unstable".to_string(), self.unstable.to_json());
1326+
Json::Object(object)
1327+
}
1328+
}
1329+
12931330
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
12941331
pub enum FramePointer {
12951332
/// Forces the machine code generator to always preserve the frame pointers.
@@ -2197,7 +2234,7 @@ pub struct TargetOptions {
21972234
/// Note that the support here is at a codegen level. If the machine code with sanitizer
21982235
/// enabled can generated on this target, but the necessary supporting libraries are not
21992236
/// distributed with the target, the sanitizer should still appear in this list for the target.
2200-
pub supported_sanitizers: SanitizerSet,
2237+
pub supported_sanitizers: SanitizerSupport,
22012238

22022239
/// If present it's a default value to use for adjusting the C ABI.
22032240
pub default_adjusted_cabi: Option<Abi>,
@@ -2432,7 +2469,10 @@ impl Default for TargetOptions {
24322469
split_debuginfo: Default::default(),
24332470
// `Off` is supported by default, but targets can remove this manually, e.g. Windows.
24342471
supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
2435-
supported_sanitizers: SanitizerSet::empty(),
2472+
supported_sanitizers: SanitizerSupport {
2473+
stable: SanitizerSet::empty(),
2474+
unstable: SanitizerSet::empty(),
2475+
},
24362476
default_adjusted_cabi: None,
24372477
c_enum_min_bits: None,
24382478
generate_arange_section: true,
@@ -2623,6 +2663,35 @@ impl Target {
26232663

26242664
let mut incorrect_type = vec![];
26252665

2666+
let parse_sanitizer_set = |sanitizers_json: &Json| -> Result<SanitizerSet, String> {
2667+
let mut sanitizer_set = SanitizerSet::empty();
2668+
if let Some(sanitizers) = sanitizers_json.as_array() {
2669+
for sanitizer in sanitizers {
2670+
let name = sanitizer
2671+
.as_str()
2672+
.ok_or_else(|| "Sanitizer name must be a string".to_string())?;
2673+
sanitizer_set |= match name {
2674+
"address" => SanitizerSet::ADDRESS,
2675+
"cfi" => SanitizerSet::CFI,
2676+
"dataflow" => SanitizerSet::DATAFLOW,
2677+
"kcfi" => SanitizerSet::KCFI,
2678+
"kernel-address" => SanitizerSet::KERNELADDRESS,
2679+
"leak" => SanitizerSet::LEAK,
2680+
"memory" => SanitizerSet::MEMORY,
2681+
"memtag" => SanitizerSet::MEMTAG,
2682+
"safestack" => SanitizerSet::SAFESTACK,
2683+
"shadow-call-stack" => SanitizerSet::SHADOWCALLSTACK,
2684+
"thread" => SanitizerSet::THREAD,
2685+
"hwaddress" => SanitizerSet::HWADDRESS,
2686+
_ => return Err(format!("unknown sanitizer {}", name)),
2687+
};
2688+
}
2689+
} else {
2690+
return Err("Expected a list of sanitizers".to_string());
2691+
}
2692+
Ok(sanitizer_set)
2693+
};
2694+
26262695
macro_rules! key {
26272696
($key_name:ident) => ( {
26282697
let name = (stringify!($key_name)).replace("_", "-");
@@ -2856,32 +2925,17 @@ impl Target {
28562925
)),
28572926
}).unwrap_or(Ok(()))
28582927
} );
2859-
($key_name:ident, SanitizerSet) => ( {
2860-
let name = (stringify!($key_name)).replace("_", "-");
2861-
if let Some(o) = obj.remove(&name) {
2862-
if let Some(a) = o.as_array() {
2863-
for s in a {
2864-
base.$key_name |= match s.as_str() {
2865-
Some("address") => SanitizerSet::ADDRESS,
2866-
Some("cfi") => SanitizerSet::CFI,
2867-
Some("dataflow") => SanitizerSet::DATAFLOW,
2868-
Some("kcfi") => SanitizerSet::KCFI,
2869-
Some("kernel-address") => SanitizerSet::KERNELADDRESS,
2870-
Some("leak") => SanitizerSet::LEAK,
2871-
Some("memory") => SanitizerSet::MEMORY,
2872-
Some("memtag") => SanitizerSet::MEMTAG,
2873-
Some("safestack") => SanitizerSet::SAFESTACK,
2874-
Some("shadow-call-stack") => SanitizerSet::SHADOWCALLSTACK,
2875-
Some("thread") => SanitizerSet::THREAD,
2876-
Some("hwaddress") => SanitizerSet::HWADDRESS,
2877-
Some(s) => return Err(format!("unknown sanitizer {}", s)),
2878-
_ => return Err(format!("not a string: {:?}", s)),
2879-
};
2880-
}
2881-
} else {
2882-
incorrect_type.push(name)
2883-
}
2884-
}
2928+
($key_name:ident, SanitizerSupport) => ( {
2929+
let stable_sanitizers_json = obj.remove("stable")
2930+
.unwrap_or_else(|| serde_json::Value::Array(Vec::new()));
2931+
let unstable_sanitizers_json = obj.remove("unstable")
2932+
.unwrap_or_else(|| serde_json::Value::Array(Vec::new()));
2933+
let stable_sanitizers = parse_sanitizer_set(&stable_sanitizers_json)?;
2934+
let unstable_sanitizers = parse_sanitizer_set(&unstable_sanitizers_json)?;
2935+
base.$key_name = SanitizerSupport {
2936+
stable: stable_sanitizers,
2937+
unstable: unstable_sanitizers,
2938+
};
28852939
Ok::<(), String>(())
28862940
} );
28872941
($key_name:ident, link_self_contained_components) => ( {
@@ -3163,7 +3217,7 @@ impl Target {
31633217
key!(debuginfo_kind, DebuginfoKind)?;
31643218
key!(split_debuginfo, SplitDebuginfo)?;
31653219
key!(supported_split_debuginfo, fallible_list)?;
3166-
key!(supported_sanitizers, SanitizerSet)?;
3220+
key!(supported_sanitizers, SanitizerSupport)?;
31673221
key!(default_adjusted_cabi, Option<Abi>)?;
31683222
key!(generate_arange_section, bool);
31693223
key!(supports_stack_protector, bool);

compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::spec::base::apple::{macos_llvm_target, opts, Arch};
2-
use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
2+
use crate::spec::{FramePointer, SanitizerSet, SanitizerSupport, Target, TargetOptions};
33

44
pub fn target() -> Target {
55
let arch = Arch::Arm64;
@@ -8,7 +8,10 @@ pub fn target() -> Target {
88
base.max_atomic_width = Some(128);
99

1010
// FIXME: The leak sanitizer currently fails the tests, see #88132.
11-
base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD;
11+
base.supported_sanitizers = SanitizerSupport {
12+
stable: SanitizerSet::empty(),
13+
unstable: SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD,
14+
};
1215

1316
Target {
1417
// Clang automatically chooses a more specific target based on

compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
use crate::spec::base::apple::{ios_llvm_target, opts, Arch};
2-
use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
2+
use crate::spec::{FramePointer, SanitizerSet, SanitizerSupport, Target, TargetOptions};
33

44
pub fn target() -> Target {
55
let arch = Arch::Arm64;
66
let mut base = opts("ios", arch);
7-
base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD;
7+
base.supported_sanitizers = SanitizerSupport {
8+
stable: SanitizerSet::empty(),
9+
unstable: SanitizerSet::ADDRESS | SanitizerSet::THREAD,
10+
};
811

912
Target {
1013
// Clang automatically chooses a more specific target based on

compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
use crate::spec::base::apple::{mac_catalyst_llvm_target, opts, Arch};
2-
use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
2+
use crate::spec::{FramePointer, SanitizerSet, SanitizerSupport, Target, TargetOptions};
33

44
pub fn target() -> Target {
55
let arch = Arch::Arm64_macabi;
66
let mut base = opts("ios", arch);
7-
base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::THREAD;
7+
base.supported_sanitizers = SanitizerSupport {
8+
stable: SanitizerSet::empty(),
9+
unstable: SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::THREAD,
10+
};
811

912
Target {
1013
llvm_target: mac_catalyst_llvm_target(arch).into(),

compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
use crate::spec::base::apple::{ios_sim_llvm_target, opts, Arch};
2-
use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
2+
use crate::spec::{FramePointer, SanitizerSet, SanitizerSupport, Target, TargetOptions};
33

44
pub fn target() -> Target {
55
let arch = Arch::Arm64_sim;
66
let mut base = opts("ios", arch);
7-
base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD;
7+
base.supported_sanitizers = SanitizerSupport {
8+
stable: SanitizerSet::empty(),
9+
unstable: SanitizerSet::ADDRESS | SanitizerSet::THREAD,
10+
};
811

912
Target {
1013
// Clang automatically chooses a more specific target based on

compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
use crate::spec::base::apple::{opts, visionos_llvm_target, Arch};
2-
use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
2+
use crate::spec::{FramePointer, SanitizerSet, SanitizerSupport, Target, TargetOptions};
33

44
pub fn target() -> Target {
55
let arch = Arch::Arm64;
66
let mut base = opts("visionos", arch);
7-
base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD;
7+
base.supported_sanitizers = SanitizerSupport {
8+
stable: SanitizerSet::empty(),
9+
unstable: SanitizerSet::ADDRESS | SanitizerSet::THREAD,
10+
};
811

912
Target {
1013
llvm_target: visionos_llvm_target(arch).into(),

compiler/rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
use crate::spec::base::apple::{opts, visionos_sim_llvm_target, Arch};
2-
use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
2+
use crate::spec::{FramePointer, SanitizerSet, SanitizerSupport, Target, TargetOptions};
33

44
pub fn target() -> Target {
55
let arch = Arch::Arm64_sim;
66
let mut base = opts("visionos", arch);
7-
base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD;
7+
base.supported_sanitizers = SanitizerSupport {
8+
stable: SanitizerSet::empty(),
9+
unstable: SanitizerSet::ADDRESS | SanitizerSet::THREAD,
10+
};
811

912
Target {
1013
llvm_target: visionos_sim_llvm_target(arch).into(),

compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::spec::{base, SanitizerSet, StackProbeType, Target, TargetOptions};
1+
use crate::spec::{base, SanitizerSet, SanitizerSupport, StackProbeType, Target, TargetOptions};
22

33
// See https://developer.android.com/ndk/guides/abis.html#arm64-v8a
44
// for target ABI requirements.
@@ -21,11 +21,14 @@ pub fn target() -> Target {
2121
// the neon (ASIMD) and FP must exist on all android aarch64 targets.
2222
features: "+v8a,+neon,+fp-armv8".into(),
2323
stack_probes: StackProbeType::Inline,
24-
supported_sanitizers: SanitizerSet::CFI
25-
| SanitizerSet::HWADDRESS
26-
| SanitizerSet::MEMTAG
27-
| SanitizerSet::SHADOWCALLSTACK
28-
| SanitizerSet::ADDRESS,
24+
supported_sanitizers: SanitizerSupport {
25+
stable: SanitizerSet::empty(),
26+
unstable: SanitizerSet::ADDRESS
27+
| SanitizerSet::CFI
28+
| SanitizerSet::HWADDRESS
29+
| SanitizerSet::MEMTAG
30+
| SanitizerSet::SHADOWCALLSTACK,
31+
},
2932
supports_xray: true,
3033
..base::android::opts()
3134
},

compiler/rustc_target/src/spec/targets/aarch64_unknown_freebsd.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::spec::{base, SanitizerSet, StackProbeType, Target, TargetOptions};
1+
use crate::spec::{base, SanitizerSet, SanitizerSupport, StackProbeType, Target, TargetOptions};
22

33
pub fn target() -> Target {
44
Target {
@@ -16,10 +16,13 @@ pub fn target() -> Target {
1616
features: "+v8a".into(),
1717
max_atomic_width: Some(128),
1818
stack_probes: StackProbeType::Inline,
19-
supported_sanitizers: SanitizerSet::ADDRESS
20-
| SanitizerSet::CFI
21-
| SanitizerSet::MEMORY
22-
| SanitizerSet::THREAD,
19+
supported_sanitizers: SanitizerSupport {
20+
stable: SanitizerSet::empty(),
21+
unstable: SanitizerSet::ADDRESS
22+
| SanitizerSet::CFI
23+
| SanitizerSet::MEMORY
24+
| SanitizerSet::THREAD,
25+
},
2326
..base::freebsd::opts()
2427
},
2528
}

compiler/rustc_target/src/spec/targets/aarch64_unknown_fuchsia.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::spec::{base, SanitizerSet, StackProbeType, Target, TargetOptions};
1+
use crate::spec::{base, SanitizerSet, SanitizerSupport, StackProbeType, Target, TargetOptions};
22

33
pub fn target() -> Target {
44
Target {
@@ -16,9 +16,10 @@ pub fn target() -> Target {
1616
features: "+v8a".into(),
1717
max_atomic_width: Some(128),
1818
stack_probes: StackProbeType::Inline,
19-
supported_sanitizers: SanitizerSet::ADDRESS
20-
| SanitizerSet::CFI
21-
| SanitizerSet::SHADOWCALLSTACK,
19+
supported_sanitizers: SanitizerSupport {
20+
stable: SanitizerSet::empty(),
21+
unstable: SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::SHADOWCALLSTACK,
22+
},
2223
..base::fuchsia::opts()
2324
},
2425
}

0 commit comments

Comments
 (0)