Skip to content

Commit a395d25

Browse files
committed
sanitizers: Add support for stable sanitizers
Add suppport for specifying stable sanitizers in addition to the existing supported sanitizers.
1 parent 4a54b26 commit a395d25

File tree

144 files changed

+442
-338
lines changed

Some content is hidden

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

144 files changed

+442
-338
lines changed

compiler/rustc_codegen_llvm/src/abi.rs

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

2221
use crate::attributes::{self, llfn_attrs_from_instance};
@@ -92,7 +91,7 @@ fn get_attrs<'ll>(this: &ArgAttributes, cx: &CodegenCx<'ll, '_>) -> SmallVec<[&'
9291
attrs.push(llattr.create_attr(cx.llcx));
9392
}
9493
}
95-
} else if cx.tcx.sess.opts.unstable_opts.sanitizer.contains(SanitizerSet::MEMORY) {
94+
} else if cx.tcx.sess.is_sanitizer_memory_enabled() {
9695
// If we're not optimising, *but* memory sanitizer is on, emit noundef, since it affects
9796
// memory sanitizer's behavior.
9897

compiler/rustc_codegen_llvm/src/attributes.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ pub(crate) fn sanitize_attrs<'ll, 'tcx>(
100100
no_sanitize: SanitizerSet,
101101
) -> SmallVec<[&'ll Attribute; 4]> {
102102
let mut attrs = SmallVec::new();
103-
let enabled = tcx.sess.opts.unstable_opts.sanitizer - no_sanitize;
103+
let enabled = tcx.sess.opts.cg.sanitize - no_sanitize;
104104
if enabled.contains(SanitizerSet::ADDRESS) || enabled.contains(SanitizerSet::KERNELADDRESS) {
105105
attrs.push(llvm::AttributeKind::SanitizeAddress.create_attr(cx.llcx));
106106
}
@@ -239,13 +239,7 @@ fn probestack_attr<'ll, 'tcx>(cx: &SimpleCx<'ll>, tcx: TyCtxt<'tcx>) -> Option<&
239239
// Currently stack probes seem somewhat incompatible with the address
240240
// sanitizer and thread sanitizer. With asan we're already protected from
241241
// stack overflow anyway so we don't really need stack probes regardless.
242-
if tcx
243-
.sess
244-
.opts
245-
.unstable_opts
246-
.sanitizer
247-
.intersects(SanitizerSet::ADDRESS | SanitizerSet::THREAD)
248-
{
242+
if tcx.sess.is_sanitizer_address_enabled() || tcx.sess.is_sanitizer_thread_enabled() {
249243
return None;
250244
}
251245

compiler/rustc_codegen_ssa/src/back/link.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1226,7 +1226,7 @@ fn add_sanitizer_libraries(
12261226
return;
12271227
}
12281228

1229-
let sanitizer = sess.opts.unstable_opts.sanitizer;
1229+
let sanitizer = sess.opts.cg.sanitize;
12301230
if sanitizer.contains(SanitizerSet::ADDRESS) {
12311231
link_sanitizer_runtime(sess, flavor, linker, "asan");
12321232
}
@@ -2496,11 +2496,7 @@ fn add_order_independent_options(
24962496
&& crate_type == CrateType::Executable
24972497
&& !matches!(flavor, LinkerFlavor::Gnu(Cc::Yes, _))
24982498
{
2499-
let prefix = if sess.opts.unstable_opts.sanitizer.contains(SanitizerSet::ADDRESS) {
2500-
"asan/"
2501-
} else {
2502-
""
2503-
};
2499+
let prefix = if sess.is_sanitizer_address_enabled() { "asan/" } else { "" };
25042500
cmd.link_arg(format!("--dynamic-linker={prefix}ld.so.1"));
25052501
}
25062502

compiler/rustc_codegen_ssa/src/back/write.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ impl ModuleConfig {
176176
debug_info_for_profiling: sess.opts.unstable_opts.debug_info_for_profiling,
177177
instrument_coverage: if_regular!(sess.instrument_coverage(), false),
178178

179-
sanitizer: if_regular!(sess.opts.unstable_opts.sanitizer, SanitizerSet::empty()),
179+
sanitizer: if_regular!(sess.opts.cg.sanitize, SanitizerSet::empty()),
180180
sanitizer_dataflow_abilist: if_regular!(
181181
sess.opts.unstable_opts.sanitizer_dataflow_abilist.clone(),
182182
Vec::new()

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_metadata/src/native_libs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ pub fn walk_native_lib_search_dirs<R>(
7171
|| sess.target.os == "linux"
7272
|| sess.target.os == "fuchsia"
7373
|| sess.target.is_like_aix
74-
|| sess.target.is_like_darwin && !sess.opts.unstable_opts.sanitizer.is_empty()
74+
|| sess.target.is_like_darwin && !sess.opts.cg.sanitize.is_empty()
7575
{
7676
f(&sess.target_tlib_path.dir, false)?;
7777
}

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/config/cfg.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ pub(crate) fn default_configuration(sess: &Session) -> Cfg {
224224
ins_sym!(sym::relocation_model, sess.target.relocation_model.desc_symbol());
225225
}
226226

227-
for mut s in sess.opts.unstable_opts.sanitizer {
227+
for mut s in sess.opts.cg.sanitize {
228228
// KASAN is still ASAN under the hood, so it uses the same attribute.
229229
if s == SanitizerSet::KERNELADDRESS {
230230
s = SanitizerSet::ADDRESS;

compiler/rustc_session/src/options.rs

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ mod target_modifier_consistency_check {
116116
r: Option<&TargetModifier>,
117117
) -> bool {
118118
// For kCFI, the helper flag -Zsanitizer-cfi-normalize-integers should also be a target modifier
119-
if opts.unstable_opts.sanitizer.contains(SanitizerSet::KCFI) {
119+
if opts.cg.sanitize.contains(SanitizerSet::KCFI) {
120120
if let Some(r) = r {
121121
return l.extend().tech_value == r.extend().tech_value;
122122
} else {
@@ -136,18 +136,19 @@ impl TargetModifier {
136136
pub fn consistent(&self, opts: &Options, 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
opts, self, other,
146148
);
147149
}
148150
_ => {}
149151
},
150-
_ => {}
151152
};
152153
match other {
153154
Some(other) => self.extend().tech_value == other.extend().tech_value,
@@ -1239,25 +1240,14 @@ pub mod parse {
12391240
}
12401241

12411242
pub(crate) fn parse_sanitizers(slot: &mut SanitizerSet, v: Option<&str>) -> bool {
1242-
if let Some(v) = v {
1243-
for s in v.split(',') {
1244-
*slot |= match s {
1245-
"address" => SanitizerSet::ADDRESS,
1246-
"cfi" => SanitizerSet::CFI,
1247-
"dataflow" => SanitizerSet::DATAFLOW,
1248-
"kcfi" => SanitizerSet::KCFI,
1249-
"kernel-address" => SanitizerSet::KERNELADDRESS,
1250-
"leak" => SanitizerSet::LEAK,
1251-
"memory" => SanitizerSet::MEMORY,
1252-
"memtag" => SanitizerSet::MEMTAG,
1253-
"shadow-call-stack" => SanitizerSet::SHADOWCALLSTACK,
1254-
"thread" => SanitizerSet::THREAD,
1255-
"hwaddress" => SanitizerSet::HWADDRESS,
1256-
"safestack" => SanitizerSet::SAFESTACK,
1257-
_ => return false,
1258-
}
1243+
if let Some(s) = v {
1244+
let sanitizer_set = SanitizerSet::from_comma_list(s);
1245+
if sanitizer_set.is_ok() {
1246+
*slot |= sanitizer_set.unwrap();
1247+
true
1248+
} else {
1249+
false
12591250
}
1260-
true
12611251
} else {
12621252
false
12631253
}
@@ -2158,8 +2148,8 @@ options! {
21582148
"output remarks for these optimization passes (space separated, or \"all\")"),
21592149
rpath: bool = (false, parse_bool, [UNTRACKED],
21602150
"set rpath values in libs/exes (default: no)"),
2161-
save_temps: bool = (false, parse_bool, [UNTRACKED],
2162-
"save all temporary output files during compilation (default: no)"),
2151+
sanitize: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED TARGET_MODIFIER],
2152+
"use one or multiple sanitizers"),
21632153
soft_float: bool = (false, parse_bool, [TRACKED],
21642154
"deprecated option: use soft float ABI (*eabihf targets only) (default: no)"),
21652155
#[rustc_lint_opt_deny_field_access("use `Session::split_debuginfo` instead of this field")]
@@ -2177,6 +2167,8 @@ options! {
21772167
This feature is unsafe."),
21782168
unsafe_allow_abi_mismatch: Vec<String> = (Vec::new(), parse_comma_list, [UNTRACKED],
21792169
"Allow incompatible target modifiers in dependency crates (comma separated list)"),
2170+
save_temps: bool = (false, parse_bool, [UNTRACKED],
2171+
"Allow incompatible target modifiers in dependency crates (comma separated list)"),
21802172
// tidy-alphabetical-end
21812173

21822174
// If you add a new option, please update:
@@ -2575,8 +2567,6 @@ written to standard error output)"),
25752567
retpoline_external_thunk: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER],
25762568
"enables retpoline-external-thunk, retpoline-indirect-branches and retpoline-indirect-calls \
25772569
target features (default: no)"),
2578-
sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED TARGET_MODIFIER],
2579-
"use a sanitizer"),
25802570
sanitizer_cfi_canonical_jump_tables: Option<bool> = (Some(true), parse_opt_bool, [TRACKED],
25812571
"enable canonical jump tables (default: yes)"),
25822572
sanitizer_cfi_generalize_pointers: Option<bool> = (None, parse_opt_bool, [TRACKED],
@@ -2594,6 +2584,8 @@ written to standard error output)"),
25942584
saturating_float_casts: Option<bool> = (None, parse_opt_bool, [TRACKED],
25952585
"make float->int casts UB-free: numbers outside the integer type's range are clipped to \
25962586
the max/min integer respectively, and NaN is mapped to 0 (default: yes)"),
2587+
sanitize: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED TARGET_MODIFIER],
2588+
"use one or multiple sanitizers"),
25972589
self_profile: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
25982590
parse_switch_with_opt_path, [UNTRACKED],
25992591
"run the self profiler and output the raw event data"),

compiler/rustc_session/src/session.rs

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -328,8 +328,12 @@ impl Session {
328328
&self.opts.unstable_opts.coverage_options
329329
}
330330

331+
pub fn is_sanitizer_address_enabled(&self) -> bool {
332+
self.opts.cg.sanitize.contains(SanitizerSet::ADDRESS)
333+
}
334+
331335
pub fn is_sanitizer_cfi_enabled(&self) -> bool {
332-
self.opts.unstable_opts.sanitizer.contains(SanitizerSet::CFI)
336+
self.opts.cg.sanitize.contains(SanitizerSet::CFI)
333337
}
334338

335339
pub fn is_sanitizer_cfi_canonical_jump_tables_disabled(&self) -> bool {
@@ -348,12 +352,36 @@ impl Session {
348352
self.opts.unstable_opts.sanitizer_cfi_normalize_integers == Some(true)
349353
}
350354

355+
pub fn is_sanitizer_hwaddress_enabled(&self) -> bool {
356+
self.opts.cg.sanitize.contains(SanitizerSet::HWADDRESS)
357+
}
358+
351359
pub fn is_sanitizer_kcfi_arity_enabled(&self) -> bool {
352360
self.opts.unstable_opts.sanitizer_kcfi_arity == Some(true)
353361
}
354362

355363
pub fn is_sanitizer_kcfi_enabled(&self) -> bool {
356-
self.opts.unstable_opts.sanitizer.contains(SanitizerSet::KCFI)
364+
self.opts.cg.sanitize.contains(SanitizerSet::KCFI)
365+
}
366+
367+
pub fn is_sanitizer_kernel_address_enabled(&self) -> bool {
368+
self.opts.cg.sanitize.contains(SanitizerSet::KERNELADDRESS)
369+
}
370+
371+
pub fn is_sanitizer_memory_enabled(&self) -> bool {
372+
self.opts.cg.sanitize.contains(SanitizerSet::MEMORY)
373+
}
374+
375+
pub fn is_sanitizer_memory_recover_enabled(&self) -> bool {
376+
self.opts.unstable_opts.sanitizer_recover.contains(SanitizerSet::MEMORY)
377+
}
378+
379+
pub fn is_sanitizer_memory_track_origins_enabled(&self) -> bool {
380+
self.opts.unstable_opts.sanitizer_memory_track_origins != 0
381+
}
382+
383+
pub fn is_sanitizer_thread_enabled(&self) -> bool {
384+
self.opts.cg.sanitize.contains(SanitizerSet::THREAD)
357385
}
358386

359387
pub fn is_split_lto_unit_enabled(&self) -> bool {
@@ -533,7 +561,10 @@ impl Session {
533561
// AddressSanitizer and KernelAddressSanitizer uses lifetimes to detect use after scope bugs.
534562
// MemorySanitizer uses lifetimes to detect use of uninitialized stack variables.
535563
// HWAddressSanitizer will use lifetimes to detect use after scope bugs in the future.
536-
|| self.opts.unstable_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS | SanitizerSet::MEMORY | SanitizerSet::HWADDRESS)
564+
|| self.is_sanitizer_address_enabled()
565+
|| self.is_sanitizer_kernel_address_enabled()
566+
|| self.is_sanitizer_memory_enabled()
567+
|| self.is_sanitizer_hwaddress_enabled()
537568
}
538569

539570
pub fn diagnostic_width(&self) -> usize {
@@ -683,7 +714,7 @@ impl Session {
683714
let more_names = self.opts.output_types.contains_key(&OutputType::LlvmAssembly)
684715
|| self.opts.output_types.contains_key(&OutputType::Bitcode)
685716
// AddressSanitizer and MemorySanitizer use alloca name when reporting an issue.
686-
|| self.opts.unstable_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY);
717+
|| self.is_sanitizer_address_enabled() || self.is_sanitizer_memory_enabled();
687718
!more_names
688719
}
689720
}
@@ -1187,14 +1218,19 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
11871218
}
11881219
}
11891220

1190-
// Sanitizers can only be used on platforms that we know have working sanitizer codegen.
1191-
let supported_sanitizers = sess.target.options.supported_sanitizers;
1192-
let mut unsupported_sanitizers = sess.opts.unstable_opts.sanitizer - supported_sanitizers;
1221+
let supported_sanitizers = if sess.unstable_options() {
1222+
sess.target.options.supported_sanitizers | sess.target.options.stable_sanitizers
1223+
} else {
1224+
sess.target.options.stable_sanitizers
1225+
};
1226+
let mut unsupported_sanitizers = sess.opts.cg.sanitize - supported_sanitizers;
1227+
11931228
// Niche: if `fixed-x18`, or effectively switching on `reserved-x18` flag, is enabled
11941229
// we should allow Shadow Call Stack sanitizer.
11951230
if sess.opts.unstable_opts.fixed_x18 && sess.target.arch == "aarch64" {
11961231
unsupported_sanitizers -= SanitizerSet::SHADOWCALLSTACK;
11971232
}
1233+
11981234
match unsupported_sanitizers.into_iter().count() {
11991235
0 => {}
12001236
1 => {
@@ -1209,18 +1245,15 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
12091245
}
12101246

12111247
// Cannot mix and match mutually-exclusive sanitizers.
1212-
if let Some((first, second)) = sess.opts.unstable_opts.sanitizer.mutually_exclusive() {
1248+
if let Some((first, second)) = sess.opts.cg.sanitize.mutually_exclusive() {
12131249
sess.dcx().emit_err(errors::CannotMixAndMatchSanitizers {
12141250
first: first.to_string(),
12151251
second: second.to_string(),
12161252
});
12171253
}
12181254

12191255
// Cannot enable crt-static with sanitizers on Linux
1220-
if sess.crt_static(None)
1221-
&& !sess.opts.unstable_opts.sanitizer.is_empty()
1222-
&& !sess.target.is_like_msvc
1223-
{
1256+
if sess.crt_static(None) && !sess.opts.cg.sanitize.is_empty() && !sess.target.is_like_msvc {
12241257
sess.dcx().emit_err(errors::CannotEnableCrtStaticLinux);
12251258
}
12261259

0 commit comments

Comments
 (0)