diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 6939674ce9d..37b8f81ad94 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1230,7 +1230,10 @@ fn add_sanitizer_libraries( if sanitizer.contains(SanitizerSet::DATAFLOW) { link_sanitizer_runtime(sess, flavor, linker, "dfsan"); } - if sanitizer.contains(SanitizerSet::LEAK) { + if sanitizer.contains(SanitizerSet::LEAK) + && !sanitizer.contains(SanitizerSet::ADDRESS) + && !sanitizer.contains(SanitizerSet::HWADDRESS) + { link_sanitizer_runtime(sess, flavor, linker, "lsan"); } if sanitizer.contains(SanitizerSet::MEMORY) { diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index db01bb90d6f..a2872fc1661 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1183,9 +1183,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(), @@ -1220,14 +1220,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() { diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 910c6aeb7d6..83ee63e2cf2 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1317,6 +1317,34 @@ bitflags::bitflags! { rustc_data_structures::external_bitflags_debug! { SanitizerSet } impl SanitizerSet { + // Taken from LLVM's sanitizer compatibility logic: + // https://github.com/llvm/llvm-project/blob/release/18.x/clang/lib/Driver/SanitizerArgs.cpp#L512 + const MUTUALLY_EXCLUSIVE: &'static [(SanitizerSet, SanitizerSet)] = &[ + (SanitizerSet::ADDRESS, SanitizerSet::MEMORY), + (SanitizerSet::ADDRESS, SanitizerSet::THREAD), + (SanitizerSet::ADDRESS, SanitizerSet::HWADDRESS), + (SanitizerSet::ADDRESS, SanitizerSet::MEMTAG), + (SanitizerSet::ADDRESS, SanitizerSet::KERNELADDRESS), + (SanitizerSet::ADDRESS, SanitizerSet::SAFESTACK), + (SanitizerSet::LEAK, SanitizerSet::MEMORY), + (SanitizerSet::LEAK, SanitizerSet::THREAD), + (SanitizerSet::LEAK, SanitizerSet::KERNELADDRESS), + (SanitizerSet::LEAK, SanitizerSet::SAFESTACK), + (SanitizerSet::MEMORY, SanitizerSet::THREAD), + (SanitizerSet::MEMORY, SanitizerSet::HWADDRESS), + (SanitizerSet::MEMORY, SanitizerSet::KERNELADDRESS), + (SanitizerSet::MEMORY, SanitizerSet::SAFESTACK), + (SanitizerSet::THREAD, SanitizerSet::HWADDRESS), + (SanitizerSet::THREAD, SanitizerSet::KERNELADDRESS), + (SanitizerSet::THREAD, SanitizerSet::SAFESTACK), + (SanitizerSet::HWADDRESS, SanitizerSet::MEMTAG), + (SanitizerSet::HWADDRESS, SanitizerSet::KERNELADDRESS), + (SanitizerSet::HWADDRESS, SanitizerSet::SAFESTACK), + (SanitizerSet::CFI, SanitizerSet::KCFI), + (SanitizerSet::MEMTAG, SanitizerSet::KERNELADDRESS), + (SanitizerSet::KERNELADDRESS, SanitizerSet::SAFESTACK), + ]; + /// Return sanitizer's name /// /// Returns none if the flags is a set of sanitizers numbering not exactly one. @@ -1337,6 +1365,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. diff --git a/tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.aarch64.stderr b/tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.aarch64.stderr index 1006c3bc17e..7f596a19104 100644 --- a/tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.aarch64.stderr +++ b/tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.aarch64.stderr @@ -2,9 +2,5 @@ error: cfi sanitizer is not supported for this target error: `-Zsanitizer=cfi` is incompatible with `-Zsanitizer=kcfi` -error: `-Zsanitizer=cfi` is incompatible with `-Zsanitizer=kcfi` - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.x86_64.stderr b/tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.x86_64.stderr index 1006c3bc17e..7f596a19104 100644 --- a/tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.x86_64.stderr +++ b/tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.x86_64.stderr @@ -2,9 +2,5 @@ error: cfi sanitizer is not supported for this target error: `-Zsanitizer=cfi` is incompatible with `-Zsanitizer=kcfi` -error: `-Zsanitizer=cfi` is incompatible with `-Zsanitizer=kcfi` - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors