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
6 changes: 4 additions & 2 deletions compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,15 @@ mod target_modifier_consistency_check {
l: &TargetModifier,
r: Option<&TargetModifier>,
) -> bool {
let mut lparsed: SanitizerSet = sess.target.options.default_sanitizers;
let mut lparsed: SanitizerSet = SanitizerSet::empty();
let lval = if l.value_name.is_empty() { None } else { Some(l.value_name.as_str()) };
parse::parse_sanitizers(&mut lparsed, lval);
let lparsed = lparsed.combine_with_defaults(sess.target.options.default_sanitizers);

let mut rparsed: SanitizerSet = sess.target.options.default_sanitizers;
let mut rparsed: SanitizerSet = SanitizerSet::empty();
let rval = r.filter(|v| !v.value_name.is_empty()).map(|v| v.value_name.as_str());
parse::parse_sanitizers(&mut rparsed, rval);
let rparsed = rparsed.combine_with_defaults(sess.target.options.default_sanitizers);

// Some sanitizers need to be target modifiers, and some do not.
// For now, we should mark all sanitizers as target modifiers except for these:
Expand Down
16 changes: 8 additions & 8 deletions compiler/rustc_session/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -929,7 +929,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.sanitizers().intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY);
!more_names
}
}
Expand Down Expand Up @@ -1178,7 +1178,10 @@ impl Session {
}

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

pub fn pointer_authentication(&self) -> bool {
Expand Down Expand Up @@ -1497,7 +1500,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;
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 {
Expand All @@ -1518,18 +1521,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.sanitizers().mutually_exclusive() {
sess.dcx().emit_err(diagnostics::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(diagnostics::CannotEnableCrtStaticLinux);
}

Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_structures/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@ pub use crate_type::CrateType;
pub use limit::Limit;
pub use native_lib_kind::NativeLibKind;
pub use sanitizer_set::SanitizerSet;

#[cfg(test)]
mod tests;
14 changes: 14 additions & 0 deletions compiler/rustc_structures/src/sanitizer_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,20 @@ impl SanitizerSet {
.find(|&(a, b)| self.contains(*a) && self.contains(*b))
.copied()
}

/// Disable default sanitizers that are incompatible with explicitly requested ones,
/// matching Clang's `SanitizerArgs` driver logic.
pub fn combine_with_defaults(self, mut defaults: SanitizerSet) -> SanitizerSet {
for &(a, b) in Self::MUTUALLY_EXCLUSIVE {
if defaults.contains(a) && self.contains(b) {
defaults -= a;
}
if defaults.contains(b) && self.contains(a) {
defaults -= b;
}
}
self | defaults
}
}

/// Formats a sanitizer set as a comma separated list of sanitizers' names.
Expand Down
36 changes: 36 additions & 0 deletions compiler/rustc_structures/src/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use super::*;

#[test]
fn test_combine_with_defaults_no_conflict() {
let defaults = SanitizerSet::SHADOWCALLSTACK;
let explicit = SanitizerSet::ADDRESS;
assert_eq!(
explicit.combine_with_defaults(defaults),
SanitizerSet::ADDRESS | SanitizerSet::SHADOWCALLSTACK
);
}

#[test]
fn test_combine_with_defaults_safestack_address_conflict() {
let defaults = SanitizerSet::SAFESTACK;
let explicit = SanitizerSet::ADDRESS;
// SafeStack should be implicitly disabled when Address is explicitly provided.
assert_eq!(explicit.combine_with_defaults(defaults), SanitizerSet::ADDRESS);
}

#[test]
fn test_combine_with_defaults_empty_explicit() {
let defaults = SanitizerSet::SAFESTACK;
let explicit = SanitizerSet::empty();
assert_eq!(explicit.combine_with_defaults(defaults), SanitizerSet::SAFESTACK);
}

#[test]
fn test_combine_with_defaults_safestack_cfi() {
let defaults = SanitizerSet::SAFESTACK;
let explicit = SanitizerSet::CFI;
assert_eq!(
explicit.combine_with_defaults(defaults),
SanitizerSet::CFI | SanitizerSet::SAFESTACK
);
}
Loading