mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
Add initial support for DataFlowSanitizer
Adds initial support for DataFlowSanitizer to the Rust compiler. It currently supports `-Zsanitizer-dataflow-abilist`. Additional options for it can be passed to LLVM command line argument processor via LLVM arguments using `llvm-args` codegen option (e.g., `-Cllvm-args=-dfsan-combine-pointer-labels-on-load=false`).
This commit is contained in:
parent
eaee1e9453
commit
dee4e02102
@ -519,12 +519,22 @@ pub(crate) unsafe fn llvm_optimize(
|
|||||||
let pgo_sample_use_path = get_pgo_sample_use_path(config);
|
let pgo_sample_use_path = get_pgo_sample_use_path(config);
|
||||||
let is_lto = opt_stage == llvm::OptStage::ThinLTO || opt_stage == llvm::OptStage::FatLTO;
|
let is_lto = opt_stage == llvm::OptStage::ThinLTO || opt_stage == llvm::OptStage::FatLTO;
|
||||||
let instr_profile_output_path = get_instr_profile_output_path(config);
|
let instr_profile_output_path = get_instr_profile_output_path(config);
|
||||||
|
let sanitize_dataflow_abilist: Vec<_> = config
|
||||||
|
.sanitizer_dataflow_abilist
|
||||||
|
.iter()
|
||||||
|
.map(|file| CString::new(file.as_str()).unwrap())
|
||||||
|
.collect();
|
||||||
|
let sanitize_dataflow_abilist_ptrs: Vec<_> =
|
||||||
|
sanitize_dataflow_abilist.iter().map(|file| file.as_ptr()).collect();
|
||||||
// Sanitizer instrumentation is only inserted during the pre-link optimization stage.
|
// Sanitizer instrumentation is only inserted during the pre-link optimization stage.
|
||||||
let sanitizer_options = if !is_lto {
|
let sanitizer_options = if !is_lto {
|
||||||
Some(llvm::SanitizerOptions {
|
Some(llvm::SanitizerOptions {
|
||||||
sanitize_address: config.sanitizer.contains(SanitizerSet::ADDRESS),
|
sanitize_address: config.sanitizer.contains(SanitizerSet::ADDRESS),
|
||||||
sanitize_address_recover: config.sanitizer_recover.contains(SanitizerSet::ADDRESS),
|
sanitize_address_recover: config.sanitizer_recover.contains(SanitizerSet::ADDRESS),
|
||||||
sanitize_cfi: config.sanitizer.contains(SanitizerSet::CFI),
|
sanitize_cfi: config.sanitizer.contains(SanitizerSet::CFI),
|
||||||
|
sanitize_dataflow: config.sanitizer.contains(SanitizerSet::DATAFLOW),
|
||||||
|
sanitize_dataflow_abilist: sanitize_dataflow_abilist_ptrs.as_ptr(),
|
||||||
|
sanitize_dataflow_abilist_len: sanitize_dataflow_abilist_ptrs.len(),
|
||||||
sanitize_kcfi: config.sanitizer.contains(SanitizerSet::KCFI),
|
sanitize_kcfi: config.sanitizer.contains(SanitizerSet::KCFI),
|
||||||
sanitize_memory: config.sanitizer.contains(SanitizerSet::MEMORY),
|
sanitize_memory: config.sanitizer.contains(SanitizerSet::MEMORY),
|
||||||
sanitize_memory_recover: config.sanitizer_recover.contains(SanitizerSet::MEMORY),
|
sanitize_memory_recover: config.sanitizer_recover.contains(SanitizerSet::MEMORY),
|
||||||
|
@ -480,6 +480,9 @@ pub struct SanitizerOptions {
|
|||||||
pub sanitize_address: bool,
|
pub sanitize_address: bool,
|
||||||
pub sanitize_address_recover: bool,
|
pub sanitize_address_recover: bool,
|
||||||
pub sanitize_cfi: bool,
|
pub sanitize_cfi: bool,
|
||||||
|
pub sanitize_dataflow: bool,
|
||||||
|
pub sanitize_dataflow_abilist: *const *const c_char,
|
||||||
|
pub sanitize_dataflow_abilist_len: size_t,
|
||||||
pub sanitize_kcfi: bool,
|
pub sanitize_kcfi: bool,
|
||||||
pub sanitize_memory: bool,
|
pub sanitize_memory: bool,
|
||||||
pub sanitize_memory_recover: bool,
|
pub sanitize_memory_recover: bool,
|
||||||
|
@ -1221,6 +1221,9 @@ fn add_sanitizer_libraries(
|
|||||||
if sanitizer.contains(SanitizerSet::ADDRESS) {
|
if sanitizer.contains(SanitizerSet::ADDRESS) {
|
||||||
link_sanitizer_runtime(sess, flavor, linker, "asan");
|
link_sanitizer_runtime(sess, flavor, linker, "asan");
|
||||||
}
|
}
|
||||||
|
if sanitizer.contains(SanitizerSet::DATAFLOW) {
|
||||||
|
link_sanitizer_runtime(sess, flavor, linker, "dfsan");
|
||||||
|
}
|
||||||
if sanitizer.contains(SanitizerSet::LEAK) {
|
if sanitizer.contains(SanitizerSet::LEAK) {
|
||||||
link_sanitizer_runtime(sess, flavor, linker, "lsan");
|
link_sanitizer_runtime(sess, flavor, linker, "lsan");
|
||||||
}
|
}
|
||||||
|
@ -95,6 +95,7 @@ pub struct ModuleConfig {
|
|||||||
|
|
||||||
pub sanitizer: SanitizerSet,
|
pub sanitizer: SanitizerSet,
|
||||||
pub sanitizer_recover: SanitizerSet,
|
pub sanitizer_recover: SanitizerSet,
|
||||||
|
pub sanitizer_dataflow_abilist: Vec<String>,
|
||||||
pub sanitizer_memory_track_origins: usize,
|
pub sanitizer_memory_track_origins: usize,
|
||||||
|
|
||||||
// Flags indicating which outputs to produce.
|
// Flags indicating which outputs to produce.
|
||||||
@ -197,6 +198,10 @@ impl ModuleConfig {
|
|||||||
),
|
),
|
||||||
|
|
||||||
sanitizer: if_regular!(sess.opts.unstable_opts.sanitizer, SanitizerSet::empty()),
|
sanitizer: if_regular!(sess.opts.unstable_opts.sanitizer, SanitizerSet::empty()),
|
||||||
|
sanitizer_dataflow_abilist: if_regular!(
|
||||||
|
sess.opts.unstable_opts.sanitizer_dataflow_abilist.clone(),
|
||||||
|
Vec::new()
|
||||||
|
),
|
||||||
sanitizer_recover: if_regular!(
|
sanitizer_recover: if_regular!(
|
||||||
sess.opts.unstable_opts.sanitizer_recover,
|
sess.opts.unstable_opts.sanitizer_recover,
|
||||||
SanitizerSet::empty()
|
SanitizerSet::empty()
|
||||||
|
@ -811,6 +811,7 @@ fn test_unstable_options_tracking_hash() {
|
|||||||
tracked!(sanitizer_cfi_canonical_jump_tables, None);
|
tracked!(sanitizer_cfi_canonical_jump_tables, None);
|
||||||
tracked!(sanitizer_cfi_generalize_pointers, Some(true));
|
tracked!(sanitizer_cfi_generalize_pointers, Some(true));
|
||||||
tracked!(sanitizer_cfi_normalize_integers, Some(true));
|
tracked!(sanitizer_cfi_normalize_integers, Some(true));
|
||||||
|
tracked!(sanitizer_dataflow_abilist, vec![String::from("/rustc/abc")]);
|
||||||
tracked!(sanitizer_memory_track_origins, 2);
|
tracked!(sanitizer_memory_track_origins, 2);
|
||||||
tracked!(sanitizer_recover, SanitizerSet::ADDRESS);
|
tracked!(sanitizer_recover, SanitizerSet::ADDRESS);
|
||||||
tracked!(saturating_float_casts, Some(true));
|
tracked!(saturating_float_casts, Some(true));
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#include "llvm/Transforms/Instrumentation.h"
|
#include "llvm/Transforms/Instrumentation.h"
|
||||||
#include "llvm/Transforms/Instrumentation/AddressSanitizer.h"
|
#include "llvm/Transforms/Instrumentation/AddressSanitizer.h"
|
||||||
|
#include "llvm/Transforms/Instrumentation/DataFlowSanitizer.h"
|
||||||
#include "llvm/Support/TimeProfiler.h"
|
#include "llvm/Support/TimeProfiler.h"
|
||||||
#if LLVM_VERSION_GE(19, 0)
|
#if LLVM_VERSION_GE(19, 0)
|
||||||
#include "llvm/Support/PGOOptions.h"
|
#include "llvm/Support/PGOOptions.h"
|
||||||
@ -686,6 +687,9 @@ struct LLVMRustSanitizerOptions {
|
|||||||
bool SanitizeAddress;
|
bool SanitizeAddress;
|
||||||
bool SanitizeAddressRecover;
|
bool SanitizeAddressRecover;
|
||||||
bool SanitizeCFI;
|
bool SanitizeCFI;
|
||||||
|
bool SanitizeDataFlow;
|
||||||
|
char **SanitizeDataFlowABIList;
|
||||||
|
size_t SanitizeDataFlowABIListLen;
|
||||||
bool SanitizeKCFI;
|
bool SanitizeKCFI;
|
||||||
bool SanitizeMemory;
|
bool SanitizeMemory;
|
||||||
bool SanitizeMemoryRecover;
|
bool SanitizeMemoryRecover;
|
||||||
@ -883,6 +887,18 @@ LLVMRustOptimize(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (SanitizerOptions) {
|
if (SanitizerOptions) {
|
||||||
|
if (SanitizerOptions->SanitizeDataFlow) {
|
||||||
|
std::vector<std::string> ABIListFiles(
|
||||||
|
SanitizerOptions->SanitizeDataFlowABIList,
|
||||||
|
SanitizerOptions->SanitizeDataFlowABIList +
|
||||||
|
SanitizerOptions->SanitizeDataFlowABIListLen);
|
||||||
|
OptimizerLastEPCallbacks.push_back(
|
||||||
|
[ABIListFiles](ModulePassManager &MPM, OptimizationLevel Level) {
|
||||||
|
MPM.addPass(DataFlowSanitizerPass(ABIListFiles));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (SanitizerOptions->SanitizeMemory) {
|
if (SanitizerOptions->SanitizeMemory) {
|
||||||
MemorySanitizerOptions Options(
|
MemorySanitizerOptions Options(
|
||||||
SanitizerOptions->SanitizeMemoryTrackOrigins,
|
SanitizerOptions->SanitizeMemoryTrackOrigins,
|
||||||
|
@ -371,7 +371,8 @@ mod desc {
|
|||||||
pub const parse_list: &str = "a space-separated list of strings";
|
pub const parse_list: &str = "a space-separated list of strings";
|
||||||
pub const parse_list_with_polarity: &str =
|
pub const parse_list_with_polarity: &str =
|
||||||
"a comma-separated list of strings, with elements beginning with + or -";
|
"a comma-separated list of strings, with elements beginning with + or -";
|
||||||
pub const parse_opt_comma_list: &str = "a comma-separated list of strings";
|
pub const parse_comma_list: &str = "a comma-separated list of strings";
|
||||||
|
pub const parse_opt_comma_list: &str = parse_comma_list;
|
||||||
pub const parse_number: &str = "a number";
|
pub const parse_number: &str = "a number";
|
||||||
pub const parse_opt_number: &str = parse_number;
|
pub const parse_opt_number: &str = parse_number;
|
||||||
pub const parse_threads: &str = parse_number;
|
pub const parse_threads: &str = parse_number;
|
||||||
@ -381,7 +382,7 @@ mod desc {
|
|||||||
pub const parse_opt_panic_strategy: &str = parse_panic_strategy;
|
pub const parse_opt_panic_strategy: &str = parse_panic_strategy;
|
||||||
pub const parse_oom_strategy: &str = "either `panic` or `abort`";
|
pub const parse_oom_strategy: &str = "either `panic` or `abort`";
|
||||||
pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
|
pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
|
||||||
pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, or `thread`";
|
pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `dataflow`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, or `thread`";
|
||||||
pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
|
pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
|
||||||
pub const parse_cfguard: &str =
|
pub const parse_cfguard: &str =
|
||||||
"either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
|
"either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
|
||||||
@ -602,6 +603,18 @@ mod parse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn parse_comma_list(slot: &mut Vec<String>, v: Option<&str>) -> bool {
|
||||||
|
match v {
|
||||||
|
Some(s) => {
|
||||||
|
let mut v: Vec<_> = s.split(',').map(|s| s.to_string()).collect();
|
||||||
|
v.sort_unstable();
|
||||||
|
*slot = v;
|
||||||
|
true
|
||||||
|
}
|
||||||
|
None => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn parse_opt_comma_list(slot: &mut Option<Vec<String>>, v: Option<&str>) -> bool {
|
pub(crate) fn parse_opt_comma_list(slot: &mut Option<Vec<String>>, v: Option<&str>) -> bool {
|
||||||
match v {
|
match v {
|
||||||
Some(s) => {
|
Some(s) => {
|
||||||
@ -718,6 +731,7 @@ mod parse {
|
|||||||
*slot |= match s {
|
*slot |= match s {
|
||||||
"address" => SanitizerSet::ADDRESS,
|
"address" => SanitizerSet::ADDRESS,
|
||||||
"cfi" => SanitizerSet::CFI,
|
"cfi" => SanitizerSet::CFI,
|
||||||
|
"dataflow" => SanitizerSet::DATAFLOW,
|
||||||
"kcfi" => SanitizerSet::KCFI,
|
"kcfi" => SanitizerSet::KCFI,
|
||||||
"kernel-address" => SanitizerSet::KERNELADDRESS,
|
"kernel-address" => SanitizerSet::KERNELADDRESS,
|
||||||
"leak" => SanitizerSet::LEAK,
|
"leak" => SanitizerSet::LEAK,
|
||||||
@ -1846,6 +1860,8 @@ written to standard error output)"),
|
|||||||
"enable generalizing pointer types (default: no)"),
|
"enable generalizing pointer types (default: no)"),
|
||||||
sanitizer_cfi_normalize_integers: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
sanitizer_cfi_normalize_integers: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||||
"enable normalizing integer types (default: no)"),
|
"enable normalizing integer types (default: no)"),
|
||||||
|
sanitizer_dataflow_abilist: Vec<String> = (Vec::new(), parse_comma_list, [TRACKED],
|
||||||
|
"additional ABI list files that control how shadow parameters are passed (comma separated)"),
|
||||||
sanitizer_memory_track_origins: usize = (0, parse_sanitizer_memory_track_origins, [TRACKED],
|
sanitizer_memory_track_origins: usize = (0, parse_sanitizer_memory_track_origins, [TRACKED],
|
||||||
"enable origins tracking in MemorySanitizer"),
|
"enable origins tracking in MemorySanitizer"),
|
||||||
sanitizer_recover: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
|
sanitizer_recover: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
|
||||||
|
@ -1221,6 +1221,7 @@ bitflags::bitflags! {
|
|||||||
const KCFI = 1 << 8;
|
const KCFI = 1 << 8;
|
||||||
const KERNELADDRESS = 1 << 9;
|
const KERNELADDRESS = 1 << 9;
|
||||||
const SAFESTACK = 1 << 10;
|
const SAFESTACK = 1 << 10;
|
||||||
|
const DATAFLOW = 1 << 11;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rustc_data_structures::external_bitflags_debug! { SanitizerSet }
|
rustc_data_structures::external_bitflags_debug! { SanitizerSet }
|
||||||
@ -1233,6 +1234,7 @@ impl SanitizerSet {
|
|||||||
Some(match self {
|
Some(match self {
|
||||||
SanitizerSet::ADDRESS => "address",
|
SanitizerSet::ADDRESS => "address",
|
||||||
SanitizerSet::CFI => "cfi",
|
SanitizerSet::CFI => "cfi",
|
||||||
|
SanitizerSet::DATAFLOW => "dataflow",
|
||||||
SanitizerSet::KCFI => "kcfi",
|
SanitizerSet::KCFI => "kcfi",
|
||||||
SanitizerSet::KERNELADDRESS => "kernel-address",
|
SanitizerSet::KERNELADDRESS => "kernel-address",
|
||||||
SanitizerSet::LEAK => "leak",
|
SanitizerSet::LEAK => "leak",
|
||||||
@ -2790,6 +2792,7 @@ impl Target {
|
|||||||
base.$key_name |= match s.as_str() {
|
base.$key_name |= match s.as_str() {
|
||||||
Some("address") => SanitizerSet::ADDRESS,
|
Some("address") => SanitizerSet::ADDRESS,
|
||||||
Some("cfi") => SanitizerSet::CFI,
|
Some("cfi") => SanitizerSet::CFI,
|
||||||
|
Some("dataflow") => SanitizerSet::DATAFLOW,
|
||||||
Some("kcfi") => SanitizerSet::KCFI,
|
Some("kcfi") => SanitizerSet::KCFI,
|
||||||
Some("kernel-address") => SanitizerSet::KERNELADDRESS,
|
Some("kernel-address") => SanitizerSet::KERNELADDRESS,
|
||||||
Some("leak") => SanitizerSet::LEAK,
|
Some("leak") => SanitizerSet::LEAK,
|
||||||
|
@ -10,6 +10,7 @@ pub fn target() -> Target {
|
|||||||
base.static_position_independent_executables = true;
|
base.static_position_independent_executables = true;
|
||||||
base.supported_sanitizers = SanitizerSet::ADDRESS
|
base.supported_sanitizers = SanitizerSet::ADDRESS
|
||||||
| SanitizerSet::CFI
|
| SanitizerSet::CFI
|
||||||
|
| SanitizerSet::DATAFLOW
|
||||||
| SanitizerSet::LEAK
|
| SanitizerSet::LEAK
|
||||||
| SanitizerSet::MEMORY
|
| SanitizerSet::MEMORY
|
||||||
| SanitizerSet::SAFESTACK
|
| SanitizerSet::SAFESTACK
|
||||||
|
@ -48,7 +48,7 @@ o("codegen-tests", "rust.codegen-tests", "run the tests/codegen tests")
|
|||||||
o("ninja", "llvm.ninja", "build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)")
|
o("ninja", "llvm.ninja", "build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)")
|
||||||
o("locked-deps", "build.locked-deps", "force Cargo.lock to be up to date")
|
o("locked-deps", "build.locked-deps", "force Cargo.lock to be up to date")
|
||||||
o("vendor", "build.vendor", "enable usage of vendored Rust crates")
|
o("vendor", "build.vendor", "enable usage of vendored Rust crates")
|
||||||
o("sanitizers", "build.sanitizers", "build the sanitizer runtimes (asan, lsan, msan, tsan, hwasan)")
|
o("sanitizers", "build.sanitizers", "build the sanitizer runtimes (asan, dfsan, lsan, msan, tsan, hwasan)")
|
||||||
o("dist-src", "rust.dist-src", "when building tarballs enables building a source tarball")
|
o("dist-src", "rust.dist-src", "when building tarballs enables building a source tarball")
|
||||||
o("cargo-native-static", "build.cargo-native-static", "static native libraries in cargo")
|
o("cargo-native-static", "build.cargo-native-static", "static native libraries in cargo")
|
||||||
o("profiler", "build.profiler", "build the profiler runtime")
|
o("profiler", "build.profiler", "build the profiler runtime")
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
Change this file to make users of the `download-ci-llvm` configuration download
|
Change this file to make users of the `download-ci-llvm` configuration download
|
||||||
a new version of LLVM from CI, even if the LLVM submodule hasn’t changed.
|
a new version of LLVM from CI, even if the LLVM submodule hasn’t changed.
|
||||||
|
|
||||||
Last change is for: https://github.com/rust-lang/rust/pull/116881
|
Last change is for: https://github.com/rust-lang/rust/pull/120761
|
||||||
|
@ -1088,7 +1088,7 @@ fn supported_sanitizers(
|
|||||||
"x86_64-unknown-illumos" => common_libs("illumos", "x86_64", &["asan"]),
|
"x86_64-unknown-illumos" => common_libs("illumos", "x86_64", &["asan"]),
|
||||||
"x86_64-pc-solaris" => common_libs("solaris", "x86_64", &["asan"]),
|
"x86_64-pc-solaris" => common_libs("solaris", "x86_64", &["asan"]),
|
||||||
"x86_64-unknown-linux-gnu" => {
|
"x86_64-unknown-linux-gnu" => {
|
||||||
common_libs("linux", "x86_64", &["asan", "lsan", "msan", "safestack", "tsan"])
|
common_libs("linux", "x86_64", &["asan", "dfsan", "lsan", "msan", "safestack", "tsan"])
|
||||||
}
|
}
|
||||||
"x86_64-unknown-linux-musl" => {
|
"x86_64-unknown-linux-musl" => {
|
||||||
common_libs("linux", "x86_64", &["asan", "lsan", "msan", "tsan"])
|
common_libs("linux", "x86_64", &["asan", "lsan", "msan", "tsan"])
|
||||||
|
@ -29,6 +29,8 @@ This feature allows for use of one of following sanitizers:
|
|||||||
* Those that apart from testing, may be used in production:
|
* Those that apart from testing, may be used in production:
|
||||||
* [ControlFlowIntegrity](#controlflowintegrity) LLVM Control Flow Integrity
|
* [ControlFlowIntegrity](#controlflowintegrity) LLVM Control Flow Integrity
|
||||||
(CFI) provides forward-edge control flow protection.
|
(CFI) provides forward-edge control flow protection.
|
||||||
|
* [DataFlowSanitizer](#dataflowsanitizer) a generic dynamic data flow analysis
|
||||||
|
framework.
|
||||||
* [KernelControlFlowIntegrity](#kernelcontrolflowintegrity) LLVM Kernel
|
* [KernelControlFlowIntegrity](#kernelcontrolflowintegrity) LLVM Kernel
|
||||||
Control Flow Integrity (KCFI) provides forward-edge control flow protection
|
Control Flow Integrity (KCFI) provides forward-edge control flow protection
|
||||||
for operating systems kernels.
|
for operating systems kernels.
|
||||||
@ -39,14 +41,21 @@ This feature allows for use of one of following sanitizers:
|
|||||||
* [ShadowCallStack](#shadowcallstack) provides backward-edge control flow
|
* [ShadowCallStack](#shadowcallstack) provides backward-edge control flow
|
||||||
protection (aarch64 only).
|
protection (aarch64 only).
|
||||||
|
|
||||||
To enable a sanitizer compile with `-Zsanitizer=address`,`-Zsanitizer=cfi`,
|
To enable a sanitizer compile with `-Zsanitizer=address`, `-Zsanitizer=cfi`,
|
||||||
`-Zsanitizer=hwaddress`, `-Zsanitizer=leak`, `-Zsanitizer=memory`,
|
`-Zsanitizer=dataflow`,`-Zsanitizer=hwaddress`, `-Zsanitizer=leak`,
|
||||||
`-Zsanitizer=memtag`, `-Zsanitizer=shadow-call-stack`, or `-Zsanitizer=thread`.
|
`-Zsanitizer=memory`, `-Zsanitizer=memtag`, `-Zsanitizer=shadow-call-stack`, or
|
||||||
You might also need the `--target` and `build-std` flags. Example:
|
`-Zsanitizer=thread`. You might also need the `--target` and `build-std` flags.
|
||||||
|
|
||||||
|
Example:
|
||||||
```shell
|
```shell
|
||||||
$ RUSTFLAGS=-Zsanitizer=address cargo build -Zbuild-std --target x86_64-unknown-linux-gnu
|
$ RUSTFLAGS=-Zsanitizer=address cargo build -Zbuild-std --target x86_64-unknown-linux-gnu
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Additional options for sanitizers can be passed to LLVM command line argument
|
||||||
|
processor via LLVM arguments using `llvm-args` codegen option (e.g.,
|
||||||
|
`-Cllvm-args=-dfsan-combine-pointer-labels-on-load=false`). See the sanitizer
|
||||||
|
documentation for more information about additional options.
|
||||||
|
|
||||||
# AddressSanitizer
|
# AddressSanitizer
|
||||||
|
|
||||||
AddressSanitizer is a memory error detector. It can detect the following types
|
AddressSanitizer is a memory error detector. It can detect the following types
|
||||||
@ -639,6 +648,21 @@ LLVM KCFI is supported on the following targets:
|
|||||||
See the [Clang KernelControlFlowIntegrity documentation][clang-kcfi] for more
|
See the [Clang KernelControlFlowIntegrity documentation][clang-kcfi] for more
|
||||||
details.
|
details.
|
||||||
|
|
||||||
|
# DataFlowSanitizer
|
||||||
|
|
||||||
|
DataFlowSanitizer is a generalised dynamic data flow analysis.
|
||||||
|
|
||||||
|
Unlike other Sanitizer tools, this tool is not designed to detect a specific
|
||||||
|
class of bugs on its own. Instead, it provides a generic dynamic data flow
|
||||||
|
analysis framework to be used by clients to help detect application-specific
|
||||||
|
issues within their own code.
|
||||||
|
|
||||||
|
DataFlowSanitizer is supported on the following targets:
|
||||||
|
|
||||||
|
* `x86_64-unknown-linux-gnu`
|
||||||
|
|
||||||
|
See the [Clang DataFlowSanitizer documentation][clang-dataflow] for more details.
|
||||||
|
|
||||||
# KernelAddressSanitizer
|
# KernelAddressSanitizer
|
||||||
|
|
||||||
KernelAddressSanitizer (KASAN) is a freestanding version of AddressSanitizer
|
KernelAddressSanitizer (KASAN) is a freestanding version of AddressSanitizer
|
||||||
@ -849,6 +873,7 @@ Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PAT
|
|||||||
* [Sanitizers project page](https://github.com/google/sanitizers/wiki/)
|
* [Sanitizers project page](https://github.com/google/sanitizers/wiki/)
|
||||||
* [AddressSanitizer in Clang][clang-asan]
|
* [AddressSanitizer in Clang][clang-asan]
|
||||||
* [ControlFlowIntegrity in Clang][clang-cfi]
|
* [ControlFlowIntegrity in Clang][clang-cfi]
|
||||||
|
* [DataFlowSanitizer in Clang][clang-dataflow]
|
||||||
* [HWAddressSanitizer in Clang][clang-hwasan]
|
* [HWAddressSanitizer in Clang][clang-hwasan]
|
||||||
* [Linux Kernel's KernelAddressSanitizer documentation][linux-kasan]
|
* [Linux Kernel's KernelAddressSanitizer documentation][linux-kasan]
|
||||||
* [LeakSanitizer in Clang][clang-lsan]
|
* [LeakSanitizer in Clang][clang-lsan]
|
||||||
@ -858,6 +883,7 @@ Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PAT
|
|||||||
|
|
||||||
[clang-asan]: https://clang.llvm.org/docs/AddressSanitizer.html
|
[clang-asan]: https://clang.llvm.org/docs/AddressSanitizer.html
|
||||||
[clang-cfi]: https://clang.llvm.org/docs/ControlFlowIntegrity.html
|
[clang-cfi]: https://clang.llvm.org/docs/ControlFlowIntegrity.html
|
||||||
|
[clang-dataflow]: https://clang.llvm.org/docs/DataFlowSanitizer.html
|
||||||
[clang-hwasan]: https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html
|
[clang-hwasan]: https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html
|
||||||
[clang-kcfi]: https://clang.llvm.org/docs/ControlFlowIntegrity.html#fsanitize-kcfi
|
[clang-kcfi]: https://clang.llvm.org/docs/ControlFlowIntegrity.html#fsanitize-kcfi
|
||||||
[clang-lsan]: https://clang.llvm.org/docs/LeakSanitizer.html
|
[clang-lsan]: https://clang.llvm.org/docs/LeakSanitizer.html
|
||||||
|
@ -156,6 +156,7 @@ impl PanicStrategy {
|
|||||||
pub enum Sanitizer {
|
pub enum Sanitizer {
|
||||||
Address,
|
Address,
|
||||||
Cfi,
|
Cfi,
|
||||||
|
Dataflow,
|
||||||
Kcfi,
|
Kcfi,
|
||||||
KernelAddress,
|
KernelAddress,
|
||||||
Leak,
|
Leak,
|
||||||
|
@ -29,6 +29,11 @@ pub(super) fn handle_needs(
|
|||||||
condition: cache.sanitizer_cfi,
|
condition: cache.sanitizer_cfi,
|
||||||
ignore_reason: "ignored on targets without CFI sanitizer",
|
ignore_reason: "ignored on targets without CFI sanitizer",
|
||||||
},
|
},
|
||||||
|
Need {
|
||||||
|
name: "needs-sanitizer-dataflow",
|
||||||
|
condition: cache.sanitizer_dataflow,
|
||||||
|
ignore_reason: "ignored on targets without dataflow sanitizer",
|
||||||
|
},
|
||||||
Need {
|
Need {
|
||||||
name: "needs-sanitizer-kcfi",
|
name: "needs-sanitizer-kcfi",
|
||||||
condition: cache.sanitizer_kcfi,
|
condition: cache.sanitizer_kcfi,
|
||||||
@ -190,6 +195,7 @@ pub(super) struct CachedNeedsConditions {
|
|||||||
sanitizer_support: bool,
|
sanitizer_support: bool,
|
||||||
sanitizer_address: bool,
|
sanitizer_address: bool,
|
||||||
sanitizer_cfi: bool,
|
sanitizer_cfi: bool,
|
||||||
|
sanitizer_dataflow: bool,
|
||||||
sanitizer_kcfi: bool,
|
sanitizer_kcfi: bool,
|
||||||
sanitizer_kasan: bool,
|
sanitizer_kasan: bool,
|
||||||
sanitizer_leak: bool,
|
sanitizer_leak: bool,
|
||||||
@ -229,6 +235,7 @@ impl CachedNeedsConditions {
|
|||||||
sanitizer_support: std::env::var_os("RUSTC_SANITIZER_SUPPORT").is_some(),
|
sanitizer_support: std::env::var_os("RUSTC_SANITIZER_SUPPORT").is_some(),
|
||||||
sanitizer_address: sanitizers.contains(&Sanitizer::Address),
|
sanitizer_address: sanitizers.contains(&Sanitizer::Address),
|
||||||
sanitizer_cfi: sanitizers.contains(&Sanitizer::Cfi),
|
sanitizer_cfi: sanitizers.contains(&Sanitizer::Cfi),
|
||||||
|
sanitizer_dataflow: sanitizers.contains(&Sanitizer::Dataflow),
|
||||||
sanitizer_kcfi: sanitizers.contains(&Sanitizer::Kcfi),
|
sanitizer_kcfi: sanitizers.contains(&Sanitizer::Kcfi),
|
||||||
sanitizer_kasan: sanitizers.contains(&Sanitizer::KernelAddress),
|
sanitizer_kasan: sanitizers.contains(&Sanitizer::KernelAddress),
|
||||||
sanitizer_leak: sanitizers.contains(&Sanitizer::Leak),
|
sanitizer_leak: sanitizers.contains(&Sanitizer::Leak),
|
||||||
|
@ -43,6 +43,7 @@ const EXTENSION_EXCEPTION_PATHS: &[&str] = &[
|
|||||||
"tests/ui/macros/syntax-extension-source-utils-files/includeme.fragment", // more include
|
"tests/ui/macros/syntax-extension-source-utils-files/includeme.fragment", // more include
|
||||||
"tests/ui/proc-macro/auxiliary/included-file.txt", // more include
|
"tests/ui/proc-macro/auxiliary/included-file.txt", // more include
|
||||||
"tests/ui/invalid/foo.natvis.xml", // sample debugger visualizer
|
"tests/ui/invalid/foo.natvis.xml", // sample debugger visualizer
|
||||||
|
"tests/ui/sanitizer/dataflow-abilist.txt", // dataflow sanitizer ABI list file
|
||||||
"tests/ui/shell-argfiles/shell-argfiles.args", // passing args via a file
|
"tests/ui/shell-argfiles/shell-argfiles.args", // passing args via a file
|
||||||
"tests/ui/shell-argfiles/shell-argfiles-badquotes.args", // passing args via a file
|
"tests/ui/shell-argfiles/shell-argfiles-badquotes.args", // passing args via a file
|
||||||
"tests/ui/shell-argfiles/shell-argfiles-via-argfile-shell.args", // passing args via a file
|
"tests/ui/shell-argfiles/shell-argfiles-via-argfile-shell.args", // passing args via a file
|
||||||
|
10
tests/codegen/sanitizer/dataflow-instrument-functions.rs
Normal file
10
tests/codegen/sanitizer/dataflow-instrument-functions.rs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// Verifies that functions are instrumented.
|
||||||
|
//
|
||||||
|
//@ needs-sanitizer-dataflow
|
||||||
|
//@ compile-flags: -Copt-level=0 -Zsanitizer=dataflow
|
||||||
|
|
||||||
|
#![crate_type="lib"]
|
||||||
|
|
||||||
|
pub fn foo() {
|
||||||
|
}
|
||||||
|
// CHECK: define{{.*}}foo{{.*}}.dfsan
|
@ -100,7 +100,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
|
|||||||
LL | sanitize = "_UNEXPECTED_VALUE",
|
LL | sanitize = "_UNEXPECTED_VALUE",
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: expected values for `sanitize` are: `address`, `cfi`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, `thread`
|
= note: expected values for `sanitize` are: `address`, `cfi`, `dataflow`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, `thread`
|
||||||
= note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
|
= note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
|
||||||
|
|
||||||
warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
|
warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
|
||||||
|
505
tests/ui/sanitizer/dataflow-abilist.txt
Normal file
505
tests/ui/sanitizer/dataflow-abilist.txt
Normal file
@ -0,0 +1,505 @@
|
|||||||
|
fun:main=uninstrumented
|
||||||
|
fun:main=discard
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# DFSan interface functions
|
||||||
|
###############################################################################
|
||||||
|
fun:dfsan_union=uninstrumented
|
||||||
|
fun:dfsan_union=discard
|
||||||
|
fun:dfsan_create_label=uninstrumented
|
||||||
|
fun:dfsan_create_label=discard
|
||||||
|
fun:dfsan_set_label=uninstrumented
|
||||||
|
fun:dfsan_set_label=discard
|
||||||
|
fun:dfsan_add_label=uninstrumented
|
||||||
|
fun:dfsan_add_label=discard
|
||||||
|
fun:dfsan_get_label=uninstrumented
|
||||||
|
fun:dfsan_get_label=custom
|
||||||
|
fun:dfsan_read_label=uninstrumented
|
||||||
|
fun:dfsan_read_label=discard
|
||||||
|
fun:dfsan_get_label_count=uninstrumented
|
||||||
|
fun:dfsan_get_label_count=discard
|
||||||
|
fun:dfsan_get_label_info=uninstrumented
|
||||||
|
fun:dfsan_get_label_info=discard
|
||||||
|
fun:dfsan_has_label=uninstrumented
|
||||||
|
fun:dfsan_has_label=discard
|
||||||
|
fun:dfsan_has_label_with_desc=uninstrumented
|
||||||
|
fun:dfsan_has_label_with_desc=discard
|
||||||
|
fun:dfsan_set_write_callback=uninstrumented
|
||||||
|
fun:dfsan_set_write_callback=custom
|
||||||
|
fun:dfsan_flush=uninstrumented
|
||||||
|
fun:dfsan_flush=discard
|
||||||
|
fun:dfsan_print_origin_trace=uninstrumented
|
||||||
|
fun:dfsan_print_origin_trace=discard
|
||||||
|
fun:dfsan_print_origin_id_trace=uninstrumented
|
||||||
|
fun:dfsan_print_origin_id_trace=discard
|
||||||
|
fun:dfsan_sprint_origin_trace=uninstrumented
|
||||||
|
fun:dfsan_sprint_origin_trace=discard
|
||||||
|
fun:dfsan_sprint_origin_id_trace=uninstrumented
|
||||||
|
fun:dfsan_sprint_origin_id_trace=discard
|
||||||
|
fun:dfsan_sprint_stack_trace=uninstrumented
|
||||||
|
fun:dfsan_sprint_stack_trace=discard
|
||||||
|
fun:dfsan_get_origin=uninstrumented
|
||||||
|
fun:dfsan_get_origin=custom
|
||||||
|
fun:dfsan_read_origin_of_first_taint=uninstrumented
|
||||||
|
fun:dfsan_read_origin_of_first_taint=discard
|
||||||
|
fun:dfsan_get_init_origin=uninstrumented
|
||||||
|
fun:dfsan_get_init_origin=discard
|
||||||
|
fun:dfsan_get_track_origins=uninstrumented
|
||||||
|
fun:dfsan_get_track_origins=discard
|
||||||
|
fun:dfsan_set_conditional_callback=uninstrumented
|
||||||
|
fun:dfsan_set_conditional_callback=discard
|
||||||
|
fun:dfsan_get_labels_in_signal_conditional=uninstrumented
|
||||||
|
fun:dfsan_get_labels_in_signal_conditional=discard
|
||||||
|
fun:dfsan_set_reaches_function_callback=uninstrumented
|
||||||
|
fun:dfsan_set_reaches_function_callback=discard
|
||||||
|
fun:dfsan_get_labels_in_signal_reaches_function=uninstrumented
|
||||||
|
fun:dfsan_get_labels_in_signal_reaches_function=discard
|
||||||
|
fun:dfsan_reaches_function_callback=uninstrumented
|
||||||
|
fun:dfsan_reaches_function_callback=discard
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# glibc
|
||||||
|
###############################################################################
|
||||||
|
# Functions of memory allocators
|
||||||
|
fun:__libc_memalign=discard
|
||||||
|
fun:aligned_alloc=discard
|
||||||
|
fun:calloc=discard
|
||||||
|
fun:cfree=discard
|
||||||
|
fun:mallinfo=discard
|
||||||
|
fun:malloc=discard
|
||||||
|
fun:free=discard
|
||||||
|
fun:malloc_stats=discard
|
||||||
|
fun:malloc_usable_size=discard
|
||||||
|
fun:mallopt=discard
|
||||||
|
fun:memalign=discard
|
||||||
|
fun:posix_memalign=discard
|
||||||
|
fun:pvalloc=discard
|
||||||
|
fun:realloc=discard
|
||||||
|
fun:reallocarray=discard
|
||||||
|
fun:valloc=discard
|
||||||
|
|
||||||
|
# Functions that return a value that depends on the input, but the output might
|
||||||
|
# not be necessarily data-dependent on the input.
|
||||||
|
fun:isalpha=functional
|
||||||
|
fun:isdigit=functional
|
||||||
|
fun:isprint=functional
|
||||||
|
fun:isxdigit=functional
|
||||||
|
fun:isalnum=functional
|
||||||
|
fun:ispunct=functional
|
||||||
|
fun:isspace=functional
|
||||||
|
fun:tolower=functional
|
||||||
|
fun:_tolower=functional
|
||||||
|
fun:toupper=functional
|
||||||
|
|
||||||
|
# Functions that return a value that is data-dependent on the input.
|
||||||
|
fun:__isinf=functional
|
||||||
|
fun:__isinff=functional
|
||||||
|
fun:__signbit=functional
|
||||||
|
fun:__signbitf=functional
|
||||||
|
fun:__signbitl=functional
|
||||||
|
fun:btowc=functional
|
||||||
|
fun:exp=functional
|
||||||
|
fun:exp2=functional
|
||||||
|
fun:expf=functional
|
||||||
|
fun:expl=functional
|
||||||
|
fun:fabs=functional
|
||||||
|
fun:finite=functional
|
||||||
|
fun:finitef=functional
|
||||||
|
fun:finitel=functional
|
||||||
|
fun:floor=functional
|
||||||
|
fun:fmod=functional
|
||||||
|
fun:isinf=functional
|
||||||
|
fun:isinff=functional
|
||||||
|
fun:isinfl=functional
|
||||||
|
fun:isnan=functional
|
||||||
|
fun:isnanf=functional
|
||||||
|
fun:isnanl=functional
|
||||||
|
fun:log=functional
|
||||||
|
fun:log1p=functional
|
||||||
|
fun:log1pf=functional
|
||||||
|
fun:log1pl=functional
|
||||||
|
fun:log2=functional
|
||||||
|
fun:log2f=functional
|
||||||
|
fun:log2l=functional
|
||||||
|
fun:modf=functional
|
||||||
|
fun:nextafter=functional
|
||||||
|
fun:nextafterf=functional
|
||||||
|
fun:nextafterl=functional
|
||||||
|
fun:nexttoward=functional
|
||||||
|
fun:nexttowardf=functional
|
||||||
|
fun:nexttowardl=functional
|
||||||
|
fun:pow=functional
|
||||||
|
fun:powf=functional
|
||||||
|
fun:powl=functional
|
||||||
|
fun:round=functional
|
||||||
|
fun:sqrt=functional
|
||||||
|
fun:sqrtf=functional
|
||||||
|
fun:sqrtl=functional
|
||||||
|
fun:wctob=functional
|
||||||
|
|
||||||
|
# Functions that produce an output that does not depend on the input (shadow is
|
||||||
|
# zeroed automatically).
|
||||||
|
fun:__assert_fail=discard
|
||||||
|
fun:__cmsg_nxthdr=discard
|
||||||
|
fun:__ctype_b_loc=discard
|
||||||
|
fun:__cxa_atexit=discard
|
||||||
|
fun:__errno_location=discard
|
||||||
|
fun:__newlocale=discard
|
||||||
|
fun:__sbrk=discard
|
||||||
|
fun:__sigsetjmp=discard
|
||||||
|
fun:__uselocale=discard
|
||||||
|
fun:__wctype_l=discard
|
||||||
|
fun:access=discard
|
||||||
|
fun:alarm=discard
|
||||||
|
fun:atexit=discard
|
||||||
|
fun:bind=discard
|
||||||
|
fun:chdir=discard
|
||||||
|
fun:close=discard
|
||||||
|
fun:closedir=discard
|
||||||
|
fun:connect=discard
|
||||||
|
fun:creat=discard
|
||||||
|
fun:dladdr=discard
|
||||||
|
fun:dlclose=discard
|
||||||
|
fun:epoll_create=discard
|
||||||
|
fun:epoll_create1=discard
|
||||||
|
fun:epoll_ctl=discard
|
||||||
|
fun:fclose=discard
|
||||||
|
fun:feof=discard
|
||||||
|
fun:ferror=discard
|
||||||
|
fun:fflush=discard
|
||||||
|
fun:fileno=discard
|
||||||
|
fun:fopen=discard
|
||||||
|
fun:fprintf=discard
|
||||||
|
fun:fputc=discard
|
||||||
|
fun:fputc=discard
|
||||||
|
fun:fputs=discard
|
||||||
|
fun:fputs=discard
|
||||||
|
fun:fseek=discard
|
||||||
|
fun:ftell=discard
|
||||||
|
fun:fwrite=discard
|
||||||
|
fun:getenv=discard
|
||||||
|
fun:getuid=discard
|
||||||
|
fun:geteuid=discard
|
||||||
|
fun:getpagesize=discard
|
||||||
|
fun:getpid=discard
|
||||||
|
fun:kill=discard
|
||||||
|
fun:listen=discard
|
||||||
|
fun:lseek=discard
|
||||||
|
fun:mkdir=discard
|
||||||
|
fun:mmap=discard
|
||||||
|
fun:munmap=discard
|
||||||
|
fun:open=discard
|
||||||
|
fun:openat=discard
|
||||||
|
fun:pipe=discard
|
||||||
|
fun:posix_fadvise=discard
|
||||||
|
fun:prctl=discard
|
||||||
|
fun:printf=discard
|
||||||
|
fun:pthread_sigmask=discard
|
||||||
|
fun:putc=discard
|
||||||
|
fun:putchar=discard
|
||||||
|
fun:puts=discard
|
||||||
|
fun:rand=discard
|
||||||
|
fun:random=discard
|
||||||
|
fun:remove=discard
|
||||||
|
fun:sched_getcpu=discard
|
||||||
|
fun:sched_get_priority_max=discard
|
||||||
|
fun:sched_setaffinity=discard
|
||||||
|
fun:sched_yield=discard
|
||||||
|
fun:sem_destroy=discard
|
||||||
|
fun:sem_init=discard
|
||||||
|
fun:sem_post=discard
|
||||||
|
fun:sem_wait=discard
|
||||||
|
fun:send=discard
|
||||||
|
fun:sendmsg=discard
|
||||||
|
fun:sendto=discard
|
||||||
|
fun:setsockopt=discard
|
||||||
|
fun:shutdown=discard
|
||||||
|
fun:sleep=discard
|
||||||
|
fun:socket=discard
|
||||||
|
fun:strerror=discard
|
||||||
|
fun:strspn=discard
|
||||||
|
fun:strcspn=discard
|
||||||
|
fun:symlink=discard
|
||||||
|
fun:syscall=discard
|
||||||
|
fun:unlink=discard
|
||||||
|
fun:uselocale=discard
|
||||||
|
fun:vfprintf=discard
|
||||||
|
|
||||||
|
# Functions that produce output does not depend on the input (need to zero the
|
||||||
|
# shadow manually).
|
||||||
|
fun:_dl_get_tls_static_info=custom
|
||||||
|
fun:clock_gettime=custom
|
||||||
|
fun:dlopen=custom
|
||||||
|
fun:epoll_wait=custom
|
||||||
|
fun:fgets=custom
|
||||||
|
fun:fstat=custom
|
||||||
|
fun:getcwd=custom
|
||||||
|
fun:get_current_dir_name=custom
|
||||||
|
fun:getentropy=custom
|
||||||
|
fun:gethostname=custom
|
||||||
|
fun:getpeername=custom
|
||||||
|
fun:getrlimit=custom
|
||||||
|
fun:getrusage=custom
|
||||||
|
fun:getsockname=custom
|
||||||
|
fun:getsockopt=custom
|
||||||
|
fun:nanosleep=custom
|
||||||
|
fun:pread=custom
|
||||||
|
fun:read=custom
|
||||||
|
fun:recvmmsg=custom
|
||||||
|
fun:recvmsg=custom
|
||||||
|
fun:sigaltstack=custom
|
||||||
|
fun:socketpair=custom
|
||||||
|
fun:stat=custom
|
||||||
|
fun:time=custom
|
||||||
|
|
||||||
|
# Functions that produce an output that depend on the input (propagate the
|
||||||
|
# shadow manually).
|
||||||
|
fun:ctime_r=custom
|
||||||
|
fun:inet_pton=custom
|
||||||
|
fun:localtime_r=custom
|
||||||
|
fun:memcpy=custom
|
||||||
|
fun:memmove=custom
|
||||||
|
fun:memset=custom
|
||||||
|
fun:strcpy=custom
|
||||||
|
fun:strdup=custom
|
||||||
|
fun:strncpy=custom
|
||||||
|
fun:strtod=custom
|
||||||
|
fun:strtol=custom
|
||||||
|
fun:strtoll=custom
|
||||||
|
fun:strtoul=custom
|
||||||
|
fun:strtoull=custom
|
||||||
|
fun:strcat=custom
|
||||||
|
fun:strncat=custom
|
||||||
|
fun:__isoc23_strtod=custom
|
||||||
|
fun:__isoc23_strtol=custom
|
||||||
|
fun:__isoc23_strtoll=custom
|
||||||
|
fun:__isoc23_strtoul=custom
|
||||||
|
fun:__isoc23_strtoull=custom
|
||||||
|
|
||||||
|
# Functions that produce an output that is computed from the input, but is not
|
||||||
|
# necessarily data dependent.
|
||||||
|
fun:bcmp=custom
|
||||||
|
fun:memchr=custom
|
||||||
|
fun:memcmp=custom
|
||||||
|
fun:strcasecmp=custom
|
||||||
|
fun:strchr=custom
|
||||||
|
fun:strcmp=custom
|
||||||
|
fun:strlen=custom
|
||||||
|
fun:strnlen=custom
|
||||||
|
fun:strncasecmp=custom
|
||||||
|
fun:strncmp=custom
|
||||||
|
fun:strpbrk=custom
|
||||||
|
fun:strrchr=custom
|
||||||
|
fun:strstr=custom
|
||||||
|
fun:strsep=custom
|
||||||
|
|
||||||
|
# Functions which take action based on global state, such as running a callback
|
||||||
|
# set by a separate function.
|
||||||
|
fun:write=custom
|
||||||
|
|
||||||
|
# Functions that take a callback (wrap the callback manually).
|
||||||
|
fun:dl_iterate_phdr=custom
|
||||||
|
|
||||||
|
fun:getpwuid_r=custom
|
||||||
|
fun:poll=custom
|
||||||
|
fun:sched_getaffinity=custom
|
||||||
|
fun:select=custom
|
||||||
|
fun:sigemptyset=custom
|
||||||
|
fun:sigaction=custom
|
||||||
|
fun:signal=custom
|
||||||
|
fun:gettimeofday=custom
|
||||||
|
|
||||||
|
# sprintf-like
|
||||||
|
fun:sprintf=custom
|
||||||
|
fun:snprintf=custom
|
||||||
|
|
||||||
|
# scanf-like
|
||||||
|
fun:sscanf=custom
|
||||||
|
fun:__isoc99_sscanf=custom
|
||||||
|
fun:__isoc23_sscanf=custom
|
||||||
|
|
||||||
|
# TODO: custom
|
||||||
|
fun:asprintf=discard
|
||||||
|
fun:qsort=discard
|
||||||
|
|
||||||
|
# fork
|
||||||
|
fun:fork=custom
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# pthread
|
||||||
|
###############################################################################
|
||||||
|
fun:__pthread_register_cancel=discard
|
||||||
|
fun:__pthread_unregister_cancel=discard
|
||||||
|
fun:pthread_attr_destroy=discard
|
||||||
|
fun:pthread_attr_getaffinity_np=discard
|
||||||
|
fun:pthread_attr_getdetachstate=discard
|
||||||
|
fun:pthread_attr_getguardsize=discard
|
||||||
|
fun:pthread_attr_getinheritsched=discard
|
||||||
|
fun:pthread_attr_getschedparam=discard
|
||||||
|
fun:pthread_attr_getschedpolicy=discard
|
||||||
|
fun:pthread_attr_getscope=discard
|
||||||
|
fun:pthread_attr_getstack=discard
|
||||||
|
fun:pthread_attr_getstackaddr=disacrd
|
||||||
|
fun:pthread_attr_getstacksize=discard
|
||||||
|
fun:pthread_attr_init=discard
|
||||||
|
fun:pthread_attr_setaffinity_np=discard
|
||||||
|
fun:pthread_attr_setdetachstate=discard
|
||||||
|
fun:pthread_attr_setguardsize=discard
|
||||||
|
fun:pthread_attr_setinheritsched=discard
|
||||||
|
fun:pthread_attr_setschedparam=discard
|
||||||
|
fun:pthread_attr_setschedpolicy=discard
|
||||||
|
fun:pthread_attr_setscope=discard
|
||||||
|
fun:pthread_attr_setstack=discard
|
||||||
|
fun:pthread_attr_setstackaddr=discard
|
||||||
|
fun:pthread_attr_setstacksize=discard
|
||||||
|
fun:pthread_equal=discard
|
||||||
|
fun:pthread_getschedparam=discard
|
||||||
|
fun:pthread_getspecific=discard
|
||||||
|
fun:pthread_key_create=discard
|
||||||
|
fun:pthread_key_delete=discard
|
||||||
|
fun:pthread_mutex_destroy=discard
|
||||||
|
fun:pthread_mutex_init=discard
|
||||||
|
fun:pthread_mutex_lock=discard
|
||||||
|
fun:pthread_mutex_trylock=discard
|
||||||
|
fun:pthread_mutex_unlock=discard
|
||||||
|
fun:pthread_mutexattr_destroy=discard
|
||||||
|
fun:pthread_mutexattr_init=discard
|
||||||
|
fun:pthread_mutexattr_settype=discard
|
||||||
|
fun:pthread_rwlock_destroy=discard
|
||||||
|
fun:pthread_rwlock_init=discard
|
||||||
|
fun:pthread_rwlock_rdlock=discard
|
||||||
|
fun:pthread_rwlock_timedrdlock=discard
|
||||||
|
fun:pthread_rwlock_timedwrlock=discard
|
||||||
|
fun:pthread_rwlock_tryrdlock=discard
|
||||||
|
fun:pthread_rwlock_trywrlock=discard
|
||||||
|
fun:pthread_rwlock_wrlock=discard
|
||||||
|
fun:pthread_rwlock_unlock=discard
|
||||||
|
fun:pthread_setschedparam=discard
|
||||||
|
fun:pthread_setname_np=discard
|
||||||
|
fun:pthread_once=discard
|
||||||
|
fun:pthread_self=discard
|
||||||
|
fun:pthread_setspecific=discard
|
||||||
|
|
||||||
|
# Functions that take a callback (wrap the callback manually).
|
||||||
|
fun:pthread_create=custom
|
||||||
|
|
||||||
|
# Functions that produce output does not depend on the input (need to zero the
|
||||||
|
# shadow manually).
|
||||||
|
fun:pthread_join=custom
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# libffi/libgo
|
||||||
|
###############################################################################
|
||||||
|
# Functions that are written in asm or are called from asm.
|
||||||
|
fun:ffi_call_unix64=uninstrumented
|
||||||
|
fun:ffi_call_unix64=discard
|
||||||
|
fun:ffi_closure_unix64_inner=uninstrumented
|
||||||
|
fun:ffi_closure_unix64_inner=discard
|
||||||
|
fun:ffi_closure_unix64=uninstrumented
|
||||||
|
fun:ffi_closure_unix64=discard
|
||||||
|
fun:__go_get_closure=uninstrumented
|
||||||
|
fun:__go_get_closure=discard
|
||||||
|
fun:__go_makefunc_can_recover=uninstrumented
|
||||||
|
fun:__go_makefunc_can_recover=discard
|
||||||
|
fun:__go_makefunc_returning=uninstrumented
|
||||||
|
fun:__go_makefunc_returning=discard
|
||||||
|
fun:reflect.MakeFuncStubGo=uninstrumented
|
||||||
|
fun:reflect.MakeFuncStubGo=discard
|
||||||
|
fun:reflect.makeFuncStub=uninstrumented
|
||||||
|
fun:reflect.makeFuncStub=discard
|
||||||
|
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# lib/Fuzzer
|
||||||
|
###############################################################################
|
||||||
|
# Replaces __sanitizer_cov_trace_cmp with __dfsw___sanitizer_cov_trace_cmp
|
||||||
|
fun:__sanitizer_cov_trace_cmp1=custom
|
||||||
|
fun:__sanitizer_cov_trace_cmp1=uninstrumented
|
||||||
|
fun:__sanitizer_cov_trace_cmp2=custom
|
||||||
|
fun:__sanitizer_cov_trace_cmp2=uninstrumented
|
||||||
|
fun:__sanitizer_cov_trace_cmp4=custom
|
||||||
|
fun:__sanitizer_cov_trace_cmp4=uninstrumented
|
||||||
|
fun:__sanitizer_cov_trace_cmp8=custom
|
||||||
|
fun:__sanitizer_cov_trace_cmp8=uninstrumented
|
||||||
|
fun:__sanitizer_cov_trace_const_cmp1=custom
|
||||||
|
fun:__sanitizer_cov_trace_const_cmp1=uninstrumented
|
||||||
|
fun:__sanitizer_cov_trace_const_cmp2=custom
|
||||||
|
fun:__sanitizer_cov_trace_const_cmp2=uninstrumented
|
||||||
|
fun:__sanitizer_cov_trace_const_cmp4=custom
|
||||||
|
fun:__sanitizer_cov_trace_const_cmp4=uninstrumented
|
||||||
|
fun:__sanitizer_cov_trace_const_cmp8=custom
|
||||||
|
fun:__sanitizer_cov_trace_const_cmp8=uninstrumented
|
||||||
|
# Similar for __sanitizer_cov_trace_switch
|
||||||
|
fun:__sanitizer_cov_trace_switch=custom
|
||||||
|
fun:__sanitizer_cov_trace_switch=uninstrumented
|
||||||
|
|
||||||
|
# Ignores all other __sanitizer callbacks.
|
||||||
|
fun:__sanitizer_cov=uninstrumented
|
||||||
|
fun:__sanitizer_cov=discard
|
||||||
|
fun:__sanitizer_cov_module_init=uninstrumented
|
||||||
|
fun:__sanitizer_cov_module_init=discard
|
||||||
|
fun:__sanitizer_cov_with_check=uninstrumented
|
||||||
|
fun:__sanitizer_cov_with_check=discard
|
||||||
|
fun:__sanitizer_set_death_callback=uninstrumented
|
||||||
|
fun:__sanitizer_set_death_callback=discard
|
||||||
|
fun:__sanitizer_update_counter_bitset_and_clear_counters=uninstrumented
|
||||||
|
fun:__sanitizer_update_counter_bitset_and_clear_counters=discard
|
||||||
|
fun:__sanitizer_cov_trace_pc*=uninstrumented
|
||||||
|
fun:__sanitizer_cov_trace_pc*=discard
|
||||||
|
fun:__sanitizer_cov_pcs_init=uninstrumented
|
||||||
|
fun:__sanitizer_cov_pcs_init=discard
|
||||||
|
|
||||||
|
fun:__sanitizer_get_current_allocated_bytes=uninstrumented
|
||||||
|
fun:__sanitizer_get_current_allocated_bytes=discard
|
||||||
|
fun:__sanitizer_get_heap_size=uninstrumented
|
||||||
|
fun:__sanitizer_get_heap_size=discard
|
||||||
|
fun:__sanitizer_get_free_bytes=uninstrumented
|
||||||
|
fun:__sanitizer_get_free_bytes=discard
|
||||||
|
fun:__sanitizer_get_unmapped_bytes=uninstrumented
|
||||||
|
fun:__sanitizer_get_unmapped_bytes=discard
|
||||||
|
fun:__sanitizer_get_estimated_allocated_size=uninstrumented
|
||||||
|
fun:__sanitizer_get_estimated_allocated_size=discard
|
||||||
|
fun:__sanitizer_get_ownership=uninstrumented
|
||||||
|
fun:__sanitizer_get_ownership=discard
|
||||||
|
fun:__sanitizer_get_allocated_begin=uninstrumented
|
||||||
|
fun:__sanitizer_get_allocated_begin=discard
|
||||||
|
fun:__sanitizer_get_allocated_size=uninstrumented
|
||||||
|
fun:__sanitizer_get_allocated_size=discard
|
||||||
|
fun:__sanitizer_get_allocated_size_fast=uninstrumented
|
||||||
|
fun:__sanitizer_get_allocated_size_fast=discard
|
||||||
|
fun:__sanitizer_print_stack_trace=uninstrumented
|
||||||
|
fun:__sanitizer_print_stack_trace=discard
|
||||||
|
|
||||||
|
fun:TcmallocSlab_Internal_PushBatch_FixedShift=uninstrumented
|
||||||
|
fun:TcmallocSlab_Internal_PushBatch_FixedShift=discard
|
||||||
|
fun:TcmallocSlab_Internal_PushBatch_FixedShift_VCPU=uninstrumented
|
||||||
|
fun:TcmallocSlab_Internal_PushBatch_FixedShift_VCPU=discard
|
||||||
|
fun:TcmallocSlab_Internal_PerCpuCmpxchg64=uninstrumented
|
||||||
|
fun:TcmallocSlab_Internal_PerCpuCmpxchg64=discard
|
||||||
|
fun:TcmallocSlab_Internal_PerCpuCmpxchg64_VCPU=uninstrumented
|
||||||
|
fun:TcmallocSlab_Internal_PerCpuCmpxchg64_VCPU=discard
|
||||||
|
fun:TcmallocSlab_Internal_PopBatch_FixedShift=uninstrumented
|
||||||
|
fun:TcmallocSlab_Internal_PopBatch_FixedShift=discard
|
||||||
|
fun:TcmallocSlab_Internal_PopBatch_FixedShift_VCPU=uninstrumented
|
||||||
|
fun:TcmallocSlab_Internal_PopBatch_FixedShift_VCPU=discard
|
||||||
|
|
||||||
|
# Ignores the dfsan wrappers.
|
||||||
|
fun:__dfsw_*=uninstrumented
|
||||||
|
fun:__dfsw_*=discard
|
||||||
|
fun:__dfso_*=uninstrumented
|
||||||
|
fun:__dfso_*=discard
|
||||||
|
|
||||||
|
# Rust functions.
|
||||||
|
fun:__rdl_alloc=uninstrumented
|
||||||
|
fun:__rdl_alloc_zeroed=uninstrumented
|
||||||
|
fun:__rdl_dealloc=uninstrumented
|
||||||
|
fun:__rdl_realloc=uninstrumented
|
||||||
|
fun:__rg_oom=uninstrumented
|
||||||
|
fun:__rust_alloc=uninstrumented
|
||||||
|
fun:__rust_alloc_error_handler=uninstrumented
|
||||||
|
fun:__rust_alloc_zeroed=uninstrumented
|
||||||
|
fun:__rust_dealloc=uninstrumented
|
||||||
|
fun:__rust_realloc=uninstrumented
|
||||||
|
fun:_ZN4core*=uninstrumented
|
||||||
|
fun:_ZN3std*=uninstrumented
|
||||||
|
fun:rust_eh_personality=uninstrumented
|
60
tests/ui/sanitizer/dataflow.rs
Normal file
60
tests/ui/sanitizer/dataflow.rs
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#![allow(non_camel_case_types)]
|
||||||
|
// Verifies that labels are propagated through loads and stores.
|
||||||
|
//
|
||||||
|
//@ needs-sanitizer-support
|
||||||
|
//@ needs-sanitizer-dataflow
|
||||||
|
//@ run-pass
|
||||||
|
//@ compile-flags: -Zsanitizer=dataflow -Zsanitizer-dataflow-abilist={{src-base}}/sanitizer/dataflow-abilist.txt
|
||||||
|
|
||||||
|
use std::mem::size_of;
|
||||||
|
use std::os::raw::{c_int, c_long, c_void};
|
||||||
|
|
||||||
|
type dfsan_label = u8;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
fn dfsan_add_label(label: dfsan_label, addr: *mut c_void, size: usize);
|
||||||
|
fn dfsan_get_label(data: c_long) -> dfsan_label;
|
||||||
|
fn dfsan_has_label(label: dfsan_label, elem: dfsan_label) -> c_int;
|
||||||
|
fn dfsan_read_label(addr: *const c_void, size: usize) -> dfsan_label;
|
||||||
|
fn dfsan_set_label(label: dfsan_label, addr: *mut c_void, size: usize);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn propagate2(i: &i64) -> i64 {
|
||||||
|
i.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn propagate(i: i64) -> i64 {
|
||||||
|
let v = vec!(i, 1, 2, 3);
|
||||||
|
let j = v.iter().sum();
|
||||||
|
propagate2(&j)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
let mut i = 1i64;
|
||||||
|
let i_ptr = &mut i as *mut i64;
|
||||||
|
let i_label: dfsan_label = 1;
|
||||||
|
unsafe {
|
||||||
|
dfsan_set_label(i_label, i_ptr as *mut c_void, size_of::<i64>());
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_label = unsafe { dfsan_get_label(i) };
|
||||||
|
assert_eq!(i_label, new_label);
|
||||||
|
|
||||||
|
let read_label = unsafe { dfsan_read_label(i_ptr as *const c_void, size_of::<i64>()) };
|
||||||
|
assert_eq!(i_label, read_label);
|
||||||
|
|
||||||
|
let j_label: dfsan_label = 2;
|
||||||
|
unsafe {
|
||||||
|
dfsan_add_label(j_label, i_ptr as *mut c_void, size_of::<i64>());
|
||||||
|
}
|
||||||
|
|
||||||
|
let read_label = unsafe { dfsan_read_label(i_ptr as *const c_void, size_of::<i64>()) };
|
||||||
|
assert_eq!(unsafe { dfsan_has_label(read_label, i_label) }, 1);
|
||||||
|
assert_eq!(unsafe { dfsan_has_label(read_label, j_label) }, 1);
|
||||||
|
|
||||||
|
let mut new_i = propagate(i);
|
||||||
|
let new_i_ptr = &mut new_i as *mut i64;
|
||||||
|
let read_label = unsafe { dfsan_read_label(new_i_ptr as *const c_void, size_of::<i64>()) };
|
||||||
|
assert_eq!(unsafe { dfsan_has_label(read_label, i_label) }, 1);
|
||||||
|
assert_eq!(unsafe { dfsan_has_label(read_label, j_label) }, 1);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user