Skip to content

Commit ef8dd4a

Browse files
committed
sanitizers: Add stable and unstable sanitizers
Add suppport for separating sanitizers support in stable and unstable for supported targets.
1 parent 00ed4ed commit ef8dd4a

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

+418
-176
lines changed

compiler/rustc_interface/src/tests.rs

+1
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,7 @@ fn test_codegen_options_tracking_hash() {
623623
tracked!(profile_use, Some(PathBuf::from("abc")));
624624
tracked!(relocation_model, Some(RelocModel::Pic));
625625
tracked!(relro_level, Some(RelroLevel::Full));
626+
tracked!(sanitizer, SanitizerSet::ADDRESS);
626627
tracked!(soft_float, true);
627628
tracked!(split_debuginfo, Some(SplitDebuginfo::Packed));
628629
tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0));

compiler/rustc_session/src/options.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1540,6 +1540,8 @@ options! {
15401540
"output remarks for these optimization passes (space separated, or \"all\")"),
15411541
rpath: bool = (false, parse_bool, [UNTRACKED],
15421542
"set rpath values in libs/exes (default: no)"),
1543+
sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
1544+
"use a sanitizer"),
15431545
save_temps: bool = (false, parse_bool, [UNTRACKED],
15441546
"save all temporary output files during compilation (default: no)"),
15451547
soft_float: bool = (false, parse_bool, [TRACKED],

compiler/rustc_session/src/session.rs

+19-2
Original file line numberDiff line numberDiff line change
@@ -1163,7 +1163,23 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
11631163
}
11641164

11651165
// Sanitizers can only be used on platforms that we know have working sanitizer codegen.
1166-
let supported_sanitizers = sess.target.options.supported_sanitizers;
1166+
let supported_stable_sanitizers = sess.target.options.supported_sanitizers.stable_sanitizers();
1167+
let unsupported_sanitizers = sess.opts.cg.sanitizer - supported_stable_sanitizers;
1168+
match unsupported_sanitizers.into_iter().count() {
1169+
0 => {}
1170+
1 => {
1171+
sess.dcx()
1172+
.emit_err(errors::SanitizerNotSupported { us: unsupported_sanitizers.to_string() });
1173+
}
1174+
_ => {
1175+
sess.dcx().emit_err(errors::SanitizersNotSupported {
1176+
us: unsupported_sanitizers.to_string(),
1177+
});
1178+
}
1179+
}
1180+
// Allow both stable and unstable sanitizers to be used as an unstable option for backwards
1181+
// compatibility until they are all stabilized.
1182+
let supported_sanitizers = sess.target.options.supported_sanitizers.supported_sanitizers();
11671183
let unsupported_sanitizers = sess.opts.unstable_opts.sanitizer - supported_sanitizers;
11681184
match unsupported_sanitizers.into_iter().count() {
11691185
0 => {}
@@ -1178,7 +1194,8 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
11781194
}
11791195
}
11801196
// Cannot mix and match sanitizers.
1181-
let mut sanitizer_iter = sess.opts.unstable_opts.sanitizer.into_iter();
1197+
let mut sanitizer_iter =
1198+
sess.opts.cg.sanitizer.into_iter().chain(sess.opts.unstable_opts.sanitizer.into_iter());
11821199
if let (Some(first), Some(second)) = (sanitizer_iter.next(), sanitizer_iter.next()) {
11831200
sess.dcx().emit_err(errors::CannotMixAndMatchSanitizers {
11841201
first: first.to_string(),

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

+3-2
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

+86-29
Original file line numberDiff line numberDiff line change
@@ -1364,6 +1364,46 @@ impl ToJson for SanitizerSet {
13641364
}
13651365
}
13661366

1367+
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
1368+
/// Sanitizers supported by a target.
1369+
pub struct SanitizerSupport {
1370+
/// Sanitizers supported by a target that can be used on stable.
1371+
pub stable: SanitizerSet,
1372+
/// Sanitizers supported by a target that cannot be used on stable.
1373+
pub unstable: SanitizerSet,
1374+
}
1375+
1376+
impl SanitizerSupport {
1377+
/// Returns the set of stable sanitizers.
1378+
pub fn stable_sanitizers(&self) -> SanitizerSet {
1379+
self.stable
1380+
}
1381+
1382+
/// Returns the set of supported sanitizers.
1383+
pub fn supported_sanitizers(&self) -> SanitizerSet {
1384+
self.stable | self.unstable
1385+
}
1386+
1387+
/// Returns the set of unstable sanitizers.
1388+
pub fn unstable_sanitizers(&self) -> SanitizerSet {
1389+
self.unstable
1390+
}
1391+
1392+
/// Returns the set of unsupported sanitizers.
1393+
pub fn unsupported_sanitizers(&self) -> SanitizerSet {
1394+
SanitizerSet::empty() - (self.stable | self.unstable)
1395+
}
1396+
}
1397+
1398+
impl ToJson for SanitizerSupport {
1399+
fn to_json(&self) -> Json {
1400+
let mut object = serde_json::Map::new();
1401+
object.insert("stable".to_string(), self.stable.to_json());
1402+
object.insert("unstable".to_string(), self.unstable.to_json());
1403+
Json::Object(object)
1404+
}
1405+
}
1406+
13671407
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
13681408
pub enum FramePointer {
13691409
/// Forces the machine code generator to always preserve the frame pointers.
@@ -2271,7 +2311,7 @@ pub struct TargetOptions {
22712311
/// Note that the support here is at a codegen level. If the machine code with sanitizer
22722312
/// enabled can generated on this target, but the necessary supporting libraries are not
22732313
/// distributed with the target, the sanitizer should still appear in this list for the target.
2274-
pub supported_sanitizers: SanitizerSet,
2314+
pub supported_sanitizers: SanitizerSupport,
22752315

22762316
/// If present it's a default value to use for adjusting the C ABI.
22772317
pub default_adjusted_cabi: Option<Abi>,
@@ -2506,7 +2546,10 @@ impl Default for TargetOptions {
25062546
split_debuginfo: Default::default(),
25072547
// `Off` is supported by default, but targets can remove this manually, e.g. Windows.
25082548
supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
2509-
supported_sanitizers: SanitizerSet::empty(),
2549+
supported_sanitizers: SanitizerSupport {
2550+
stable: SanitizerSet::empty(),
2551+
unstable: SanitizerSet::empty(),
2552+
},
25102553
default_adjusted_cabi: None,
25112554
c_enum_min_bits: None,
25122555
generate_arange_section: true,
@@ -2697,6 +2740,35 @@ impl Target {
26972740

26982741
let mut incorrect_type = vec![];
26992742

2743+
let parse_sanitizer_set = |sanitizers_json: &Json| -> Result<SanitizerSet, String> {
2744+
let mut sanitizer_set = SanitizerSet::empty();
2745+
if let Some(sanitizers) = sanitizers_json.as_array() {
2746+
for sanitizer in sanitizers {
2747+
let name = sanitizer
2748+
.as_str()
2749+
.ok_or_else(|| "Sanitizer name must be a string".to_string())?;
2750+
sanitizer_set |= match name {
2751+
"address" => SanitizerSet::ADDRESS,
2752+
"cfi" => SanitizerSet::CFI,
2753+
"dataflow" => SanitizerSet::DATAFLOW,
2754+
"kcfi" => SanitizerSet::KCFI,
2755+
"kernel-address" => SanitizerSet::KERNELADDRESS,
2756+
"leak" => SanitizerSet::LEAK,
2757+
"memory" => SanitizerSet::MEMORY,
2758+
"memtag" => SanitizerSet::MEMTAG,
2759+
"safestack" => SanitizerSet::SAFESTACK,
2760+
"shadow-call-stack" => SanitizerSet::SHADOWCALLSTACK,
2761+
"thread" => SanitizerSet::THREAD,
2762+
"hwaddress" => SanitizerSet::HWADDRESS,
2763+
_ => return Err(format!("unknown sanitizer {}", name)),
2764+
};
2765+
}
2766+
} else {
2767+
return Err("Expected a list of sanitizers".to_string());
2768+
}
2769+
Ok(sanitizer_set)
2770+
};
2771+
27002772
macro_rules! key {
27012773
($key_name:ident) => ( {
27022774
let name = (stringify!($key_name)).replace("_", "-");
@@ -2930,32 +3002,17 @@ impl Target {
29303002
)),
29313003
}).unwrap_or(Ok(()))
29323004
} );
2933-
($key_name:ident, SanitizerSet) => ( {
2934-
let name = (stringify!($key_name)).replace("_", "-");
2935-
if let Some(o) = obj.remove(&name) {
2936-
if let Some(a) = o.as_array() {
2937-
for s in a {
2938-
base.$key_name |= match s.as_str() {
2939-
Some("address") => SanitizerSet::ADDRESS,
2940-
Some("cfi") => SanitizerSet::CFI,
2941-
Some("dataflow") => SanitizerSet::DATAFLOW,
2942-
Some("kcfi") => SanitizerSet::KCFI,
2943-
Some("kernel-address") => SanitizerSet::KERNELADDRESS,
2944-
Some("leak") => SanitizerSet::LEAK,
2945-
Some("memory") => SanitizerSet::MEMORY,
2946-
Some("memtag") => SanitizerSet::MEMTAG,
2947-
Some("safestack") => SanitizerSet::SAFESTACK,
2948-
Some("shadow-call-stack") => SanitizerSet::SHADOWCALLSTACK,
2949-
Some("thread") => SanitizerSet::THREAD,
2950-
Some("hwaddress") => SanitizerSet::HWADDRESS,
2951-
Some(s) => return Err(format!("unknown sanitizer {}", s)),
2952-
_ => return Err(format!("not a string: {:?}", s)),
2953-
};
2954-
}
2955-
} else {
2956-
incorrect_type.push(name)
2957-
}
2958-
}
3005+
($key_name:ident, SanitizerSupport) => ( {
3006+
let stable_sanitizers_json = obj.remove("stable")
3007+
.unwrap_or_else(|| serde_json::Value::Array(Vec::new()));
3008+
let unstable_sanitizers_json = obj.remove("unstable")
3009+
.unwrap_or_else(|| serde_json::Value::Array(Vec::new()));
3010+
let stable_sanitizers = parse_sanitizer_set(&stable_sanitizers_json)?;
3011+
let unstable_sanitizers = parse_sanitizer_set(&unstable_sanitizers_json)?;
3012+
base.$key_name = SanitizerSupport {
3013+
stable: stable_sanitizers,
3014+
unstable: unstable_sanitizers,
3015+
};
29593016
Ok::<(), String>(())
29603017
} );
29613018
($key_name:ident, link_self_contained_components) => ( {
@@ -3237,7 +3294,7 @@ impl Target {
32373294
key!(debuginfo_kind, DebuginfoKind)?;
32383295
key!(split_debuginfo, SplitDebuginfo)?;
32393296
key!(supported_split_debuginfo, fallible_list)?;
3240-
key!(supported_sanitizers, SanitizerSet)?;
3297+
key!(supported_sanitizers, SanitizerSupport)?;
32413298
key!(default_adjusted_cabi, Option<Abi>)?;
32423299
key!(generate_arange_section, bool);
32433300
key!(supports_stack_protector, bool);

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

+5-2
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

+5-2
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

+5-2
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

+5-2
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

+5-2
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

+5-2
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

+9-6
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

+8-5
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

+5-4
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)