Skip to content

Commit 8dbc916

Browse files
committed
sanitizers: Add support for stable sanitizers
Add suppport for specifying stable sanitizers in addition to the existing supported sanitizers.
1 parent 8700ba1 commit 8dbc916

File tree

124 files changed

+324
-254
lines changed

Some content is hidden

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

124 files changed

+324
-254
lines changed

compiler/rustc_codegen_llvm/src/abi.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ pub(crate) use rustc_middle::ty::layout::{WIDE_PTR_ADDR, WIDE_PTR_EXTRA};
1515
use rustc_middle::{bug, ty};
1616
use rustc_session::config;
1717
pub(crate) use rustc_target::callconv::*;
18-
use rustc_target::spec::SanitizerSet;
1918
use smallvec::SmallVec;
2019

2120
use crate::attributes::llfn_attrs_from_instance;
@@ -84,7 +83,7 @@ fn get_attrs<'ll>(this: &ArgAttributes, cx: &CodegenCx<'ll, '_>) -> SmallVec<[&'
8483
attrs.push(llattr.create_attr(cx.llcx));
8584
}
8685
}
87-
} else if cx.tcx.sess.opts.unstable_opts.sanitizer.contains(SanitizerSet::MEMORY) {
86+
} else if cx.tcx.sess.is_sanitizer_memory_enabled() {
8887
// If we're not optimising, *but* memory sanitizer is on, emit noundef, since it affects
8988
// memory sanitizer's behavior.
9089

compiler/rustc_codegen_llvm/src/attributes.rs

+2-8
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ pub(crate) fn sanitize_attrs<'ll>(
8484
no_sanitize: SanitizerSet,
8585
) -> SmallVec<[&'ll Attribute; 4]> {
8686
let mut attrs = SmallVec::new();
87-
let enabled = cx.tcx.sess.opts.unstable_opts.sanitizer - no_sanitize;
87+
let enabled = cx.tcx.sess.opts.cg.sanitize - no_sanitize;
8888
if enabled.contains(SanitizerSet::ADDRESS) || enabled.contains(SanitizerSet::KERNELADDRESS) {
8989
attrs.push(llvm::AttributeKind::SanitizeAddress.create_attr(cx.llcx));
9090
}
@@ -217,13 +217,7 @@ fn probestack_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
217217
// Currently stack probes seem somewhat incompatible with the address
218218
// sanitizer and thread sanitizer. With asan we're already protected from
219219
// stack overflow anyway so we don't really need stack probes regardless.
220-
if cx
221-
.sess()
222-
.opts
223-
.unstable_opts
224-
.sanitizer
225-
.intersects(SanitizerSet::ADDRESS | SanitizerSet::THREAD)
226-
{
220+
if cx.sess().is_sanitizer_address_enabled() || cx.sess().is_sanitizer_thread_enabled() {
227221
return None;
228222
}
229223

compiler/rustc_codegen_ssa/src/back/link.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -1315,7 +1315,7 @@ fn add_sanitizer_libraries(
13151315
return;
13161316
}
13171317

1318-
let sanitizer = sess.opts.unstable_opts.sanitizer;
1318+
let sanitizer = sess.opts.cg.sanitize;
13191319
if sanitizer.contains(SanitizerSet::ADDRESS) {
13201320
link_sanitizer_runtime(sess, flavor, linker, "asan");
13211321
}
@@ -2447,11 +2447,7 @@ fn add_order_independent_options(
24472447
&& crate_type == CrateType::Executable
24482448
&& !matches!(flavor, LinkerFlavor::Gnu(Cc::Yes, _))
24492449
{
2450-
let prefix = if sess.opts.unstable_opts.sanitizer.contains(SanitizerSet::ADDRESS) {
2451-
"asan/"
2452-
} else {
2453-
""
2454-
};
2450+
let prefix = if sess.is_sanitizer_address_enabled() { "asan/" } else { "" };
24552451
cmd.link_arg(format!("--dynamic-linker={prefix}ld.so.1"));
24562452
}
24572453

compiler/rustc_codegen_ssa/src/back/symbol_export.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use rustc_middle::query::LocalCrate;
1313
use rustc_middle::ty::{self, GenericArgKind, GenericArgsRef, Instance, SymbolName, TyCtxt};
1414
use rustc_middle::util::Providers;
1515
use rustc_session::config::{CrateType, OomStrategy};
16-
use rustc_target::spec::{SanitizerSet, TlsModel};
16+
use rustc_target::spec::TlsModel;
1717
use tracing::debug;
1818

1919
use crate::base::allocator_kind_for_codegen;
@@ -247,15 +247,15 @@ fn exported_symbols_provider_local(
247247
}));
248248
}
249249

250-
if tcx.sess.opts.unstable_opts.sanitizer.contains(SanitizerSet::MEMORY) {
250+
if tcx.sess.is_sanitizer_memory_enabled() {
251251
let mut msan_weak_symbols = Vec::new();
252252

253253
// Similar to profiling, preserve weak msan symbol during LTO.
254-
if tcx.sess.opts.unstable_opts.sanitizer_recover.contains(SanitizerSet::MEMORY) {
254+
if tcx.sess.is_sanitizer_memory_recover_enabled() {
255255
msan_weak_symbols.push("__msan_keep_going");
256256
}
257257

258-
if tcx.sess.opts.unstable_opts.sanitizer_memory_track_origins != 0 {
258+
if tcx.sess.is_sanitizer_memory_track_origins_enabled() {
259259
msan_weak_symbols.push("__msan_track_origins");
260260
}
261261

compiler/rustc_codegen_ssa/src/back/write.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ impl ModuleConfig {
183183
debug_info_for_profiling: sess.opts.unstable_opts.debug_info_for_profiling,
184184
instrument_coverage: if_regular!(sess.instrument_coverage(), false),
185185

186-
sanitizer: if_regular!(sess.opts.unstable_opts.sanitizer, SanitizerSet::empty()),
186+
sanitizer: if_regular!(sess.opts.cg.sanitize, SanitizerSet::empty()),
187187
sanitizer_dataflow_abilist: if_regular!(
188188
sess.opts.unstable_opts.sanitizer_dataflow_abilist.clone(),
189189
Vec::new()

compiler/rustc_interface/src/tests.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,7 @@ fn test_codegen_options_tracking_hash() {
633633
tracked!(profile_use, Some(PathBuf::from("abc")));
634634
tracked!(relocation_model, Some(RelocModel::Pic));
635635
tracked!(relro_level, Some(RelroLevel::Full));
636+
tracked!(sanitize, SanitizerSet::ADDRESS);
636637
tracked!(soft_float, true);
637638
tracked!(split_debuginfo, Some(SplitDebuginfo::Packed));
638639
tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0));
@@ -839,7 +840,6 @@ fn test_unstable_options_tracking_hash() {
839840
tracked!(regparm, Some(3));
840841
tracked!(relax_elf_relocations, Some(true));
841842
tracked!(remap_cwd_prefix, Some(PathBuf::from("abc")));
842-
tracked!(sanitizer, SanitizerSet::ADDRESS);
843843
tracked!(sanitizer_cfi_canonical_jump_tables, None);
844844
tracked!(sanitizer_cfi_generalize_pointers, Some(true));
845845
tracked!(sanitizer_cfi_normalize_integers, Some(true));

compiler/rustc_metadata/src/native_libs.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ pub fn walk_native_lib_search_dirs<R>(
6161
|| sess.target.os == "linux"
6262
|| sess.target.os == "fuchsia"
6363
|| sess.target.is_like_aix
64-
|| sess.target.is_like_osx && !sess.opts.unstable_opts.sanitizer.is_empty()
64+
|| sess.target.is_like_osx && !sess.opts.cg.sanitize.is_empty()
6565
{
6666
f(&sess.target_tlib_path.dir, false)?;
6767
}

compiler/rustc_session/messages.ftl

+6-6
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ session_branch_protection_requires_aarch64 = `-Zbranch-protection` is only suppo
33
44
session_cannot_enable_crt_static_linux = sanitizer is incompatible with statically linked libc, disable it using `-C target-feature=-crt-static`
55
6-
session_cannot_mix_and_match_sanitizers = `-Zsanitizer={$first}` is incompatible with `-Zsanitizer={$second}`
6+
session_cannot_mix_and_match_sanitizers = `-Csanitize={$first}` is incompatible with `-Csanitize={$second}`
77
88
session_cli_feature_diagnostic_help =
99
add `-Zcrate-attr="feature({$feature})"` to the command-line options to enable
@@ -88,15 +88,15 @@ session_profile_sample_use_file_does_not_exist = file `{$path}` passed to `-C pr
8888
8989
session_profile_use_file_does_not_exist = file `{$path}` passed to `-C profile-use` does not exist
9090
91-
session_sanitizer_cfi_canonical_jump_tables_requires_cfi = `-Zsanitizer-cfi-canonical-jump-tables` requires `-Zsanitizer=cfi`
91+
session_sanitizer_cfi_canonical_jump_tables_requires_cfi = `-Zsanitizer-cfi-canonical-jump-tables` requires `-Csanitize=cfi`
9292
93-
session_sanitizer_cfi_generalize_pointers_requires_cfi = `-Zsanitizer-cfi-generalize-pointers` requires `-Zsanitizer=cfi` or `-Zsanitizer=kcfi`
93+
session_sanitizer_cfi_generalize_pointers_requires_cfi = `-Zsanitizer-cfi-generalize-pointers` requires `-Csanitize=cfi` or `-Csanitize=kcfi`
9494
95-
session_sanitizer_cfi_normalize_integers_requires_cfi = `-Zsanitizer-cfi-normalize-integers` requires `-Zsanitizer=cfi` or `-Zsanitizer=kcfi`
95+
session_sanitizer_cfi_normalize_integers_requires_cfi = `-Zsanitizer-cfi-normalize-integers` requires `-Csanitize=cfi` or `-Csanitize=kcfi`
9696
97-
session_sanitizer_cfi_requires_lto = `-Zsanitizer=cfi` requires `-Clto` or `-Clinker-plugin-lto`
97+
session_sanitizer_cfi_requires_lto = `-Csanitize=cfi` requires `-Clto` or `-Clinker-plugin-lto`
9898
99-
session_sanitizer_cfi_requires_single_codegen_unit = `-Zsanitizer=cfi` with `-Clto` requires `-Ccodegen-units=1`
99+
session_sanitizer_cfi_requires_single_codegen_unit = `-Csanitize=cfi` with `-Clto` requires `-Ccodegen-units=1`
100100
101101
session_sanitizer_kcfi_requires_panic_abort = `-Z sanitizer=kcfi` requires `-C panic=abort`
102102

compiler/rustc_session/src/config/cfg.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ pub(crate) fn default_configuration(sess: &Session) -> Cfg {
210210
ins_sym!(sym::relocation_model, sess.target.relocation_model.desc_symbol());
211211
}
212212

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

compiler/rustc_session/src/options.rs

+9-20
Original file line numberDiff line numberDiff line change
@@ -813,25 +813,14 @@ pub mod parse {
813813
}
814814

815815
pub(crate) fn parse_sanitizers(slot: &mut SanitizerSet, v: Option<&str>) -> bool {
816-
if let Some(v) = v {
817-
for s in v.split(',') {
818-
*slot |= match s {
819-
"address" => SanitizerSet::ADDRESS,
820-
"cfi" => SanitizerSet::CFI,
821-
"dataflow" => SanitizerSet::DATAFLOW,
822-
"kcfi" => SanitizerSet::KCFI,
823-
"kernel-address" => SanitizerSet::KERNELADDRESS,
824-
"leak" => SanitizerSet::LEAK,
825-
"memory" => SanitizerSet::MEMORY,
826-
"memtag" => SanitizerSet::MEMTAG,
827-
"shadow-call-stack" => SanitizerSet::SHADOWCALLSTACK,
828-
"thread" => SanitizerSet::THREAD,
829-
"hwaddress" => SanitizerSet::HWADDRESS,
830-
"safestack" => SanitizerSet::SAFESTACK,
831-
_ => return false,
832-
}
816+
if let Some(s) = v {
817+
let sanitizer_set = SanitizerSet::from_comma_list(s);
818+
if sanitizer_set.is_ok() {
819+
*slot |= sanitizer_set.unwrap();
820+
true
821+
} else {
822+
false
833823
}
834-
true
835824
} else {
836825
false
837826
}
@@ -1648,6 +1637,8 @@ options! {
16481637
"output remarks for these optimization passes (space separated, or \"all\")"),
16491638
rpath: bool = (false, parse_bool, [UNTRACKED],
16501639
"set rpath values in libs/exes (default: no)"),
1640+
sanitize: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
1641+
"use one or multiple sanitizers"),
16511642
save_temps: bool = (false, parse_bool, [UNTRACKED],
16521643
"save all temporary output files during compilation (default: no)"),
16531644
soft_float: bool = (false, parse_bool, [TRACKED],
@@ -2018,8 +2009,6 @@ options! {
20182009
remark_dir: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
20192010
"directory into which to write optimization remarks (if not specified, they will be \
20202011
written to standard error output)"),
2021-
sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
2022-
"use a sanitizer"),
20232012
sanitizer_cfi_canonical_jump_tables: Option<bool> = (Some(true), parse_opt_bool, [TRACKED],
20242013
"enable canonical jump tables (default: yes)"),
20252014
sanitizer_cfi_generalize_pointers: Option<bool> = (None, parse_opt_bool, [TRACKED],

compiler/rustc_session/src/session.rs

+45-12
Original file line numberDiff line numberDiff line change
@@ -357,8 +357,12 @@ impl Session {
357357
self.opts.unstable_opts.coverage_options.discard_all_spans_in_codegen
358358
}
359359

360+
pub fn is_sanitizer_address_enabled(&self) -> bool {
361+
self.opts.cg.sanitize.contains(SanitizerSet::ADDRESS)
362+
}
363+
360364
pub fn is_sanitizer_cfi_enabled(&self) -> bool {
361-
self.opts.unstable_opts.sanitizer.contains(SanitizerSet::CFI)
365+
self.opts.cg.sanitize.contains(SanitizerSet::CFI)
362366
}
363367

364368
pub fn is_sanitizer_cfi_canonical_jump_tables_disabled(&self) -> bool {
@@ -377,8 +381,32 @@ impl Session {
377381
self.opts.unstable_opts.sanitizer_cfi_normalize_integers == Some(true)
378382
}
379383

384+
pub fn is_sanitizer_hwaddress_enabled(&self) -> bool {
385+
self.opts.cg.sanitize.contains(SanitizerSet::HWADDRESS)
386+
}
387+
380388
pub fn is_sanitizer_kcfi_enabled(&self) -> bool {
381-
self.opts.unstable_opts.sanitizer.contains(SanitizerSet::KCFI)
389+
self.opts.cg.sanitize.contains(SanitizerSet::KCFI)
390+
}
391+
392+
pub fn is_sanitizer_kernel_address_enabled(&self) -> bool {
393+
self.opts.cg.sanitize.contains(SanitizerSet::KERNELADDRESS)
394+
}
395+
396+
pub fn is_sanitizer_memory_enabled(&self) -> bool {
397+
self.opts.cg.sanitize.contains(SanitizerSet::MEMORY)
398+
}
399+
400+
pub fn is_sanitizer_memory_recover_enabled(&self) -> bool {
401+
self.opts.unstable_opts.sanitizer_recover.contains(SanitizerSet::MEMORY)
402+
}
403+
404+
pub fn is_sanitizer_memory_track_origins_enabled(&self) -> bool {
405+
self.opts.unstable_opts.sanitizer_memory_track_origins != 0
406+
}
407+
408+
pub fn is_sanitizer_thread_enabled(&self) -> bool {
409+
self.opts.cg.sanitize.contains(SanitizerSet::THREAD)
382410
}
383411

384412
pub fn is_split_lto_unit_enabled(&self) -> bool {
@@ -560,7 +588,10 @@ impl Session {
560588
// AddressSanitizer and KernelAddressSanitizer uses lifetimes to detect use after scope bugs.
561589
// MemorySanitizer uses lifetimes to detect use of uninitialized stack variables.
562590
// HWAddressSanitizer will use lifetimes to detect use after scope bugs in the future.
563-
|| self.opts.unstable_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS | SanitizerSet::MEMORY | SanitizerSet::HWADDRESS)
591+
|| self.is_sanitizer_address_enabled()
592+
|| self.is_sanitizer_kernel_address_enabled()
593+
|| self.is_sanitizer_memory_enabled()
594+
|| self.is_sanitizer_hwaddress_enabled()
564595
}
565596

566597
pub fn diagnostic_width(&self) -> usize {
@@ -688,7 +719,7 @@ impl Session {
688719
let more_names = self.opts.output_types.contains_key(&OutputType::LlvmAssembly)
689720
|| self.opts.output_types.contains_key(&OutputType::Bitcode)
690721
// AddressSanitizer and MemorySanitizer use alloca name when reporting an issue.
691-
|| self.opts.unstable_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY);
722+
|| self.is_sanitizer_address_enabled() || self.is_sanitizer_memory_enabled();
692723
!more_names
693724
}
694725
}
@@ -1131,14 +1162,19 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
11311162
}
11321163
}
11331164

1134-
// Sanitizers can only be used on platforms that we know have working sanitizer codegen.
1135-
let supported_sanitizers = sess.target.options.supported_sanitizers;
1136-
let mut unsupported_sanitizers = sess.opts.unstable_opts.sanitizer - supported_sanitizers;
1165+
let supported_sanitizers = if sess.unstable_options() {
1166+
sess.target.options.supported_sanitizers | sess.target.options.stable_sanitizers
1167+
} else {
1168+
sess.target.options.stable_sanitizers
1169+
};
1170+
let mut unsupported_sanitizers = sess.opts.cg.sanitize - supported_sanitizers;
1171+
11371172
// Niche: if `fixed-x18`, or effectively switching on `reserved-x18` flag, is enabled
11381173
// we should allow Shadow Call Stack sanitizer.
11391174
if sess.opts.unstable_opts.fixed_x18 && sess.target.arch == "aarch64" {
11401175
unsupported_sanitizers -= SanitizerSet::SHADOWCALLSTACK;
11411176
}
1177+
11421178
match unsupported_sanitizers.into_iter().count() {
11431179
0 => {}
11441180
1 => {
@@ -1153,18 +1189,15 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
11531189
}
11541190

11551191
// Cannot mix and match mutually-exclusive sanitizers.
1156-
if let Some((first, second)) = sess.opts.unstable_opts.sanitizer.mutually_exclusive() {
1192+
if let Some((first, second)) = sess.opts.cg.sanitize.mutually_exclusive() {
11571193
sess.dcx().emit_err(errors::CannotMixAndMatchSanitizers {
11581194
first: first.to_string(),
11591195
second: second.to_string(),
11601196
});
11611197
}
11621198

11631199
// Cannot enable crt-static with sanitizers on Linux
1164-
if sess.crt_static(None)
1165-
&& !sess.opts.unstable_opts.sanitizer.is_empty()
1166-
&& !sess.target.is_like_msvc
1167-
{
1200+
if sess.crt_static(None) && !sess.opts.cg.sanitize.is_empty() && !sess.target.is_like_msvc {
11681201
sess.dcx().emit_err(errors::CannotEnableCrtStaticLinux);
11691202
}
11701203

compiler/rustc_target/src/spec/json.rs

+12-26
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use serde_json::Value;
66

77
use super::{Target, TargetKind, TargetOptions, TargetWarnings};
88
use crate::json::{Json, ToJson};
9+
use crate::spec::SanitizerSet;
910

1011
impl Target {
1112
/// Loads a target descriptor from a JSON object.
@@ -313,32 +314,15 @@ impl Target {
313314
} );
314315
($key_name:ident, SanitizerSet) => ( {
315316
let name = (stringify!($key_name)).replace("_", "-");
316-
if let Some(o) = obj.remove(&name) {
317-
if let Some(a) = o.as_array() {
318-
for s in a {
319-
use super::SanitizerSet;
320-
base.$key_name |= match s.as_str() {
321-
Some("address") => SanitizerSet::ADDRESS,
322-
Some("cfi") => SanitizerSet::CFI,
323-
Some("dataflow") => SanitizerSet::DATAFLOW,
324-
Some("kcfi") => SanitizerSet::KCFI,
325-
Some("kernel-address") => SanitizerSet::KERNELADDRESS,
326-
Some("leak") => SanitizerSet::LEAK,
327-
Some("memory") => SanitizerSet::MEMORY,
328-
Some("memtag") => SanitizerSet::MEMTAG,
329-
Some("safestack") => SanitizerSet::SAFESTACK,
330-
Some("shadow-call-stack") => SanitizerSet::SHADOWCALLSTACK,
331-
Some("thread") => SanitizerSet::THREAD,
332-
Some("hwaddress") => SanitizerSet::HWADDRESS,
333-
Some(s) => return Err(format!("unknown sanitizer {}", s)),
334-
_ => return Err(format!("not a string: {:?}", s)),
335-
};
336-
}
337-
} else {
338-
incorrect_type.push(name)
339-
}
340-
}
341-
Ok::<(), String>(())
317+
obj.remove(&name).and_then(|o| match SanitizerSet::from_json(&o) {
318+
Ok(v) => {
319+
base.$key_name = v;
320+
Some(Ok(()))
321+
},
322+
Err(s) => Some(Err(
323+
format!("`{:?}` is not a valid value for `{}`: {}", o, name, s)
324+
)),
325+
}).unwrap_or(Ok(()))
342326
} );
343327
($key_name:ident, link_self_contained_components) => ( {
344328
// Skeleton of what needs to be parsed:
@@ -607,6 +591,7 @@ impl Target {
607591
key!(split_debuginfo, SplitDebuginfo)?;
608592
key!(supported_split_debuginfo, fallible_list)?;
609593
key!(supported_sanitizers, SanitizerSet)?;
594+
key!(stable_sanitizers, SanitizerSet)?;
610595
key!(generate_arange_section, bool);
611596
key!(supports_stack_protector, bool);
612597
key!(small_data_threshold_support, SmallDataThresholdSupport)?;
@@ -781,6 +766,7 @@ impl ToJson for Target {
781766
target_option_val!(split_debuginfo);
782767
target_option_val!(supported_split_debuginfo);
783768
target_option_val!(supported_sanitizers);
769+
target_option_val!(stable_sanitizers);
784770
target_option_val!(c_enum_min_bits);
785771
target_option_val!(generate_arange_section);
786772
target_option_val!(supports_stack_protector);

0 commit comments

Comments
 (0)