Skip to content

Commit

Permalink
sanitizers: Add stable and unstable sanitizers
Browse files Browse the repository at this point in the history
Add suppport for separating sanitizers support in stable and unstable
for supported targets.
  • Loading branch information
rcvalle committed Apr 17, 2024
1 parent 00ed4ed commit ef8dd4a
Show file tree
Hide file tree
Showing 49 changed files with 418 additions and 176 deletions.
1 change: 1 addition & 0 deletions compiler/rustc_interface/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,7 @@ fn test_codegen_options_tracking_hash() {
tracked!(profile_use, Some(PathBuf::from("abc")));
tracked!(relocation_model, Some(RelocModel::Pic));
tracked!(relro_level, Some(RelroLevel::Full));
tracked!(sanitizer, SanitizerSet::ADDRESS);
tracked!(soft_float, true);
tracked!(split_debuginfo, Some(SplitDebuginfo::Packed));
tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0));
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1540,6 +1540,8 @@ options! {
"output remarks for these optimization passes (space separated, or \"all\")"),
rpath: bool = (false, parse_bool, [UNTRACKED],
"set rpath values in libs/exes (default: no)"),
sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
"use a sanitizer"),
save_temps: bool = (false, parse_bool, [UNTRACKED],
"save all temporary output files during compilation (default: no)"),
soft_float: bool = (false, parse_bool, [TRACKED],
Expand Down
21 changes: 19 additions & 2 deletions compiler/rustc_session/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1163,7 +1163,23 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
}

// Sanitizers can only be used on platforms that we know have working sanitizer codegen.
let supported_sanitizers = sess.target.options.supported_sanitizers;
let supported_stable_sanitizers = sess.target.options.supported_sanitizers.stable_sanitizers();
let unsupported_sanitizers = sess.opts.cg.sanitizer - supported_stable_sanitizers;
match unsupported_sanitizers.into_iter().count() {
0 => {}
1 => {
sess.dcx()
.emit_err(errors::SanitizerNotSupported { us: unsupported_sanitizers.to_string() });
}
_ => {
sess.dcx().emit_err(errors::SanitizersNotSupported {
us: unsupported_sanitizers.to_string(),
});
}
}
// Allow both stable and unstable sanitizers to be used as an unstable option for backwards
// compatibility until they are all stabilized.
let supported_sanitizers = sess.target.options.supported_sanitizers.supported_sanitizers();
let unsupported_sanitizers = sess.opts.unstable_opts.sanitizer - supported_sanitizers;
match unsupported_sanitizers.into_iter().count() {
0 => {}
Expand All @@ -1178,7 +1194,8 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
}
}
// Cannot mix and match sanitizers.
let mut sanitizer_iter = sess.opts.unstable_opts.sanitizer.into_iter();
let mut sanitizer_iter =
sess.opts.cg.sanitizer.into_iter().chain(sess.opts.unstable_opts.sanitizer.into_iter());
if let (Some(first), Some(second)) = (sanitizer_iter.next(), sanitizer_iter.next()) {
sess.dcx().emit_err(errors::CannotMixAndMatchSanitizers {
first: first.to_string(),
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_target/src/spec/base/android.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::spec::{base, SanitizerSet, TargetOptions, TlsModel};
use crate::spec::{base, SanitizerSet, SanitizerSupport, TargetOptions, TlsModel};

pub fn opts() -> TargetOptions {
let mut base = base::linux::opts();
Expand All @@ -7,7 +7,8 @@ pub fn opts() -> TargetOptions {
base.default_dwarf_version = 2;
base.tls_model = TlsModel::Emulated;
base.has_thread_local = false;
base.supported_sanitizers = SanitizerSet::ADDRESS;
base.supported_sanitizers =
SanitizerSupport { stable: SanitizerSet::empty(), unstable: SanitizerSet::ADDRESS };
// This is for backward compatibility, see https://github.com/rust-lang/rust/issues/49867
// for context. (At that time, there was no `-C force-unwind-tables`, so the only solution
// was to always emit `uwtable`).
Expand Down
115 changes: 86 additions & 29 deletions compiler/rustc_target/src/spec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1364,6 +1364,46 @@ impl ToJson for SanitizerSet {
}
}

#[derive(Clone, Copy, PartialEq, Hash, Debug)]
/// Sanitizers supported by a target.
pub struct SanitizerSupport {
/// Sanitizers supported by a target that can be used on stable.
pub stable: SanitizerSet,
/// Sanitizers supported by a target that cannot be used on stable.
pub unstable: SanitizerSet,
}

impl SanitizerSupport {
/// Returns the set of stable sanitizers.
pub fn stable_sanitizers(&self) -> SanitizerSet {
self.stable
}

/// Returns the set of supported sanitizers.
pub fn supported_sanitizers(&self) -> SanitizerSet {
self.stable | self.unstable
}

/// Returns the set of unstable sanitizers.
pub fn unstable_sanitizers(&self) -> SanitizerSet {
self.unstable
}

/// Returns the set of unsupported sanitizers.
pub fn unsupported_sanitizers(&self) -> SanitizerSet {
SanitizerSet::empty() - (self.stable | self.unstable)
}
}

impl ToJson for SanitizerSupport {
fn to_json(&self) -> Json {
let mut object = serde_json::Map::new();
object.insert("stable".to_string(), self.stable.to_json());
object.insert("unstable".to_string(), self.unstable.to_json());
Json::Object(object)
}
}

#[derive(Clone, Copy, PartialEq, Hash, Debug)]
pub enum FramePointer {
/// Forces the machine code generator to always preserve the frame pointers.
Expand Down Expand Up @@ -2271,7 +2311,7 @@ pub struct TargetOptions {
/// Note that the support here is at a codegen level. If the machine code with sanitizer
/// enabled can generated on this target, but the necessary supporting libraries are not
/// distributed with the target, the sanitizer should still appear in this list for the target.
pub supported_sanitizers: SanitizerSet,
pub supported_sanitizers: SanitizerSupport,

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

let mut incorrect_type = vec![];

let parse_sanitizer_set = |sanitizers_json: &Json| -> Result<SanitizerSet, String> {
let mut sanitizer_set = SanitizerSet::empty();
if let Some(sanitizers) = sanitizers_json.as_array() {
for sanitizer in sanitizers {
let name = sanitizer
.as_str()
.ok_or_else(|| "Sanitizer name must be a string".to_string())?;
sanitizer_set |= match name {
"address" => SanitizerSet::ADDRESS,
"cfi" => SanitizerSet::CFI,
"dataflow" => SanitizerSet::DATAFLOW,
"kcfi" => SanitizerSet::KCFI,
"kernel-address" => SanitizerSet::KERNELADDRESS,
"leak" => SanitizerSet::LEAK,
"memory" => SanitizerSet::MEMORY,
"memtag" => SanitizerSet::MEMTAG,
"safestack" => SanitizerSet::SAFESTACK,
"shadow-call-stack" => SanitizerSet::SHADOWCALLSTACK,
"thread" => SanitizerSet::THREAD,
"hwaddress" => SanitizerSet::HWADDRESS,
_ => return Err(format!("unknown sanitizer {}", name)),
};
}
} else {
return Err("Expected a list of sanitizers".to_string());
}
Ok(sanitizer_set)
};

macro_rules! key {
($key_name:ident) => ( {
let name = (stringify!($key_name)).replace("_", "-");
Expand Down Expand Up @@ -2930,32 +3002,17 @@ impl Target {
)),
}).unwrap_or(Ok(()))
} );
($key_name:ident, SanitizerSet) => ( {
let name = (stringify!($key_name)).replace("_", "-");
if let Some(o) = obj.remove(&name) {
if let Some(a) = o.as_array() {
for s in a {
base.$key_name |= match s.as_str() {
Some("address") => SanitizerSet::ADDRESS,
Some("cfi") => SanitizerSet::CFI,
Some("dataflow") => SanitizerSet::DATAFLOW,
Some("kcfi") => SanitizerSet::KCFI,
Some("kernel-address") => SanitizerSet::KERNELADDRESS,
Some("leak") => SanitizerSet::LEAK,
Some("memory") => SanitizerSet::MEMORY,
Some("memtag") => SanitizerSet::MEMTAG,
Some("safestack") => SanitizerSet::SAFESTACK,
Some("shadow-call-stack") => SanitizerSet::SHADOWCALLSTACK,
Some("thread") => SanitizerSet::THREAD,
Some("hwaddress") => SanitizerSet::HWADDRESS,
Some(s) => return Err(format!("unknown sanitizer {}", s)),
_ => return Err(format!("not a string: {:?}", s)),
};
}
} else {
incorrect_type.push(name)
}
}
($key_name:ident, SanitizerSupport) => ( {
let stable_sanitizers_json = obj.remove("stable")
.unwrap_or_else(|| serde_json::Value::Array(Vec::new()));
let unstable_sanitizers_json = obj.remove("unstable")
.unwrap_or_else(|| serde_json::Value::Array(Vec::new()));
let stable_sanitizers = parse_sanitizer_set(&stable_sanitizers_json)?;
let unstable_sanitizers = parse_sanitizer_set(&unstable_sanitizers_json)?;
base.$key_name = SanitizerSupport {
stable: stable_sanitizers,
unstable: unstable_sanitizers,
};
Ok::<(), String>(())
} );
($key_name:ident, link_self_contained_components) => ( {
Expand Down Expand Up @@ -3237,7 +3294,7 @@ impl Target {
key!(debuginfo_kind, DebuginfoKind)?;
key!(split_debuginfo, SplitDebuginfo)?;
key!(supported_split_debuginfo, fallible_list)?;
key!(supported_sanitizers, SanitizerSet)?;
key!(supported_sanitizers, SanitizerSupport)?;
key!(default_adjusted_cabi, Option<Abi>)?;
key!(generate_arange_section, bool);
key!(supports_stack_protector, bool);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::spec::base::apple::{macos_llvm_target, opts, Arch};
use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
use crate::spec::{FramePointer, SanitizerSet, SanitizerSupport, Target, TargetOptions};

pub fn target() -> Target {
let arch = Arch::Arm64;
Expand All @@ -8,7 +8,10 @@ pub fn target() -> Target {
base.max_atomic_width = Some(128);

// FIXME: The leak sanitizer currently fails the tests, see #88132.
base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD;
base.supported_sanitizers = SanitizerSupport {
stable: SanitizerSet::empty(),
unstable: SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD,
};

Target {
// Clang automatically chooses a more specific target based on
Expand Down
7 changes: 5 additions & 2 deletions compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
use crate::spec::base::apple::{ios_llvm_target, opts, Arch};
use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
use crate::spec::{FramePointer, SanitizerSet, SanitizerSupport, Target, TargetOptions};

pub fn target() -> Target {
let arch = Arch::Arm64;
let mut base = opts("ios", arch);
base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD;
base.supported_sanitizers = SanitizerSupport {
stable: SanitizerSet::empty(),
unstable: SanitizerSet::ADDRESS | SanitizerSet::THREAD,
};

Target {
// Clang automatically chooses a more specific target based on
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
use crate::spec::base::apple::{mac_catalyst_llvm_target, opts, Arch};
use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
use crate::spec::{FramePointer, SanitizerSet, SanitizerSupport, Target, TargetOptions};

pub fn target() -> Target {
let arch = Arch::Arm64_macabi;
let mut base = opts("ios", arch);
base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::THREAD;
base.supported_sanitizers = SanitizerSupport {
stable: SanitizerSet::empty(),
unstable: SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::THREAD,
};

Target {
llvm_target: mac_catalyst_llvm_target(arch).into(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
use crate::spec::base::apple::{ios_sim_llvm_target, opts, Arch};
use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
use crate::spec::{FramePointer, SanitizerSet, SanitizerSupport, Target, TargetOptions};

pub fn target() -> Target {
let arch = Arch::Arm64_sim;
let mut base = opts("ios", arch);
base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD;
base.supported_sanitizers = SanitizerSupport {
stable: SanitizerSet::empty(),
unstable: SanitizerSet::ADDRESS | SanitizerSet::THREAD,
};

Target {
// Clang automatically chooses a more specific target based on
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
use crate::spec::base::apple::{opts, visionos_llvm_target, Arch};
use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
use crate::spec::{FramePointer, SanitizerSet, SanitizerSupport, Target, TargetOptions};

pub fn target() -> Target {
let arch = Arch::Arm64;
let mut base = opts("visionos", arch);
base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD;
base.supported_sanitizers = SanitizerSupport {
stable: SanitizerSet::empty(),
unstable: SanitizerSet::ADDRESS | SanitizerSet::THREAD,
};

Target {
llvm_target: visionos_llvm_target(arch).into(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
use crate::spec::base::apple::{opts, visionos_sim_llvm_target, Arch};
use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
use crate::spec::{FramePointer, SanitizerSet, SanitizerSupport, Target, TargetOptions};

pub fn target() -> Target {
let arch = Arch::Arm64_sim;
let mut base = opts("visionos", arch);
base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD;
base.supported_sanitizers = SanitizerSupport {
stable: SanitizerSet::empty(),
unstable: SanitizerSet::ADDRESS | SanitizerSet::THREAD,
};

Target {
llvm_target: visionos_sim_llvm_target(arch).into(),
Expand Down
15 changes: 9 additions & 6 deletions compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::spec::{base, SanitizerSet, StackProbeType, Target, TargetOptions};
use crate::spec::{base, SanitizerSet, SanitizerSupport, StackProbeType, Target, TargetOptions};

// See https://developer.android.com/ndk/guides/abis.html#arm64-v8a
// for target ABI requirements.
Expand All @@ -21,11 +21,14 @@ pub fn target() -> Target {
// the neon (ASIMD) and FP must exist on all android aarch64 targets.
features: "+v8a,+neon,+fp-armv8".into(),
stack_probes: StackProbeType::Inline,
supported_sanitizers: SanitizerSet::CFI
| SanitizerSet::HWADDRESS
| SanitizerSet::MEMTAG
| SanitizerSet::SHADOWCALLSTACK
| SanitizerSet::ADDRESS,
supported_sanitizers: SanitizerSupport {
stable: SanitizerSet::empty(),
unstable: SanitizerSet::ADDRESS
| SanitizerSet::CFI
| SanitizerSet::HWADDRESS
| SanitizerSet::MEMTAG
| SanitizerSet::SHADOWCALLSTACK,
},
supports_xray: true,
..base::android::opts()
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::spec::{base, SanitizerSet, StackProbeType, Target, TargetOptions};
use crate::spec::{base, SanitizerSet, SanitizerSupport, StackProbeType, Target, TargetOptions};

pub fn target() -> Target {
Target {
Expand All @@ -16,10 +16,13 @@ pub fn target() -> Target {
features: "+v8a".into(),
max_atomic_width: Some(128),
stack_probes: StackProbeType::Inline,
supported_sanitizers: SanitizerSet::ADDRESS
| SanitizerSet::CFI
| SanitizerSet::MEMORY
| SanitizerSet::THREAD,
supported_sanitizers: SanitizerSupport {
stable: SanitizerSet::empty(),
unstable: SanitizerSet::ADDRESS
| SanitizerSet::CFI
| SanitizerSet::MEMORY
| SanitizerSet::THREAD,
},
..base::freebsd::opts()
},
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::spec::{base, SanitizerSet, StackProbeType, Target, TargetOptions};
use crate::spec::{base, SanitizerSet, SanitizerSupport, StackProbeType, Target, TargetOptions};

pub fn target() -> Target {
Target {
Expand All @@ -16,9 +16,10 @@ pub fn target() -> Target {
features: "+v8a".into(),
max_atomic_width: Some(128),
stack_probes: StackProbeType::Inline,
supported_sanitizers: SanitizerSet::ADDRESS
| SanitizerSet::CFI
| SanitizerSet::SHADOWCALLSTACK,
supported_sanitizers: SanitizerSupport {
stable: SanitizerSet::empty(),
unstable: SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::SHADOWCALLSTACK,
},
..base::fuchsia::opts()
},
}
Expand Down
Loading

0 comments on commit ef8dd4a

Please sign in to comment.