Skip to content

Commit c8f1f86

Browse files
committed
sanitizers: Add support for stable sanitizers
Add suppport for specifying stable sanitizers in addition to the existing supported sanitizers.
1 parent 5bc3450 commit c8f1f86

File tree

145 files changed

+420
-318
lines changed

Some content is hidden

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

145 files changed

+420
-318
lines changed

compiler/rustc_codegen_llvm/src/abi.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use rustc_session::{Session, config};
1616
use rustc_target::callconv::{
1717
ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, CastTarget, FnAbi, PassMode,
1818
};
19-
use rustc_target::spec::{Arch, SanitizerSet};
19+
use rustc_target::spec::Arch;
2020
use smallvec::SmallVec;
2121

2222
use crate::attributes::{self, llfn_attrs_from_instance};
@@ -96,7 +96,7 @@ fn get_attrs<'ll>(this: &ArgAttributes, cx: &CodegenCx<'ll, '_>) -> SmallVec<[&'
9696
}
9797
}
9898
}
99-
} else if cx.tcx.sess.sanitizers().contains(SanitizerSet::MEMORY) {
99+
} else if cx.tcx.sess.is_sanitizer_memory_enabled() {
100100
// If we're not optimising, *but* memory sanitizer is on, emit noundef, since it affects
101101
// memory sanitizer's behavior.
102102

compiler/rustc_codegen_llvm/src/attributes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ fn probestack_attr<'ll, 'tcx>(cx: &SimpleCx<'ll>, tcx: TyCtxt<'tcx>) -> Option<&
260260
// Currently stack probes seem somewhat incompatible with the address
261261
// sanitizer and thread sanitizer. With asan we're already protected from
262262
// stack overflow anyway so we don't really need stack probes regardless.
263-
if tcx.sess.sanitizers().intersects(SanitizerSet::ADDRESS | SanitizerSet::THREAD) {
263+
if tcx.sess.is_sanitizer_address_enabled() || tcx.sess.is_sanitizer_thread_enabled() {
264264
return None;
265265
}
266266

compiler/rustc_codegen_ssa/src/back/link.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2494,7 +2494,7 @@ fn add_order_independent_options(
24942494
&& crate_type == CrateType::Executable
24952495
&& !matches!(flavor, LinkerFlavor::Gnu(Cc::Yes, _))
24962496
{
2497-
let prefix = if sess.sanitizers().contains(SanitizerSet::ADDRESS) { "asan/" } else { "" };
2497+
let prefix = if sess.is_sanitizer_address_enabled() { "asan/" } else { "" };
24982498
cmd.link_arg(format!("--dynamic-linker={prefix}ld.so.1"));
24992499
}
25002500

compiler/rustc_interface/src/tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,7 @@ fn test_codegen_options_tracking_hash() {
639639
tracked!(profile_use, Some(PathBuf::from("abc")));
640640
tracked!(relocation_model, Some(RelocModel::Pic));
641641
tracked!(relro_level, Some(RelroLevel::Full));
642+
tracked!(sanitize, SanitizerSet::ADDRESS);
642643
tracked!(soft_float, true);
643644
tracked!(split_debuginfo, Some(SplitDebuginfo::Packed));
644645
tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0));
@@ -858,7 +859,6 @@ fn test_unstable_options_tracking_hash() {
858859
tracked!(regparm, Some(3));
859860
tracked!(relax_elf_relocations, Some(true));
860861
tracked!(remap_cwd_prefix, Some(PathBuf::from("abc")));
861-
tracked!(sanitizer, SanitizerSet::ADDRESS);
862862
tracked!(sanitizer_cfi_canonical_jump_tables, None);
863863
tracked!(sanitizer_cfi_generalize_pointers, Some(true));
864864
tracked!(sanitizer_cfi_normalize_integers, Some(true));

compiler/rustc_session/messages.ftl

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ session_branch_protection_requires_aarch64 = `-Zbranch-protection` is only suppo
99
1010
session_cannot_enable_crt_static_linux = sanitizer is incompatible with statically linked libc, disable it using `-C target-feature=-crt-static`
1111
12-
session_cannot_mix_and_match_sanitizers = `-Zsanitizer={$first}` is incompatible with `-Zsanitizer={$second}`
12+
session_cannot_mix_and_match_sanitizers = `-Csanitize={$first}` is incompatible with `-Csanitize={$second}`
1313
1414
session_cli_feature_diagnostic_help =
1515
add `-Zcrate-attr="feature({$feature})"` to the command-line options to enable
@@ -92,15 +92,15 @@ session_profile_sample_use_file_does_not_exist = file `{$path}` passed to `-C pr
9292
9393
session_profile_use_file_does_not_exist = file `{$path}` passed to `-C profile-use` does not exist
9494
95-
session_sanitizer_cfi_canonical_jump_tables_requires_cfi = `-Zsanitizer-cfi-canonical-jump-tables` requires `-Zsanitizer=cfi`
95+
session_sanitizer_cfi_canonical_jump_tables_requires_cfi = `-Zsanitizer-cfi-canonical-jump-tables` requires `-Csanitize=cfi`
9696
97-
session_sanitizer_cfi_generalize_pointers_requires_cfi = `-Zsanitizer-cfi-generalize-pointers` requires `-Zsanitizer=cfi` or `-Zsanitizer=kcfi`
97+
session_sanitizer_cfi_generalize_pointers_requires_cfi = `-Zsanitizer-cfi-generalize-pointers` requires `-Csanitize=cfi` or `-Csanitize=kcfi`
9898
99-
session_sanitizer_cfi_normalize_integers_requires_cfi = `-Zsanitizer-cfi-normalize-integers` requires `-Zsanitizer=cfi` or `-Zsanitizer=kcfi`
99+
session_sanitizer_cfi_normalize_integers_requires_cfi = `-Zsanitizer-cfi-normalize-integers` requires `-Csanitize=cfi` or `-Csanitize=kcfi`
100100
101-
session_sanitizer_cfi_requires_lto = `-Zsanitizer=cfi` requires `-Clto` or `-Clinker-plugin-lto`
101+
session_sanitizer_cfi_requires_lto = `-Csanitize=cfi` requires `-Clto` or `-Clinker-plugin-lto`
102102
103-
session_sanitizer_cfi_requires_single_codegen_unit = `-Zsanitizer=cfi` with `-Clto` requires `-Ccodegen-units=1`
103+
session_sanitizer_cfi_requires_single_codegen_unit = `-Csanitize=cfi` with `-Clto` requires `-Ccodegen-units=1`
104104
105105
session_sanitizer_kcfi_arity_requires_kcfi = `-Zsanitizer-kcfi-arity` requires `-Zsanitizer=kcfi`
106106

compiler/rustc_session/src/options.rs

Lines changed: 15 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -136,18 +136,19 @@ impl TargetModifier {
136136
pub fn consistent(&self, sess: &Session, other: Option<&TargetModifier>) -> bool {
137137
assert!(other.is_none() || self.opt == other.unwrap().opt);
138138
match self.opt {
139-
OptionsTargetModifiers::UnstableOptions(unstable) => match unstable {
140-
UnstableOptionsTargetModifiers::sanitizer => {
139+
OptionsTargetModifiers::CodegenOptions(stable) => match stable {
140+
CodegenOptionsTargetModifiers::sanitize => {
141141
return target_modifier_consistency_check::sanitizer(self, other);
142142
}
143+
},
144+
OptionsTargetModifiers::UnstableOptions(unstable) => match unstable {
143145
UnstableOptionsTargetModifiers::sanitizer_cfi_normalize_integers => {
144146
return target_modifier_consistency_check::sanitizer_cfi_normalize_integers(
145147
sess, self, other,
146148
);
147149
}
148150
_ => {}
149151
},
150-
_ => {}
151152
};
152153
match other {
153154
Some(other) => self.extend().tech_value == other.extend().tech_value,
@@ -1263,26 +1264,14 @@ pub mod parse {
12631264
}
12641265

12651266
pub(crate) fn parse_sanitizers(slot: &mut SanitizerSet, v: Option<&str>) -> bool {
1266-
if let Some(v) = v {
1267-
for s in v.split(',') {
1268-
*slot |= match s {
1269-
"address" => SanitizerSet::ADDRESS,
1270-
"cfi" => SanitizerSet::CFI,
1271-
"dataflow" => SanitizerSet::DATAFLOW,
1272-
"kcfi" => SanitizerSet::KCFI,
1273-
"kernel-address" => SanitizerSet::KERNELADDRESS,
1274-
"leak" => SanitizerSet::LEAK,
1275-
"memory" => SanitizerSet::MEMORY,
1276-
"memtag" => SanitizerSet::MEMTAG,
1277-
"shadow-call-stack" => SanitizerSet::SHADOWCALLSTACK,
1278-
"thread" => SanitizerSet::THREAD,
1279-
"hwaddress" => SanitizerSet::HWADDRESS,
1280-
"safestack" => SanitizerSet::SAFESTACK,
1281-
"realtime" => SanitizerSet::REALTIME,
1282-
_ => return false,
1283-
}
1267+
if let Some(s) = v {
1268+
let sanitizer_set = SanitizerSet::from_comma_list(s);
1269+
if sanitizer_set.is_ok() {
1270+
*slot |= sanitizer_set.unwrap();
1271+
true
1272+
} else {
1273+
false
12841274
}
1285-
true
12861275
} else {
12871276
false
12881277
}
@@ -2187,7 +2176,10 @@ options! {
21872176
rpath: bool = (false, parse_bool, [UNTRACKED],
21882177
"set rpath values in libs/exes (default: no)"),
21892178
save_temps: bool = (false, parse_bool, [UNTRACKED],
2190-
"save all temporary output files during compilation (default: no)"),
2179+
"Allow incompatible target modifiers in dependency crates (comma separated list)"),
2180+
#[rustc_lint_opt_deny_field_access("use `Session::sanitizers()` instead of this field")]
2181+
sanitize: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED TARGET_MODIFIER],
2182+
"use one or multiple sanitizers"),
21912183
soft_float: bool = (false, parse_bool, [TRACKED],
21922184
"deprecated option: use soft float ABI (*eabihf targets only) (default: no)"),
21932185
#[rustc_lint_opt_deny_field_access("use `Session::split_debuginfo` instead of this field")]
@@ -2604,9 +2596,6 @@ written to standard error output)"),
26042596
retpoline_external_thunk: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER],
26052597
"enables retpoline-external-thunk, retpoline-indirect-branches and retpoline-indirect-calls \
26062598
target features (default: no)"),
2607-
#[rustc_lint_opt_deny_field_access("use `Session::sanitizers()` instead of this field")]
2608-
sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED TARGET_MODIFIER],
2609-
"use a sanitizer"),
26102599
sanitizer_cfi_canonical_jump_tables: Option<bool> = (Some(true), parse_opt_bool, [TRACKED],
26112600
"enable canonical jump tables (default: yes)"),
26122601
sanitizer_cfi_generalize_pointers: Option<bool> = (None, parse_opt_bool, [TRACKED],

compiler/rustc_session/src/session.rs

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,10 @@ impl Session {
307307
&self.opts.unstable_opts.coverage_options
308308
}
309309

310+
pub fn is_sanitizer_address_enabled(&self) -> bool {
311+
self.sanitizers().contains(SanitizerSet::ADDRESS)
312+
}
313+
310314
pub fn is_sanitizer_cfi_enabled(&self) -> bool {
311315
self.sanitizers().contains(SanitizerSet::CFI)
312316
}
@@ -327,6 +331,10 @@ impl Session {
327331
self.opts.unstable_opts.sanitizer_cfi_normalize_integers == Some(true)
328332
}
329333

334+
pub fn is_sanitizer_hwaddress_enabled(&self) -> bool {
335+
self.sanitizers().contains(SanitizerSet::HWADDRESS)
336+
}
337+
330338
pub fn is_sanitizer_kcfi_arity_enabled(&self) -> bool {
331339
self.opts.unstable_opts.sanitizer_kcfi_arity == Some(true)
332340
}
@@ -335,6 +343,26 @@ impl Session {
335343
self.sanitizers().contains(SanitizerSet::KCFI)
336344
}
337345

346+
pub fn is_sanitizer_kernel_address_enabled(&self) -> bool {
347+
self.sanitizers().contains(SanitizerSet::KERNELADDRESS)
348+
}
349+
350+
pub fn is_sanitizer_memory_enabled(&self) -> bool {
351+
self.sanitizers().contains(SanitizerSet::MEMORY)
352+
}
353+
354+
pub fn is_sanitizer_memory_recover_enabled(&self) -> bool {
355+
self.opts.unstable_opts.sanitizer_recover.contains(SanitizerSet::MEMORY)
356+
}
357+
358+
pub fn is_sanitizer_memory_track_origins_enabled(&self) -> bool {
359+
self.opts.unstable_opts.sanitizer_memory_track_origins != 0
360+
}
361+
362+
pub fn is_sanitizer_thread_enabled(&self) -> bool {
363+
self.sanitizers().contains(SanitizerSet::THREAD)
364+
}
365+
338366
pub fn is_split_lto_unit_enabled(&self) -> bool {
339367
self.opts.unstable_opts.split_lto_unit == Some(true)
340368
}
@@ -512,7 +540,10 @@ impl Session {
512540
// AddressSanitizer and KernelAddressSanitizer uses lifetimes to detect use after scope bugs.
513541
// MemorySanitizer uses lifetimes to detect use of uninitialized stack variables.
514542
// HWAddressSanitizer will use lifetimes to detect use after scope bugs in the future.
515-
|| self.sanitizers().intersects(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS | SanitizerSet::MEMORY | SanitizerSet::HWADDRESS)
543+
|| self.is_sanitizer_address_enabled()
544+
|| self.is_sanitizer_kernel_address_enabled()
545+
|| self.is_sanitizer_memory_enabled()
546+
|| self.is_sanitizer_hwaddress_enabled()
516547
}
517548

518549
pub fn diagnostic_width(&self) -> usize {
@@ -655,7 +686,7 @@ impl Session {
655686
let more_names = self.opts.output_types.contains_key(&OutputType::LlvmAssembly)
656687
|| self.opts.output_types.contains_key(&OutputType::Bitcode)
657688
// AddressSanitizer and MemorySanitizer use alloca name when reporting an issue.
658-
|| self.opts.unstable_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY);
689+
|| self.is_sanitizer_address_enabled() || self.is_sanitizer_memory_enabled();
659690
!more_names
660691
}
661692
}
@@ -901,7 +932,7 @@ impl Session {
901932
}
902933

903934
pub fn sanitizers(&self) -> SanitizerSet {
904-
return self.opts.unstable_opts.sanitizer | self.target.options.default_sanitizers;
935+
return self.opts.cg.sanitize | self.target.options.default_sanitizers;
905936
}
906937
}
907938

@@ -1169,14 +1200,19 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
11691200
}
11701201
}
11711202

1172-
// Sanitizers can only be used on platforms that we know have working sanitizer codegen.
1173-
let supported_sanitizers = sess.target.options.supported_sanitizers;
1174-
let mut unsupported_sanitizers = sess.opts.unstable_opts.sanitizer - supported_sanitizers;
1203+
let supported_sanitizers = if sess.unstable_options() {
1204+
sess.target.options.supported_sanitizers | sess.target.options.stable_sanitizers
1205+
} else {
1206+
sess.target.options.stable_sanitizers
1207+
};
1208+
let mut unsupported_sanitizers = sess.sanitizers() - supported_sanitizers;
1209+
11751210
// Niche: if `fixed-x18`, or effectively switching on `reserved-x18` flag, is enabled
11761211
// we should allow Shadow Call Stack sanitizer.
11771212
if sess.opts.unstable_opts.fixed_x18 && sess.target.arch == Arch::AArch64 {
11781213
unsupported_sanitizers -= SanitizerSet::SHADOWCALLSTACK;
11791214
}
1215+
11801216
match unsupported_sanitizers.into_iter().count() {
11811217
0 => {}
11821218
1 => {
@@ -1191,18 +1227,15 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
11911227
}
11921228

11931229
// Cannot mix and match mutually-exclusive sanitizers.
1194-
if let Some((first, second)) = sess.opts.unstable_opts.sanitizer.mutually_exclusive() {
1230+
if let Some((first, second)) = sess.opts.cg.sanitize.mutually_exclusive() {
11951231
sess.dcx().emit_err(errors::CannotMixAndMatchSanitizers {
11961232
first: first.to_string(),
11971233
second: second.to_string(),
11981234
});
11991235
}
12001236

12011237
// Cannot enable crt-static with sanitizers on Linux
1202-
if sess.crt_static(None)
1203-
&& !sess.opts.unstable_opts.sanitizer.is_empty()
1204-
&& !sess.target.is_like_msvc
1205-
{
1238+
if sess.crt_static(None) && !sess.sanitizers().is_empty() && !sess.target.is_like_msvc {
12061239
sess.dcx().emit_err(errors::CannotEnableCrtStaticLinux);
12071240
}
12081241

compiler/rustc_target/src/spec/json.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,7 @@ impl ToJson for Target {
401401
target_option_val!(supported_split_debuginfo);
402402
target_option_val!(supported_sanitizers);
403403
target_option_val!(default_sanitizers);
404+
target_option_val!(stable_sanitizers);
404405
target_option_val!(c_enum_min_bits);
405406
target_option_val!(generate_arange_section);
406407
target_option_val!(supports_stack_protector);

compiler/rustc_target/src/spec/mod.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1233,6 +1233,28 @@ impl SanitizerSet {
12331233
})
12341234
}
12351235

1236+
pub fn from_comma_list(s: &str) -> Result<Self, String> {
1237+
let mut sanitizer_set = SanitizerSet::empty();
1238+
for name in s.split(',') {
1239+
sanitizer_set |= match name {
1240+
"address" => SanitizerSet::ADDRESS,
1241+
"cfi" => SanitizerSet::CFI,
1242+
"dataflow" => SanitizerSet::DATAFLOW,
1243+
"kcfi" => SanitizerSet::KCFI,
1244+
"kernel-address" => SanitizerSet::KERNELADDRESS,
1245+
"leak" => SanitizerSet::LEAK,
1246+
"memory" => SanitizerSet::MEMORY,
1247+
"memtag" => SanitizerSet::MEMTAG,
1248+
"safestack" => SanitizerSet::SAFESTACK,
1249+
"shadow-call-stack" => SanitizerSet::SHADOWCALLSTACK,
1250+
"thread" => SanitizerSet::THREAD,
1251+
"hwaddress" => SanitizerSet::HWADDRESS,
1252+
_ => return Err(format!("Unknown sanitizer {}", name)),
1253+
};
1254+
}
1255+
return Ok(sanitizer_set);
1256+
}
1257+
12361258
pub fn mutually_exclusive(self) -> Option<(SanitizerSet, SanitizerSet)> {
12371259
Self::MUTUALLY_EXCLUSIVE
12381260
.into_iter()
@@ -2563,6 +2585,13 @@ pub struct TargetOptions {
25632585
/// distributed with the target, the sanitizer should still appear in this list for the target.
25642586
pub default_sanitizers: SanitizerSet,
25652587

2588+
/// The stable sanitizers supported by this target
2589+
///
2590+
/// Note that the support here is at a codegen level. If the machine code with sanitizer
2591+
/// enabled can generated on this target, but the necessary supporting libraries are not
2592+
/// distributed with the target, the sanitizer should still appear in this list for the target.
2593+
pub stable_sanitizers: SanitizerSet,
2594+
25662595
/// Minimum number of bits in #[repr(C)] enum. Defaults to the size of c_int
25672596
pub c_enum_min_bits: Option<u64>,
25682597

@@ -2817,6 +2846,7 @@ impl Default for TargetOptions {
28172846
supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
28182847
supported_sanitizers: SanitizerSet::empty(),
28192848
default_sanitizers: SanitizerSet::empty(),
2849+
stable_sanitizers: SanitizerSet::empty(),
28202850
c_enum_min_bits: None,
28212851
generate_arange_section: true,
28222852
supports_stack_protector: true,

src/tools/compiletest/src/common.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1009,7 +1009,9 @@ pub struct TargetCfg {
10091009
#[serde(default)]
10101010
pub(crate) dynamic_linking: bool,
10111011
#[serde(rename = "supported-sanitizers", default)]
1012-
pub(crate) sanitizers: Vec<Sanitizer>,
1012+
pub(crate) supported_sanitizers: Vec<Sanitizer>,
1013+
#[serde(rename = "stable-sanitizers", default)]
1014+
pub(crate) stable_sanitizers: Vec<Sanitizer>,
10131015
#[serde(rename = "supports-xray", default)]
10141016
pub(crate) xray: bool,
10151017
#[serde(default = "default_reloc_model")]

0 commit comments

Comments
 (0)