Skip to content

Commit 91bd12e

Browse files
rcvalleRamon de C Valle
authored and
Ramon de C Valle
committed
sanitizers: Add stable and unstable sanitizers
Add suppport for separating sanitizers support in stable and unstable for supported targets.
1 parent 7f2fc33 commit 91bd12e

File tree

124 files changed

+528
-303
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

+528
-303
lines changed

compiler/rustc_codegen_llvm/src/abi.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ use rustc_session::config;
1818
pub use rustc_target::abi::call::*;
1919
use rustc_target::abi::{self, HasDataLayout, Int, Size};
2020
pub use rustc_target::spec::abi::Abi;
21-
use rustc_target::spec::SanitizerSet;
2221

2322
use libc::c_uint;
2423
use smallvec::SmallVec;
@@ -82,7 +81,7 @@ fn get_attrs<'ll>(this: &ArgAttributes, cx: &CodegenCx<'ll, '_>) -> SmallVec<[&'
8281
attrs.push(llattr.create_attr(cx.llcx));
8382
}
8483
}
85-
} else if cx.tcx.sess.opts.unstable_opts.sanitizer.contains(SanitizerSet::MEMORY) {
84+
} else if cx.tcx.sess.is_sanitizer_memory_enabled() {
8685
// If we're not optimising, *but* memory sanitizer is on, emit noundef, since it affects
8786
// memory sanitizer's behavior.
8887

compiler/rustc_codegen_llvm/src/attributes.rs

+2-8
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ pub fn sanitize_attrs<'ll>(
6060
no_sanitize: SanitizerSet,
6161
) -> SmallVec<[&'ll Attribute; 4]> {
6262
let mut attrs = SmallVec::new();
63-
let enabled = cx.tcx.sess.opts.unstable_opts.sanitizer - no_sanitize;
63+
let enabled = cx.tcx.sess.opts.cg.sanitizer - no_sanitize;
6464
if enabled.contains(SanitizerSet::ADDRESS) || enabled.contains(SanitizerSet::KERNELADDRESS) {
6565
attrs.push(llvm::AttributeKind::SanitizeAddress.create_attr(cx.llcx));
6666
}
@@ -192,13 +192,7 @@ fn probestack_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
192192
// Currently stack probes seem somewhat incompatible with the address
193193
// sanitizer and thread sanitizer. With asan we're already protected from
194194
// stack overflow anyway so we don't really need stack probes regardless.
195-
if cx
196-
.sess()
197-
.opts
198-
.unstable_opts
199-
.sanitizer
200-
.intersects(SanitizerSet::ADDRESS | SanitizerSet::THREAD)
201-
{
195+
if cx.sess().is_sanitizer_address_enabled() || cx.sess().is_sanitizer_thread_enabled() {
202196
return None;
203197
}
204198

compiler/rustc_codegen_ssa/src/back/link.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -1222,7 +1222,7 @@ fn add_sanitizer_libraries(
12221222
return;
12231223
}
12241224

1225-
let sanitizer = sess.opts.unstable_opts.sanitizer;
1225+
let sanitizer = sess.opts.cg.sanitizer;
12261226
if sanitizer.contains(SanitizerSet::ADDRESS) {
12271227
link_sanitizer_runtime(sess, flavor, linker, "asan");
12281228
}
@@ -2350,11 +2350,7 @@ fn add_order_independent_options(
23502350
&& crate_type == CrateType::Executable
23512351
&& !matches!(flavor, LinkerFlavor::Gnu(Cc::Yes, _))
23522352
{
2353-
let prefix = if sess.opts.unstable_opts.sanitizer.contains(SanitizerSet::ADDRESS) {
2354-
"asan/"
2355-
} else {
2356-
""
2357-
};
2353+
let prefix = if sess.is_sanitizer_address_enabled() { "asan/" } else { "" };
23582354
cmd.arg(format!("--dynamic-linker={prefix}ld.so.1"));
23592355
}
23602356

compiler/rustc_codegen_ssa/src/back/symbol_export.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use rustc_middle::ty::{self, SymbolName, TyCtxt};
1616
use rustc_middle::ty::{GenericArgKind, GenericArgsRef};
1717
use rustc_middle::util::Providers;
1818
use rustc_session::config::{CrateType, OomStrategy};
19-
use rustc_target::spec::{SanitizerSet, TlsModel};
19+
use rustc_target::spec::TlsModel;
2020

2121
pub fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel {
2222
crates_export_threshold(tcx.crate_types())
@@ -265,15 +265,15 @@ fn exported_symbols_provider_local(
265265
}));
266266
}
267267

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

271271
// Similar to profiling, preserve weak msan symbol during LTO.
272-
if tcx.sess.opts.unstable_opts.sanitizer_recover.contains(SanitizerSet::MEMORY) {
272+
if tcx.sess.is_sanitizer_memory_enabled() {
273273
msan_weak_symbols.push("__msan_keep_going");
274274
}
275275

276-
if tcx.sess.opts.unstable_opts.sanitizer_memory_track_origins != 0 {
276+
if tcx.sess.is_sanitizer_memory_track_origins_enabled() {
277277
msan_weak_symbols.push("__msan_track_origins");
278278
}
279279

compiler/rustc_codegen_ssa/src/back/write.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ impl ModuleConfig {
197197
false
198198
),
199199

200-
sanitizer: if_regular!(sess.opts.unstable_opts.sanitizer, SanitizerSet::empty()),
200+
sanitizer: if_regular!(sess.opts.cg.sanitizer, SanitizerSet::empty()),
201201
sanitizer_dataflow_abilist: if_regular!(
202202
sess.opts.unstable_opts.sanitizer_dataflow_abilist.clone(),
203203
Vec::new()

compiler/rustc_interface/src/tests.rs

+1
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,7 @@ fn test_codegen_options_tracking_hash() {
625625
tracked!(profile_use, Some(PathBuf::from("abc")));
626626
tracked!(relocation_model, Some(RelocModel::Pic));
627627
tracked!(relro_level, Some(RelroLevel::Full));
628+
tracked!(sanitizer, SanitizerSet::ADDRESS);
628629
tracked!(soft_float, true);
629630
tracked!(split_debuginfo, Some(SplitDebuginfo::Packed));
630631
tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0));

compiler/rustc_session/src/config/cfg.rs

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

134-
for mut s in sess.opts.unstable_opts.sanitizer {
134+
for mut s in sess.opts.cg.sanitizer {
135135
// KASAN is still ASAN under the hood, so it uses the same attribute.
136136
if s == SanitizerSet::KERNELADDRESS {
137137
s = SanitizerSet::ADDRESS;

compiler/rustc_session/src/options.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1554,6 +1554,8 @@ options! {
15541554
"output remarks for these optimization passes (space separated, or \"all\")"),
15551555
rpath: bool = (false, parse_bool, [UNTRACKED],
15561556
"set rpath values in libs/exes (default: no)"),
1557+
sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
1558+
"use a sanitizer"),
15571559
save_temps: bool = (false, parse_bool, [UNTRACKED],
15581560
"save all temporary output files during compilation (default: no)"),
15591561
soft_float: bool = (false, parse_bool, [TRACKED],
@@ -1907,8 +1909,6 @@ options! {
19071909
remark_dir: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
19081910
"directory into which to write optimization remarks (if not specified, they will be \
19091911
written to standard error output)"),
1910-
sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
1911-
"use a sanitizer"),
19121912
sanitizer_cfi_canonical_jump_tables: Option<bool> = (Some(true), parse_opt_bool, [TRACKED],
19131913
"enable canonical jump tables (default: yes)"),
19141914
sanitizer_cfi_generalize_pointers: Option<bool> = (None, parse_opt_bool, [TRACKED],

compiler/rustc_session/src/session.rs

+24-11
Original file line numberDiff line numberDiff line change
@@ -356,8 +356,12 @@ impl Session {
356356
self.instrument_coverage() && self.opts.unstable_opts.coverage_options.mcdc
357357
}
358358

359+
pub fn is_sanitizer_address_enabled(&self) -> bool {
360+
self.opts.cg.sanitizer.contains(SanitizerSet::ADDRESS)
361+
}
362+
359363
pub fn is_sanitizer_cfi_enabled(&self) -> bool {
360-
self.opts.unstable_opts.sanitizer.contains(SanitizerSet::CFI)
364+
self.opts.cg.sanitizer.contains(SanitizerSet::CFI)
361365
}
362366

363367
pub fn is_sanitizer_cfi_canonical_jump_tables_disabled(&self) -> bool {
@@ -377,7 +381,19 @@ impl Session {
377381
}
378382

379383
pub fn is_sanitizer_kcfi_enabled(&self) -> bool {
380-
self.opts.unstable_opts.sanitizer.contains(SanitizerSet::KCFI)
384+
self.opts.cg.sanitizer.contains(SanitizerSet::KCFI)
385+
}
386+
387+
pub fn is_sanitizer_memory_enabled(&self) -> bool {
388+
self.opts.cg.sanitizer.contains(SanitizerSet::MEMORY)
389+
}
390+
391+
pub fn is_sanitizer_memory_track_origins_enabled(&self) -> bool {
392+
self.opts.unstable_opts.sanitizer_memory_track_origins != 0
393+
}
394+
395+
pub fn is_sanitizer_thread_enabled(&self) -> bool {
396+
self.opts.cg.sanitizer.contains(SanitizerSet::THREAD)
381397
}
382398

383399
pub fn is_split_lto_unit_enabled(&self) -> bool {
@@ -595,7 +611,7 @@ impl Session {
595611
// AddressSanitizer and KernelAddressSanitizer uses lifetimes to detect use after scope bugs.
596612
// MemorySanitizer uses lifetimes to detect use of uninitialized stack variables.
597613
// HWAddressSanitizer will use lifetimes to detect use after scope bugs in the future.
598-
|| self.opts.unstable_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS | SanitizerSet::MEMORY | SanitizerSet::HWADDRESS)
614+
|| self.opts.cg.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS | SanitizerSet::MEMORY | SanitizerSet::HWADDRESS)
599615
}
600616

601617
pub fn diagnostic_width(&self) -> usize {
@@ -722,7 +738,7 @@ impl Session {
722738
let more_names = self.opts.output_types.contains_key(&OutputType::LlvmAssembly)
723739
|| self.opts.output_types.contains_key(&OutputType::Bitcode)
724740
// AddressSanitizer and MemorySanitizer use alloca name when reporting an issue.
725-
|| self.opts.unstable_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY);
741+
|| self.opts.cg.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY);
726742
!more_names
727743
}
728744
}
@@ -1167,8 +1183,8 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
11671183
}
11681184

11691185
// Sanitizers can only be used on platforms that we know have working sanitizer codegen.
1170-
let supported_sanitizers = sess.target.options.supported_sanitizers;
1171-
let unsupported_sanitizers = sess.opts.unstable_opts.sanitizer - supported_sanitizers;
1186+
let supported_sanitizers = sess.target.options.supported_sanitizers.supported_sanitizers();
1187+
let unsupported_sanitizers = sess.opts.cg.sanitizer - supported_sanitizers;
11721188
match unsupported_sanitizers.into_iter().count() {
11731189
0 => {}
11741190
1 => {
@@ -1182,7 +1198,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
11821198
}
11831199
}
11841200
// Cannot mix and match sanitizers.
1185-
let mut sanitizer_iter = sess.opts.unstable_opts.sanitizer.into_iter();
1201+
let mut sanitizer_iter = sess.opts.cg.sanitizer.into_iter();
11861202
if let (Some(first), Some(second)) = (sanitizer_iter.next(), sanitizer_iter.next()) {
11871203
sess.dcx().emit_err(errors::CannotMixAndMatchSanitizers {
11881204
first: first.to_string(),
@@ -1191,10 +1207,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
11911207
}
11921208

11931209
// Cannot enable crt-static with sanitizers on Linux
1194-
if sess.crt_static(None)
1195-
&& !sess.opts.unstable_opts.sanitizer.is_empty()
1196-
&& !sess.target.is_like_msvc
1197-
{
1210+
if sess.crt_static(None) && !sess.opts.cg.sanitizer.is_empty() && !sess.target.is_like_msvc {
11981211
sess.dcx().emit_err(errors::CannotEnableCrtStaticLinux);
11991212
}
12001213

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

+81-29
Original file line numberDiff line numberDiff line change
@@ -1364,6 +1364,41 @@ 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+
1393+
impl ToJson for SanitizerSupport {
1394+
fn to_json(&self) -> Json {
1395+
let mut object = serde_json::Map::new();
1396+
object.insert("stable".to_string(), self.stable.to_json());
1397+
object.insert("unstable".to_string(), self.unstable.to_json());
1398+
Json::Object(object)
1399+
}
1400+
}
1401+
13671402
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
13681403
pub enum FramePointer {
13691404
/// Forces the machine code generator to always preserve the frame pointers.
@@ -2284,7 +2319,7 @@ pub struct TargetOptions {
22842319
/// Note that the support here is at a codegen level. If the machine code with sanitizer
22852320
/// enabled can generated on this target, but the necessary supporting libraries are not
22862321
/// distributed with the target, the sanitizer should still appear in this list for the target.
2287-
pub supported_sanitizers: SanitizerSet,
2322+
pub supported_sanitizers: SanitizerSupport,
22882323

22892324
/// Minimum number of bits in #[repr(C)] enum. Defaults to the size of c_int
22902325
pub c_enum_min_bits: Option<u64>,
@@ -2516,7 +2551,10 @@ impl Default for TargetOptions {
25162551
split_debuginfo: Default::default(),
25172552
// `Off` is supported by default, but targets can remove this manually, e.g. Windows.
25182553
supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
2519-
supported_sanitizers: SanitizerSet::empty(),
2554+
supported_sanitizers: SanitizerSupport {
2555+
stable: SanitizerSet::empty(),
2556+
unstable: SanitizerSet::empty(),
2557+
},
25202558
c_enum_min_bits: None,
25212559
generate_arange_section: true,
25222560
supports_stack_protector: true,
@@ -2718,6 +2756,35 @@ impl Target {
27182756

27192757
let mut incorrect_type = vec![];
27202758

2759+
let parse_sanitizer_set = |sanitizers_json: &Json| -> Result<SanitizerSet, String> {
2760+
let mut sanitizer_set = SanitizerSet::empty();
2761+
if let Some(sanitizers) = sanitizers_json.as_array() {
2762+
for sanitizer in sanitizers {
2763+
let name = sanitizer
2764+
.as_str()
2765+
.ok_or_else(|| "Sanitizer name must be a string".to_string())?;
2766+
sanitizer_set |= match name {
2767+
"address" => SanitizerSet::ADDRESS,
2768+
"cfi" => SanitizerSet::CFI,
2769+
"dataflow" => SanitizerSet::DATAFLOW,
2770+
"kcfi" => SanitizerSet::KCFI,
2771+
"kernel-address" => SanitizerSet::KERNELADDRESS,
2772+
"leak" => SanitizerSet::LEAK,
2773+
"memory" => SanitizerSet::MEMORY,
2774+
"memtag" => SanitizerSet::MEMTAG,
2775+
"safestack" => SanitizerSet::SAFESTACK,
2776+
"shadow-call-stack" => SanitizerSet::SHADOWCALLSTACK,
2777+
"thread" => SanitizerSet::THREAD,
2778+
"hwaddress" => SanitizerSet::HWADDRESS,
2779+
_ => return Err(format!("unknown sanitizer {}", name)),
2780+
};
2781+
}
2782+
} else {
2783+
return Err("Expected a list of sanitizers".to_string());
2784+
}
2785+
Ok(sanitizer_set)
2786+
};
2787+
27212788
macro_rules! key {
27222789
($key_name:ident) => ( {
27232790
let name = (stringify!($key_name)).replace("_", "-");
@@ -2951,32 +3018,17 @@ impl Target {
29513018
)),
29523019
}).unwrap_or(Ok(()))
29533020
} );
2954-
($key_name:ident, SanitizerSet) => ( {
2955-
let name = (stringify!($key_name)).replace("_", "-");
2956-
if let Some(o) = obj.remove(&name) {
2957-
if let Some(a) = o.as_array() {
2958-
for s in a {
2959-
base.$key_name |= match s.as_str() {
2960-
Some("address") => SanitizerSet::ADDRESS,
2961-
Some("cfi") => SanitizerSet::CFI,
2962-
Some("dataflow") => SanitizerSet::DATAFLOW,
2963-
Some("kcfi") => SanitizerSet::KCFI,
2964-
Some("kernel-address") => SanitizerSet::KERNELADDRESS,
2965-
Some("leak") => SanitizerSet::LEAK,
2966-
Some("memory") => SanitizerSet::MEMORY,
2967-
Some("memtag") => SanitizerSet::MEMTAG,
2968-
Some("safestack") => SanitizerSet::SAFESTACK,
2969-
Some("shadow-call-stack") => SanitizerSet::SHADOWCALLSTACK,
2970-
Some("thread") => SanitizerSet::THREAD,
2971-
Some("hwaddress") => SanitizerSet::HWADDRESS,
2972-
Some(s) => return Err(format!("unknown sanitizer {}", s)),
2973-
_ => return Err(format!("not a string: {:?}", s)),
2974-
};
2975-
}
2976-
} else {
2977-
incorrect_type.push(name)
2978-
}
2979-
}
3021+
($key_name:ident, SanitizerSupport) => ( {
3022+
let stable_sanitizers_json = obj.remove("stable")
3023+
.unwrap_or_else(|| serde_json::Value::Array(Vec::new()));
3024+
let unstable_sanitizers_json = obj.remove("unstable")
3025+
.unwrap_or_else(|| serde_json::Value::Array(Vec::new()));
3026+
let stable_sanitizers = parse_sanitizer_set(&stable_sanitizers_json)?;
3027+
let unstable_sanitizers = parse_sanitizer_set(&unstable_sanitizers_json)?;
3028+
base.$key_name = SanitizerSupport {
3029+
stable: stable_sanitizers,
3030+
unstable: unstable_sanitizers,
3031+
};
29803032
Ok::<(), String>(())
29813033
} );
29823034
($key_name:ident, link_self_contained_components) => ( {
@@ -3248,7 +3300,7 @@ impl Target {
32483300
key!(debuginfo_kind, DebuginfoKind)?;
32493301
key!(split_debuginfo, SplitDebuginfo)?;
32503302
key!(supported_split_debuginfo, fallible_list)?;
3251-
key!(supported_sanitizers, SanitizerSet)?;
3303+
key!(supported_sanitizers, SanitizerSupport)?;
32523304
key!(generate_arange_section, bool);
32533305
key!(supports_stack_protector, bool);
32543306
key!(entry_name);

0 commit comments

Comments
 (0)