Auto merge of #124676 - djkoloski:relax_multiple_sanitizers, r=cuviper,rcvalle
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.
I used this python script to generate the mutually-exclusive sanitizer combinations:
```python
#!/usr/bin/python3
import subprocess
flags = [
["-fsanitize=address"],
["-fsanitize=leak"],
["-fsanitize=memory"],
["-fsanitize=thread"],
["-fsanitize=hwaddress"],
["-fsanitize=cfi", "-flto", "-fvisibility=hidden"],
["-fsanitize=memtag", "--target=aarch64-linux-android", "-march=armv8a+memtag"],
["-fsanitize=shadow-call-stack"],
["-fsanitize=kcfi", "-flto", "-fvisibility=hidden"],
["-fsanitize=kernel-address"],
["-fsanitize=safe-stack"],
["-fsanitize=dataflow"],
]
for i in range(len(flags)):
for j in range(i):
command = ["clang++"] + flags[i] + flags[j] + ["-o", "main.o", "-c", "main.cpp"]
completed = subprocess.run(command, stderr=subprocess.DEVNULL)
if completed.returncode != 0:
first = flags[i][0][11:].replace('-', '').upper()
second = flags[j][0][11:].replace('-', '').upper()
print(f"(SanitizerSet::{first}, SanitizerSet::{second}),")
```
This commit is contained in:
@@ -1230,7 +1230,10 @@ fn add_sanitizer_libraries(
|
|||||||
if sanitizer.contains(SanitizerSet::DATAFLOW) {
|
if sanitizer.contains(SanitizerSet::DATAFLOW) {
|
||||||
link_sanitizer_runtime(sess, flavor, linker, "dfsan");
|
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");
|
link_sanitizer_runtime(sess, flavor, linker, "lsan");
|
||||||
}
|
}
|
||||||
if sanitizer.contains(SanitizerSet::MEMORY) {
|
if sanitizer.contains(SanitizerSet::MEMORY) {
|
||||||
|
|||||||
@@ -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();
|
// Cannot mix and match mutually-exclusive sanitizers.
|
||||||
if let (Some(first), Some(second)) = (sanitizer_iter.next(), sanitizer_iter.next()) {
|
if let Some((first, second)) = sess.opts.unstable_opts.sanitizer.mutually_exclusive() {
|
||||||
sess.dcx().emit_err(errors::CannotMixAndMatchSanitizers {
|
sess.dcx().emit_err(errors::CannotMixAndMatchSanitizers {
|
||||||
first: first.to_string(),
|
first: first.to_string(),
|
||||||
second: second.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);
|
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.
|
// Canonical jump tables requires CFI.
|
||||||
if sess.is_sanitizer_cfi_canonical_jump_tables_disabled() {
|
if sess.is_sanitizer_cfi_canonical_jump_tables_disabled() {
|
||||||
if !sess.is_sanitizer_cfi_enabled() {
|
if !sess.is_sanitizer_cfi_enabled() {
|
||||||
|
|||||||
@@ -1317,6 +1317,34 @@ bitflags::bitflags! {
|
|||||||
rustc_data_structures::external_bitflags_debug! { SanitizerSet }
|
rustc_data_structures::external_bitflags_debug! { SanitizerSet }
|
||||||
|
|
||||||
impl 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
|
/// Return sanitizer's name
|
||||||
///
|
///
|
||||||
/// Returns none if the flags is a set of sanitizers numbering not exactly one.
|
/// Returns none if the flags is a set of sanitizers numbering not exactly one.
|
||||||
@@ -1337,6 +1365,13 @@ impl SanitizerSet {
|
|||||||
_ => return None,
|
_ => 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.
|
/// Formats a sanitizer set as a comma separated list of sanitizers' names.
|
||||||
|
|||||||
@@ -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`
|
||||||
|
|
||||||
error: `-Zsanitizer=cfi` is incompatible with `-Zsanitizer=kcfi`
|
error: aborting due to 2 previous errors
|
||||||
|
|
|
||||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
|
||||||
|
|
||||||
|
|||||||
@@ -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`
|
||||||
|
|
||||||
error: `-Zsanitizer=cfi` is incompatible with `-Zsanitizer=kcfi`
|
error: aborting due to 2 previous errors
|
||||||
|
|
|
||||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user