| # Sanitizers support | |
| The rustc compiler contains support for following sanitizers: | |
| * [AddressSanitizer][clang-asan] a faster memory error detector. | |
| Can detect out-of-bounds access to heap, stack, and globals, use after free, use | |
| after return, double free, invalid free, memory leaks. | |
| * [ControlFlowIntegrity][clang-cfi] LLVM Control Flow Integrity (CFI) provides | |
| forward-edge control flow protection. | |
| * [Hardware-assisted AddressSanitizer][clang-hwasan] a tool similar to | |
| AddressSanitizer but based on partial hardware assistance. | |
| * [KernelControlFlowIntegrity][clang-kcfi] LLVM Kernel Control Flow Integrity | |
| (KCFI) provides forward-edge control flow protection for operating systems kernels. | |
| * [LeakSanitizer][clang-lsan] a run-time memory leak detector. | |
| * [MemorySanitizer][clang-msan] a detector of uninitialized reads. | |
| * [ThreadSanitizer][clang-tsan] a fast data race detector. | |
| ## How to use the sanitizers? | |
| To enable a sanitizer compile with `-Z sanitizer=...` option, where value is one | |
| of `address`, `cfi`, `hwaddress`, `kcfi`, `leak`, `memory` or `thread`. | |
| For more details on how to use sanitizers, | |
| please refer to the sanitizer flag in [The Unstable Book]. | |
| [The Unstable Book]: https://doc.rust-lang.org/unstable-book | |
| ## How are sanitizers implemented in rustc? | |
| The implementation of sanitizers (except CFI) relies almost entirely on LLVM. | |
| The rustc is an integration point for LLVM compile time instrumentation passes | |
| and runtime libraries. | |
| Highlight of the most important aspects of the implementation: | |
| * The sanitizer runtime libraries are part of the [compiler-rt] project, and | |
| [will be built][sanitizer-build] on [supported targets][sanitizer-targets] | |
| when enabled in `bootstrap.toml`: | |
| ```toml | |
| build.sanitizers = true | |
| ``` | |
| The runtimes are [placed into target libdir][sanitizer-copy]. | |
| * During LLVM code generation, the functions intended for instrumentation are | |
| [marked][sanitizer-attribute] with appropriate LLVM attribute: | |
| `SanitizeAddress`, `SanitizeHWAddress`, `SanitizeMemory`, or `SanitizeThread`. | |
| By default, all functions are instrumented, but this | |
| behaviour can be changed with `#[sanitize(xyz = "on|off|<other>")]`. | |
| * The decision whether to perform instrumentation or not is possible only at a | |
| function granularity. | |
| In the cases were those decision differ between | |
| functions, it might be necessary to inhibit inlining, both at [MIR | |
| level][inline-mir] and [LLVM level][inline-llvm]. | |
| * The LLVM IR generated by rustc is instrumented by [dedicated LLVM | |
| passes][sanitizer-pass], different for each sanitizer. | |
| Instrumentation passes are invoked after optimization passes. | |
| * When producing an executable, the sanitizer specific runtime library is | |
| [linked in][sanitizer-link]. | |
| The libraries are searched for in the target libdir. | |
| First, the search is relative to the overridden system root, and subsequently, | |
| it is relative to the default system root. | |
| Fall-back to the default system root | |
| ensures that sanitizer runtimes remain available when using sysroot overrides | |
| constructed by cargo `-Z build-std` or xargo. | |
| [compiler-rt]: https://github.com/llvm/llvm-project/tree/main/compiler-rt | |
| [sanitizer-build]: https://github.com/rust-lang/rust/blob/1ead4761e9e2f056385768614c23ffa7acb6a19e/src/bootstrap/src/core/build_steps/llvm.rs#L958-L1031 | |
| [sanitizer-targets]: https://github.com/rust-lang/rust/blob/1ead4761e9e2f056385768614c23ffa7acb6a19e/src/bootstrap/src/core/build_steps/llvm.rs#L1073-L1111 | |
| [sanitizer-copy]: https://github.com/rust-lang/rust/blob/1ead4761e9e2f056385768614c23ffa7acb6a19e/src/bootstrap/src/core/build_steps/compile.rs#L637-L676 | |
| [sanitizer-attribute]: https://github.com/rust-lang/rust/blob/1.55.0/compiler/rustc_codegen_llvm/src/attributes.rs#L42-L58 | |
| [inline-mir]: https://github.com/rust-lang/rust/blob/1.55.0/compiler/rustc_mir/src/transform/inline.rs#L314-L316 | |
| [inline-llvm]: https://github.com/rust-lang/llvm-project/blob/9330ec5a4c1df5fc1fa62f993ed6a04da68cb040/llvm/include/llvm/IR/Attributes.td#L225-L241 | |
| [sanitizer-pass]: https://github.com/rust-lang/rust/blob/1.55.0/compiler/rustc_codegen_llvm/src/back/write.rs#L660-L678 | |
| [sanitizer-link]: https://github.com/rust-lang/rust/blob/1.55.0/compiler/rustc_codegen_ssa/src/back/link.rs#L1053-L1089 | |
| ## Testing sanitizers | |
| Sanitizers are validated by code generation tests in | |
| [`tests/codegen-llvm/sanitize*.rs`][test-cg] and end-to-end functional tests in | |
| [`tests/ui/sanitizer/`][test-ui] directory. | |
| Testing sanitizer functionality requires the sanitizer runtimes (built when | |
| `build.sanitizer = true` in `bootstrap.toml`) and target providing support for particular a sanitizer. | |
| When a sanitizer is unsupported on a given target, sanitizer tests will be ignored. | |
| This behaviour is controlled by compiletest `needs-sanitizer-*` directives. | |
| [test-cg]: https://github.com/rust-lang/rust/tree/HEAD/tests/codegen-llvm | |
| [test-ui]: https://github.com/rust-lang/rust/tree/HEAD/tests/ui/sanitizer | |
| ## Enabling a sanitizer on a new target | |
| To enable a sanitizer on a new target which is already supported by LLVM: | |
| 1. Include the sanitizer in the list of `supported_sanitizers` in [the target | |
| definition][target-definition]. | |
| `rustc --target .. -Zsanitizer=..` should now recognize the sanitizer as supported. | |
| 2. [Build the runtime for the target and include it in the libdir.][sanitizer-targets] | |
| 3. [Teach compiletest that your target now supports the sanitizer.][compiletest-definition] | |
| Tests marked with `needs-sanitizer-*` should now run on the target. | |
| 4. Run tests `./x test --force-rerun tests/ui/sanitize/` to verify. | |
| 5. [--enable-sanitizers in the CI configuration][ci-configuration] to build and | |
| distribute the sanitizer runtime as part of the release process. | |
| [target-definition]: https://github.com/rust-lang/rust/blob/1.55.0/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs#L10-L11 | |
| [compiletest-definition]: https://github.com/rust-lang/rust/blob/1.55.0/src/tools/compiletest/src/util.rs#L87-L116 | |
| [ci-configuration]: https://github.com/rust-lang/rust/blob/1.55.0/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile#L94 | |
| ## Additional Information | |
| * [Sanitizers project page](https://github.com/google/sanitizers/wiki/) | |
| * [AddressSanitizer in Clang][clang-asan] | |
| * [ControlFlowIntegrity in Clang][clang-cfi] | |
| * [Hardware-assisted AddressSanitizer][clang-hwasan] | |
| * [KernelControlFlowIntegrity in Clang][clang-kcfi] | |
| * [LeakSanitizer in Clang][clang-lsan] | |
| * [MemorySanitizer in Clang][clang-msan] | |
| * [ThreadSanitizer in Clang][clang-tsan] | |
| [clang-asan]: https://clang.llvm.org/docs/AddressSanitizer.html | |
| [clang-cfi]: https://clang.llvm.org/docs/ControlFlowIntegrity.html | |
| [clang-hwasan]: https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html | |
| [clang-kcfi]: https://clang.llvm.org/docs/ControlFlowIntegrity.html#fsanitize-kcfi | |
| [clang-lsan]: https://clang.llvm.org/docs/LeakSanitizer.html | |
| [clang-msan]: https://clang.llvm.org/docs/MemorySanitizer.html | |
| [clang-tsan]: https://clang.llvm.org/docs/ThreadSanitizer.html |