From d7d3bd12214e68f8163a3c0fef88715c39073723 Mon Sep 17 00:00:00 2001 From: David Koloski Date: Wed, 15 May 2024 15:40:52 +0000 Subject: [PATCH 1/4] 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. --- compiler/rustc_session/src/session.rs | 14 +++--------- compiler/rustc_target/src/spec/mod.rs | 33 +++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 2bc14b43234d0..f8f6aa27c12c7 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -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() { diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 291a761913bf2..256fc9983efa8 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -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. From 1b934f3e8cb3c01dfcc8a5a8b23ebae8a41c2b4b Mon Sep 17 00:00:00 2001 From: David Koloski Date: Wed, 15 May 2024 15:40:52 +0000 Subject: [PATCH 2/4] Sort mutually-exclusive pairs, update fixed tests --- compiler/rustc_target/src/spec/mod.rs | 46 +++++++++---------- ...i-is-incompatible-with-kcfi.aarch64.stderr | 6 +-- ...fi-is-incompatible-with-kcfi.x86_64.stderr | 6 +-- 3 files changed, 25 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 256fc9983efa8..73c7e9d4aa439 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1317,29 +1317,29 @@ 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), + (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 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 1006c3bc17efc..7f596a19104e6 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 1006c3bc17efc..7f596a19104e6 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 From 5976494deb022fdb1b408d9ba3896c43adb44517 Mon Sep 17 00:00:00 2001 From: David Koloski Date: Wed, 15 May 2024 15:40:53 +0000 Subject: [PATCH 3/4] Don't link lsan rt if asan or hwasan are enabled --- compiler/rustc_codegen_ssa/src/back/link.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index b458f325b7373..d94ab37c3418c 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1229,7 +1229,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) { From 1e1143c49185af1a2b3f0daa4dd3332106f51b88 Mon Sep 17 00:00:00 2001 From: David Koloski Date: Fri, 17 May 2024 23:29:25 +0000 Subject: [PATCH 4/4] Add source for mutually-exclusive list --- compiler/rustc_target/src/spec/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 73c7e9d4aa439..993477ffb24e9 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1316,6 +1316,8 @@ 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),