Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_llvm/src/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use rustc_session::{Session, config};
use rustc_target::callconv::{
ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, CastTarget, FnAbi, PassMode,
};
use rustc_target::spec::{Arch, SanitizerSet};
use rustc_target::spec::Arch;
use smallvec::SmallVec;

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

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_llvm/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ fn probestack_attr<'ll, 'tcx>(cx: &SimpleCx<'ll>, tcx: TyCtxt<'tcx>) -> Option<&
// Currently stack probes seem somewhat incompatible with the address
// sanitizer and thread sanitizer. With asan we're already protected from
// stack overflow anyway so we don't really need stack probes regardless.
if tcx.sess.sanitizers().intersects(SanitizerSet::ADDRESS | SanitizerSet::THREAD) {
if tcx.sess.is_sanitizer_address_enabled() || tcx.sess.is_sanitizer_thread_enabled() {
return None;
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_ssa/src/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2494,7 +2494,7 @@ fn add_order_independent_options(
&& crate_type == CrateType::Executable
&& !matches!(flavor, LinkerFlavor::Gnu(Cc::Yes, _))
{
let prefix = if sess.sanitizers().contains(SanitizerSet::ADDRESS) { "asan/" } else { "" };
let prefix = if sess.is_sanitizer_address_enabled() { "asan/" } else { "" };
cmd.link_arg(format!("--dynamic-linker={prefix}ld.so.1"));
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_interface/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,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!(sanitize, SanitizerSet::ADDRESS);
tracked!(soft_float, true);
tracked!(split_debuginfo, Some(SplitDebuginfo::Packed));
tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0));
Expand Down Expand Up @@ -858,7 +859,6 @@ fn test_unstable_options_tracking_hash() {
tracked!(regparm, Some(3));
tracked!(relax_elf_relocations, Some(true));
tracked!(remap_cwd_prefix, Some(PathBuf::from("abc")));
tracked!(sanitizer, SanitizerSet::ADDRESS);
tracked!(sanitizer_cfi_canonical_jump_tables, None);
tracked!(sanitizer_cfi_generalize_pointers, Some(true));
tracked!(sanitizer_cfi_normalize_integers, Some(true));
Expand Down
12 changes: 6 additions & 6 deletions compiler/rustc_session/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ session_branch_protection_requires_aarch64 = `-Zbranch-protection` is only suppo

session_cannot_enable_crt_static_linux = sanitizer is incompatible with statically linked libc, disable it using `-C target-feature=-crt-static`

session_cannot_mix_and_match_sanitizers = `-Zsanitizer={$first}` is incompatible with `-Zsanitizer={$second}`
session_cannot_mix_and_match_sanitizers = `-Csanitize={$first}` is incompatible with `-Csanitize={$second}`

session_cli_feature_diagnostic_help =
add `-Zcrate-attr="feature({$feature})"` to the command-line options to enable
Expand Down Expand Up @@ -92,15 +92,15 @@ session_profile_sample_use_file_does_not_exist = file `{$path}` passed to `-C pr

session_profile_use_file_does_not_exist = file `{$path}` passed to `-C profile-use` does not exist

session_sanitizer_cfi_canonical_jump_tables_requires_cfi = `-Zsanitizer-cfi-canonical-jump-tables` requires `-Zsanitizer=cfi`
session_sanitizer_cfi_canonical_jump_tables_requires_cfi = `-Zsanitizer-cfi-canonical-jump-tables` requires `-Csanitize=cfi`

session_sanitizer_cfi_generalize_pointers_requires_cfi = `-Zsanitizer-cfi-generalize-pointers` requires `-Zsanitizer=cfi` or `-Zsanitizer=kcfi`
session_sanitizer_cfi_generalize_pointers_requires_cfi = `-Zsanitizer-cfi-generalize-pointers` requires `-Csanitize=cfi` or `-Csanitize=kcfi`

session_sanitizer_cfi_normalize_integers_requires_cfi = `-Zsanitizer-cfi-normalize-integers` requires `-Zsanitizer=cfi` or `-Zsanitizer=kcfi`
session_sanitizer_cfi_normalize_integers_requires_cfi = `-Zsanitizer-cfi-normalize-integers` requires `-Csanitize=cfi` or `-Csanitize=kcfi`

session_sanitizer_cfi_requires_lto = `-Zsanitizer=cfi` requires `-Clto` or `-Clinker-plugin-lto`
session_sanitizer_cfi_requires_lto = `-Csanitize=cfi` requires `-Clto` or `-Clinker-plugin-lto`

session_sanitizer_cfi_requires_single_codegen_unit = `-Zsanitizer=cfi` with `-Clto` requires `-Ccodegen-units=1`
session_sanitizer_cfi_requires_single_codegen_unit = `-Csanitize=cfi` with `-Clto` requires `-Ccodegen-units=1`

session_sanitizer_kcfi_arity_requires_kcfi = `-Zsanitizer-kcfi-arity` requires `-Zsanitizer=kcfi`

Expand Down
39 changes: 14 additions & 25 deletions compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,18 +136,19 @@ impl TargetModifier {
pub fn consistent(&self, sess: &Session, other: Option<&TargetModifier>) -> bool {
assert!(other.is_none() || self.opt == other.unwrap().opt);
match self.opt {
OptionsTargetModifiers::UnstableOptions(unstable) => match unstable {
UnstableOptionsTargetModifiers::sanitizer => {
OptionsTargetModifiers::CodegenOptions(stable) => match stable {
CodegenOptionsTargetModifiers::sanitize => {
return target_modifier_consistency_check::sanitizer(self, other);
}
},
OptionsTargetModifiers::UnstableOptions(unstable) => match unstable {
UnstableOptionsTargetModifiers::sanitizer_cfi_normalize_integers => {
return target_modifier_consistency_check::sanitizer_cfi_normalize_integers(
sess, self, other,
);
}
_ => {}
},
_ => {}
};
match other {
Some(other) => self.extend().tech_value == other.extend().tech_value,
Expand Down Expand Up @@ -1263,26 +1264,14 @@ pub mod parse {
}

pub(crate) fn parse_sanitizers(slot: &mut SanitizerSet, v: Option<&str>) -> bool {
if let Some(v) = v {
for s in v.split(',') {
*slot |= match s {
"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,
"shadow-call-stack" => SanitizerSet::SHADOWCALLSTACK,
"thread" => SanitizerSet::THREAD,
"hwaddress" => SanitizerSet::HWADDRESS,
"safestack" => SanitizerSet::SAFESTACK,
"realtime" => SanitizerSet::REALTIME,
_ => return false,
}
if let Some(s) = v {
let sanitizer_set = SanitizerSet::from_comma_list(s);
if sanitizer_set.is_ok() {
*slot |= sanitizer_set.unwrap();
true
} else {
false
}
true
} else {
false
}
Expand Down Expand Up @@ -2186,6 +2175,9 @@ 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)"),
#[rustc_lint_opt_deny_field_access("use `Session::sanitizers()` instead of this field")]
sanitize: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED TARGET_MODIFIER],
"use one or multiple sanitizers"),
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 Expand Up @@ -2604,9 +2596,6 @@ written to standard error output)"),
retpoline_external_thunk: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER],
"enables retpoline-external-thunk, retpoline-indirect-branches and retpoline-indirect-calls \
target features (default: no)"),
#[rustc_lint_opt_deny_field_access("use `Session::sanitizers()` instead of this field")]
sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED TARGET_MODIFIER],
"use a sanitizer"),
sanitizer_cfi_canonical_jump_tables: Option<bool> = (Some(true), parse_opt_bool, [TRACKED],
"enable canonical jump tables (default: yes)"),
sanitizer_cfi_generalize_pointers: Option<bool> = (None, parse_opt_bool, [TRACKED],
Expand Down
55 changes: 44 additions & 11 deletions compiler/rustc_session/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,10 @@ impl Session {
&self.opts.unstable_opts.coverage_options
}

pub fn is_sanitizer_address_enabled(&self) -> bool {
self.sanitizers().contains(SanitizerSet::ADDRESS)
}

pub fn is_sanitizer_cfi_enabled(&self) -> bool {
self.sanitizers().contains(SanitizerSet::CFI)
}
Expand All @@ -327,6 +331,10 @@ impl Session {
self.opts.unstable_opts.sanitizer_cfi_normalize_integers == Some(true)
}

pub fn is_sanitizer_hwaddress_enabled(&self) -> bool {
self.sanitizers().contains(SanitizerSet::HWADDRESS)
}

pub fn is_sanitizer_kcfi_arity_enabled(&self) -> bool {
self.opts.unstable_opts.sanitizer_kcfi_arity == Some(true)
}
Expand All @@ -335,6 +343,26 @@ impl Session {
self.sanitizers().contains(SanitizerSet::KCFI)
}

pub fn is_sanitizer_kernel_address_enabled(&self) -> bool {
self.sanitizers().contains(SanitizerSet::KERNELADDRESS)
}

pub fn is_sanitizer_memory_enabled(&self) -> bool {
self.sanitizers().contains(SanitizerSet::MEMORY)
}

pub fn is_sanitizer_memory_recover_enabled(&self) -> bool {
self.opts.unstable_opts.sanitizer_recover.contains(SanitizerSet::MEMORY)
}

pub fn is_sanitizer_memory_track_origins_enabled(&self) -> bool {
self.opts.unstable_opts.sanitizer_memory_track_origins != 0
}

pub fn is_sanitizer_thread_enabled(&self) -> bool {
self.sanitizers().contains(SanitizerSet::THREAD)
}

pub fn is_split_lto_unit_enabled(&self) -> bool {
self.opts.unstable_opts.split_lto_unit == Some(true)
}
Expand Down Expand Up @@ -512,7 +540,10 @@ impl Session {
// AddressSanitizer and KernelAddressSanitizer uses lifetimes to detect use after scope bugs.
// MemorySanitizer uses lifetimes to detect use of uninitialized stack variables.
// HWAddressSanitizer will use lifetimes to detect use after scope bugs in the future.
|| self.sanitizers().intersects(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS | SanitizerSet::MEMORY | SanitizerSet::HWADDRESS)
|| self.is_sanitizer_address_enabled()
|| self.is_sanitizer_kernel_address_enabled()
|| self.is_sanitizer_memory_enabled()
|| self.is_sanitizer_hwaddress_enabled()
}

pub fn diagnostic_width(&self) -> usize {
Expand Down Expand Up @@ -655,7 +686,7 @@ impl Session {
let more_names = self.opts.output_types.contains_key(&OutputType::LlvmAssembly)
|| self.opts.output_types.contains_key(&OutputType::Bitcode)
// AddressSanitizer and MemorySanitizer use alloca name when reporting an issue.
|| self.opts.unstable_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY);
|| self.is_sanitizer_address_enabled() || self.is_sanitizer_memory_enabled();
!more_names
}
}
Expand Down Expand Up @@ -901,7 +932,7 @@ impl Session {
}

pub fn sanitizers(&self) -> SanitizerSet {
return self.opts.unstable_opts.sanitizer | self.target.options.default_sanitizers;
return self.opts.cg.sanitize | self.target.options.default_sanitizers;
}
}

Expand Down Expand Up @@ -1169,14 +1200,19 @@ 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 mut unsupported_sanitizers = sess.opts.unstable_opts.sanitizer - supported_sanitizers;
let supported_sanitizers = if sess.unstable_options() {
sess.target.options.supported_sanitizers | sess.target.options.stable_sanitizers
} else {
sess.target.options.stable_sanitizers
};
let mut unsupported_sanitizers = sess.sanitizers() - supported_sanitizers;

// Niche: if `fixed-x18`, or effectively switching on `reserved-x18` flag, is enabled
// we should allow Shadow Call Stack sanitizer.
if sess.opts.unstable_opts.fixed_x18 && sess.target.arch == Arch::AArch64 {
unsupported_sanitizers -= SanitizerSet::SHADOWCALLSTACK;
}

match unsupported_sanitizers.into_iter().count() {
0 => {}
1 => {
Expand All @@ -1191,18 +1227,15 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
}

// Cannot mix and match mutually-exclusive sanitizers.
if let Some((first, second)) = sess.opts.unstable_opts.sanitizer.mutually_exclusive() {
if let Some((first, second)) = sess.opts.cg.sanitize.mutually_exclusive() {
sess.dcx().emit_err(errors::CannotMixAndMatchSanitizers {
first: first.to_string(),
second: second.to_string(),
});
}

// Cannot enable crt-static with sanitizers on Linux
if sess.crt_static(None)
&& !sess.opts.unstable_opts.sanitizer.is_empty()
&& !sess.target.is_like_msvc
{
if sess.crt_static(None) && !sess.sanitizers().is_empty() && !sess.target.is_like_msvc {
sess.dcx().emit_err(errors::CannotEnableCrtStaticLinux);
}

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_target/src/spec/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,7 @@ impl ToJson for Target {
target_option_val!(supported_split_debuginfo);
target_option_val!(supported_sanitizers);
target_option_val!(default_sanitizers);
target_option_val!(stable_sanitizers);
target_option_val!(c_enum_min_bits);
target_option_val!(generate_arange_section);
target_option_val!(supports_stack_protector);
Expand Down
42 changes: 41 additions & 1 deletion compiler/rustc_target/src/spec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1233,6 +1233,38 @@ impl SanitizerSet {
})
}

pub fn from_comma_list(s: &str) -> Result<Self, String> {
let mut sanitizer_set = SanitizerSet::empty();
for name in s.split(',') {
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,
"realtime" => SanitizerSet::REALTIME,
"safestack" => SanitizerSet::SAFESTACK,
"shadow-call-stack" => SanitizerSet::SHADOWCALLSTACK,
"thread" => SanitizerSet::THREAD,
"hwaddress" => SanitizerSet::HWADDRESS,
_ => return Err(format!("Unknown sanitizer {}", name)),
};
}
return Ok(sanitizer_set);
}

pub fn from_json(json: &Json) -> Result<Self, String> {
if let Some(array) = json.as_array() {
let s: String = array.iter().filter_map(|v| v.as_str()).collect::<Vec<_>>().join(",");
return Self::from_comma_list(&s);
} else {
return Err("Expected a list of sanitizers".to_string());
}
}

pub fn mutually_exclusive(self) -> Option<(SanitizerSet, SanitizerSet)> {
Self::MUTUALLY_EXCLUSIVE
.into_iter()
Expand Down Expand Up @@ -1269,11 +1301,11 @@ impl FromStr for SanitizerSet {
"leak" => SanitizerSet::LEAK,
"memory" => SanitizerSet::MEMORY,
"memtag" => SanitizerSet::MEMTAG,
"realtime" => SanitizerSet::REALTIME,
"safestack" => SanitizerSet::SAFESTACK,
"shadow-call-stack" => SanitizerSet::SHADOWCALLSTACK,
"thread" => SanitizerSet::THREAD,
"hwaddress" => SanitizerSet::HWADDRESS,
"realtime" => SanitizerSet::REALTIME,
s => return Err(format!("unknown sanitizer {s}")),
})
}
Expand Down Expand Up @@ -2563,6 +2595,13 @@ pub struct TargetOptions {
/// distributed with the target, the sanitizer should still appear in this list for the target.
pub default_sanitizers: SanitizerSet,

/// The stable sanitizers supported by this target
///
/// 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 stable_sanitizers: SanitizerSet,

/// Minimum number of bits in #[repr(C)] enum. Defaults to the size of c_int
pub c_enum_min_bits: Option<u64>,

Expand Down Expand Up @@ -2817,6 +2856,7 @@ impl Default for TargetOptions {
supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
supported_sanitizers: SanitizerSet::empty(),
default_sanitizers: SanitizerSet::empty(),
stable_sanitizers: SanitizerSet::empty(),
c_enum_min_bits: None,
generate_arange_section: true,
supports_stack_protector: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ pub(crate) fn target() -> Target {
// FIXME: The leak sanitizer currently fails the tests, see #88132.
supported_sanitizers: SanitizerSet::ADDRESS
| SanitizerSet::CFI
| SanitizerSet::THREAD
| SanitizerSet::REALTIME,
| SanitizerSet::REALTIME
| SanitizerSet::THREAD,
stable_sanitizers: SanitizerSet::ADDRESS,
supports_xray: true,
..opts
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,14 @@ pub(crate) fn target() -> Target {
stack_probes: StackProbeType::Inline,
supported_sanitizers: SanitizerSet::ADDRESS
| SanitizerSet::CFI
| SanitizerSet::HWADDRESS
| SanitizerSet::KCFI
| SanitizerSet::LEAK
| SanitizerSet::MEMORY
| SanitizerSet::MEMTAG
| SanitizerSet::THREAD
| SanitizerSet::HWADDRESS
| SanitizerSet::REALTIME,
| SanitizerSet::REALTIME
| SanitizerSet::THREAD,
stable_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::LEAK,
supports_xray: true,
..base::linux_gnu::opts()
},
Expand Down
Loading
Loading