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 @@ -94,7 +94,7 @@ fn get_attrs<'ll>(this: &ArgAttributes, cx: &CodegenCx<'ll, '_>) -> SmallVec<[&'
break;
}
}
} 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 @@ -263,7 +263,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 @@ -2718,7 +2718,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 @@ -634,6 +634,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!(split_debuginfo, Some(SplitDebuginfo::Packed));
tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0));
tracked!(target_cpu, Some(String::from("abc")));
Expand Down Expand Up @@ -851,7 +852,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
16 changes: 8 additions & 8 deletions compiler/rustc_session/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ pub(crate) struct SanitizersNotSupported {
}

#[derive(Diagnostic)]
#[diag("`-Zsanitizer={$first}` is incompatible with `-Zsanitizer={$second}`")]
#[diag("`-Csanitize={$first}` is incompatible with `-Csanitize={$second}`")]
pub(crate) struct CannotMixAndMatchSanitizers {
pub(crate) first: String,
pub(crate) second: String,
Expand All @@ -308,31 +308,31 @@ pub(crate) struct CannotMixAndMatchSanitizers {
pub(crate) struct CannotEnableCrtStaticLinux;

#[derive(Diagnostic)]
#[diag("`-Zsanitizer=cfi` requires `-Clto` or `-Clinker-plugin-lto`")]
#[diag("`-Csanitize=cfi` requires `-Clto` or `-Clinker-plugin-lto`")]
pub(crate) struct SanitizerCfiRequiresLto;

#[derive(Diagnostic)]
#[diag("`-Zsanitizer=cfi` with `-Clto` requires `-Ccodegen-units=1`")]
#[diag("`-Csanitize=cfi` with `-Clto` requires `-Ccodegen-units=1`")]
pub(crate) struct SanitizerCfiRequiresSingleCodegenUnit;

#[derive(Diagnostic)]
#[diag("`-Zsanitizer-cfi-canonical-jump-tables` requires `-Zsanitizer=cfi`")]
#[diag("`-Zsanitizer-cfi-canonical-jump-tables` requires `-Csanitize=cfi`")]
pub(crate) struct SanitizerCfiCanonicalJumpTablesRequiresCfi;

#[derive(Diagnostic)]
#[diag("`-Zsanitizer-cfi-generalize-pointers` requires `-Zsanitizer=cfi` or `-Zsanitizer=kcfi`")]
#[diag("`-Zsanitizer-cfi-generalize-pointers` requires `-Csanitize=cfi` or `-Csanitize=kcfi`")]
pub(crate) struct SanitizerCfiGeneralizePointersRequiresCfi;

#[derive(Diagnostic)]
#[diag("`-Zsanitizer-cfi-normalize-integers` requires `-Zsanitizer=cfi` or `-Zsanitizer=kcfi`")]
#[diag("`-Zsanitizer-cfi-normalize-integers` requires `-Csanitize=cfi` or `-Csanitize=kcfi`")]
pub(crate) struct SanitizerCfiNormalizeIntegersRequiresCfi;

#[derive(Diagnostic)]
#[diag("`-Zsanitizer-kcfi-arity` requires `-Zsanitizer=kcfi`")]
#[diag("`-Zsanitizer-kcfi-arity` requires `-Csanitize=kcfi`")]
pub(crate) struct SanitizerKcfiArityRequiresKcfi;

#[derive(Diagnostic)]
#[diag("`-Z sanitizer=kcfi` requires `-C panic=abort`")]
#[diag("`-Csanitize=kcfi` requires `-C panic=abort`")]
pub(crate) struct SanitizerKcfiRequiresPanicAbort;

#[derive(Diagnostic)]
Expand Down
40 changes: 14 additions & 26 deletions compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,18 +140,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::Sanitizer => {
return target_modifier_consistency_check::sanitizer(self, other);
}
},
OptionsTargetModifiers::UnstableOptions(unstable) => match unstable {
UnstableOptionsTargetModifiers::SanitizerCfiNormalizeIntegers => {
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 @@ -1214,27 +1215,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,
"kernel-hwaddress" => SanitizerSet::KERNELHWADDRESS,
"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 @@ -2151,6 +2139,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: Sanitizer },
"use one or multiple sanitizers"),
save_temps: bool = (false, parse_bool, [UNTRACKED],
"save all temporary output files during compilation (default: no)"),
soft_float: () = ((), parse_ignore, [UNTRACKED],
Expand Down Expand Up @@ -2585,9 +2576,6 @@ written to standard error output)"),
retpoline_external_thunk: bool = (false, parse_bool, [TRACKED] { TARGET_MODIFIER: RetpolineExternalThunk },
"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: Sanitizer },
"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
83 changes: 64 additions & 19 deletions compiler/rustc_session/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,10 @@ impl Session {
&self.opts.unstable_opts.coverage_options
}

pub fn is_sanitizer_address_enabled(&self) -> bool {
Comment thread
wesleywiser marked this conversation as resolved.
self.sanitizers().contains(SanitizerSet::ADDRESS)
}

pub fn is_sanitizer_cfi_enabled(&self) -> bool {
self.sanitizers().contains(SanitizerSet::CFI)
}
Expand All @@ -361,6 +365,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 @@ -369,6 +377,30 @@ 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_kernel_hwaddress_enabled(&self) -> bool {
self.sanitizers().contains(SanitizerSet::KERNELHWADDRESS)
}

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 @@ -543,13 +575,15 @@ impl Session {
/// Checks if LLVM lifetime markers should be emitted.
pub fn emit_lifetime_markers(&self) -> bool {
self.opts.optimize != config::OptLevel::No
// AddressSanitizer and KernelAddressSanitizer uses lifetimes to detect use after scope bugs.
//
// AddressSanitizer and KernelAddressSanitizer use lifetimes to detect use after scope bugs.
// MemorySanitizer uses lifetimes to detect use of uninitialized stack variables.
//
// HWAddressSanitizer and KernelHWAddressSanitizer will use lifetimes to detect use after
// scope bugs in the future.
|| self.sanitizers().intersects(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS | SanitizerSet::MEMORY | SanitizerSet::HWADDRESS | SanitizerSet::KERNELHWADDRESS)
|| self.is_sanitizer_address_enabled()
|| self.is_sanitizer_kernel_address_enabled()
|| self.is_sanitizer_kernel_hwaddress_enabled()
|| self.is_sanitizer_memory_enabled()
|| self.is_sanitizer_hwaddress_enabled()
}

pub fn diagnostic_width(&self) -> usize {
Expand Down Expand Up @@ -701,7 +735,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 @@ -934,7 +968,28 @@ impl Session {
}

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

pub fn supported_sanitizers(&self) -> SanitizerSet {
if self.unstable_options() {
self.target.options.supported_sanitizers | self.target.options.stable_sanitizers
} else {
self.target.options.stable_sanitizers
}
}

pub fn unsupported_sanitizers(&self) -> SanitizerSet {
let mut unsupported_sanitizers = self.sanitizers() - self.supported_sanitizers();

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

unsupported_sanitizers
}
}

Expand Down Expand Up @@ -1173,14 +1228,7 @@ 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;
// 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;
}
let unsupported_sanitizers = sess.unsupported_sanitizers();
match unsupported_sanitizers.into_iter().count() {
0 => {}
1 => {
Expand All @@ -1195,18 +1243,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
8 changes: 8 additions & 0 deletions compiler/rustc_target/src/spec/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,11 @@ impl Target {
default_sanitizers.into_iter().fold(SanitizerSet::empty(), |a, b| a | b);
}

if let Some(stable_sanitizers) = json.stable_sanitizers {
base.stable_sanitizers =
stable_sanitizers.into_iter().fold(SanitizerSet::empty(), |a, b| a | b);
}

forward!(generate_arange_section);
forward!(supports_stack_protector);
forward!(small_data_threshold_support);
Expand Down Expand Up @@ -401,6 +406,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 Expand Up @@ -624,6 +630,8 @@ struct TargetSpecJson {
supported_split_debuginfo: Option<StaticCow<[SplitDebuginfo]>>,
supported_sanitizers: Option<Vec<SanitizerSet>>,
default_sanitizers: Option<Vec<SanitizerSet>>,
#[serde(rename = "stable-sanitizers")]
stable_sanitizers: Option<Vec<SanitizerSet>>,
generate_arange_section: Option<bool>,
supports_stack_protector: Option<bool>,
small_data_threshold_support: Option<SmallDataThresholdSupport>,
Expand Down
Loading
Loading