Relax restrictions on multiple sanitizers

Most combinations of LLVM sanitizers are legal-enough to enable
simultaneously. This change will allow simultaneously enabling ASAN and
shadow call stacks on supported platforms.
This commit is contained in:
David Koloski 2024-05-15 15:40:52 +00:00
parent 982a58e900
commit d7d3bd1221
2 changed files with 36 additions and 11 deletions

View file

@ -1181,9 +1181,9 @@ 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();
if let (Some(first), Some(second)) = (sanitizer_iter.next(), sanitizer_iter.next()) {
// Cannot mix and match mutually-exclusive sanitizers.
if let Some((first, second)) = sess.opts.unstable_opts.sanitizer.mutually_exclusive() {
sess.dcx().emit_err(errors::CannotMixAndMatchSanitizers {
first: first.to_string(),
second: second.to_string(),
@ -1218,14 +1218,6 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
sess.dcx().emit_err(errors::SanitizerCfiRequiresSingleCodegenUnit);
}
// LLVM CFI is incompatible with LLVM KCFI.
if sess.is_sanitizer_cfi_enabled() && sess.is_sanitizer_kcfi_enabled() {
sess.dcx().emit_err(errors::CannotMixAndMatchSanitizers {
first: "cfi".to_string(),
second: "kcfi".to_string(),
});
}
// Canonical jump tables requires CFI.
if sess.is_sanitizer_cfi_canonical_jump_tables_disabled() {
if !sess.is_sanitizer_cfi_enabled() {

View file

@ -1316,6 +1316,32 @@ bitflags::bitflags! {
rustc_data_structures::external_bitflags_debug! { SanitizerSet }
impl SanitizerSet {
const MUTUALLY_EXCLUSIVE: &'static [(SanitizerSet, SanitizerSet)] = &[
(SanitizerSet::MEMORY, SanitizerSet::ADDRESS),
(SanitizerSet::MEMORY, SanitizerSet::LEAK),
(SanitizerSet::THREAD, SanitizerSet::ADDRESS),
(SanitizerSet::THREAD, SanitizerSet::LEAK),
(SanitizerSet::THREAD, SanitizerSet::MEMORY),
(SanitizerSet::HWADDRESS, SanitizerSet::ADDRESS),
(SanitizerSet::HWADDRESS, SanitizerSet::MEMORY),
(SanitizerSet::HWADDRESS, SanitizerSet::THREAD),
(SanitizerSet::MEMTAG, SanitizerSet::ADDRESS),
(SanitizerSet::MEMTAG, SanitizerSet::HWADDRESS),
(SanitizerSet::KCFI, SanitizerSet::CFI),
(SanitizerSet::KERNELADDRESS, SanitizerSet::ADDRESS),
(SanitizerSet::KERNELADDRESS, SanitizerSet::LEAK),
(SanitizerSet::KERNELADDRESS, SanitizerSet::MEMORY),
(SanitizerSet::KERNELADDRESS, SanitizerSet::THREAD),
(SanitizerSet::KERNELADDRESS, SanitizerSet::HWADDRESS),
(SanitizerSet::KERNELADDRESS, SanitizerSet::MEMTAG),
(SanitizerSet::SAFESTACK, SanitizerSet::ADDRESS),
(SanitizerSet::SAFESTACK, SanitizerSet::LEAK),
(SanitizerSet::SAFESTACK, SanitizerSet::MEMORY),
(SanitizerSet::SAFESTACK, SanitizerSet::THREAD),
(SanitizerSet::SAFESTACK, SanitizerSet::HWADDRESS),
(SanitizerSet::SAFESTACK, SanitizerSet::KERNELADDRESS),
];
/// Return sanitizer's name
///
/// Returns none if the flags is a set of sanitizers numbering not exactly one.
@ -1336,6 +1362,13 @@ impl SanitizerSet {
_ => return None,
})
}
pub fn mutually_exclusive(self) -> Option<(SanitizerSet, SanitizerSet)> {
Self::MUTUALLY_EXCLUSIVE
.into_iter()
.find(|&(a, b)| self.contains(*a) && self.contains(*b))
.copied()
}
}
/// Formats a sanitizer set as a comma separated list of sanitizers' names.