blob: 80baf5d73f9af3aa105e261c064b17cb32dde34b [file] [log] [blame]
<!DOCTYPE HTML>
<html lang="en" class="light sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Sanitizers support - Rust Compiler Development Guide</title>
<!-- Custom HTML head -->
<meta name="description" content="A guide to developing the Rust compiler (rustc)">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="icon" href="favicon.svg">
<link rel="shortcut icon" href="favicon.png">
<link rel="stylesheet" href="css/variables.css">
<link rel="stylesheet" href="css/general.css">
<link rel="stylesheet" href="css/chrome.css">
<link rel="stylesheet" href="css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" id="highlight-css" href="highlight.css">
<link rel="stylesheet" id="tomorrow-night-css" href="tomorrow-night.css">
<link rel="stylesheet" id="ayu-highlight-css" href="ayu-highlight.css">
<!-- Custom theme stylesheets -->
<!-- Provide site root and default themes to javascript -->
<script>
const path_to_root = "";
const default_light_theme = "light";
const default_dark_theme = "navy";
</script>
<!-- Start loading toc.js asap -->
<script src="toc.js"></script>
</head>
<body>
<div id="body-container">
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
let theme = localStorage.getItem('mdbook-theme');
let sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
let theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
const html = document.documentElement;
html.classList.remove('light')
html.classList.add(theme);
html.classList.add("js");
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
let sidebar = null;
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<!-- populated by js -->
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
<noscript>
<iframe class="sidebar-iframe-outer" src="toc.html"></iframe>
</noscript>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Rust Compiler Development Guide</h1>
<div class="right-buttons">
<a href="print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
<a href="https://github.com/rust-lang/rustc-dev-guide" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
<a href="https://github.com/rust-lang/rustc-dev-guide/edit/master/src/sanitizers.md" title="Suggest an edit" aria-label="Suggest an edit">
<i id="git-edit-button" class="fa fa-edit"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="sanitizers-support"><a class="header" href="#sanitizers-support">Sanitizers support</a></h1>
<p>The rustc compiler contains support for following sanitizers:</p>
<ul>
<li><a href="https://clang.llvm.org/docs/AddressSanitizer.html">AddressSanitizer</a> 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.</li>
<li><a href="https://clang.llvm.org/docs/ControlFlowIntegrity.html">ControlFlowIntegrity</a> LLVM Control Flow Integrity (CFI) provides
forward-edge control flow protection.</li>
<li><a href="https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html">Hardware-assisted AddressSanitizer</a> a tool similar to
AddressSanitizer but based on partial hardware assistance.</li>
<li><a href="https://clang.llvm.org/docs/ControlFlowIntegrity.html#fsanitize-kcfi">KernelControlFlowIntegrity</a> LLVM Kernel Control Flow Integrity
(KCFI) provides forward-edge control flow protection for operating systems
kernels.</li>
<li><a href="https://clang.llvm.org/docs/LeakSanitizer.html">LeakSanitizer</a> a run-time memory leak detector.</li>
<li><a href="https://clang.llvm.org/docs/MemorySanitizer.html">MemorySanitizer</a> a detector of uninitialized reads.</li>
<li><a href="https://clang.llvm.org/docs/ThreadSanitizer.html">ThreadSanitizer</a> a fast data race detector.</li>
</ul>
<h2 id="how-to-use-the-sanitizers"><a class="header" href="#how-to-use-the-sanitizers">How to use the sanitizers?</a></h2>
<p>To enable a sanitizer compile with <code>-Z sanitizer=...</code> option, where value is one
of <code>address</code>, <code>cfi</code>, <code>hwaddress</code>, <code>kcfi</code>, <code>leak</code>, <code>memory</code> or <code>thread</code>. For more
details on how to use sanitizers please refer to the sanitizer flag in <a href="https://doc.rust-lang.org/unstable-book/">the
unstable book</a>.</p>
<h2 id="how-are-sanitizers-implemented-in-rustc"><a class="header" href="#how-are-sanitizers-implemented-in-rustc">How are sanitizers implemented in rustc?</a></h2>
<p>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:</p>
<ul>
<li>
<p>The sanitizer runtime libraries are part of the <a href="https://github.com/llvm/llvm-project/tree/main/compiler-rt">compiler-rt</a> project, and
<a href="https://github.com/rust-lang/rust/blob/1ead4761e9e2f056385768614c23ffa7acb6a19e/src/bootstrap/src/core/build_steps/llvm.rs#L958-L1031">will be built</a> on <a href="https://github.com/rust-lang/rust/blob/1ead4761e9e2f056385768614c23ffa7acb6a19e/src/bootstrap/src/core/build_steps/llvm.rs#L1073-L1111">supported targets</a>
when enabled in <code>bootstrap.toml</code>:</p>
<pre><code class="language-toml">[build]
sanitizers = true
</code></pre>
<p>The runtimes are <a href="https://github.com/rust-lang/rust/blob/1ead4761e9e2f056385768614c23ffa7acb6a19e/src/bootstrap/src/core/build_steps/compile.rs#L637-L676">placed into target libdir</a>.</p>
</li>
<li>
<p>During LLVM code generation, the functions intended for instrumentation are
<a href="https://github.com/rust-lang/rust/blob/1.55.0/compiler/rustc_codegen_llvm/src/attributes.rs#L42-L58">marked</a> with appropriate LLVM attribute:
<code>SanitizeAddress</code>, <code>SanitizeHWAddress</code>, <code>SanitizeMemory</code>, or
<code>SanitizeThread</code>. By default all functions are instrumented, but this
behaviour can be changed with <code>#[no_sanitize(...)]</code>.</p>
</li>
<li>
<p>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 <a href="https://github.com/rust-lang/rust/blob/1.55.0/compiler/rustc_mir/src/transform/inline.rs#L314-L316">MIR
level</a> and <a href="https://github.com/rust-lang/llvm-project/blob/9330ec5a4c1df5fc1fa62f993ed6a04da68cb040/llvm/include/llvm/IR/Attributes.td#L225-L241">LLVM level</a>.</p>
</li>
<li>
<p>The LLVM IR generated by rustc is instrumented by <a href="https://github.com/rust-lang/rust/blob/1.55.0/compiler/rustc_codegen_llvm/src/back/write.rs#L660-L678">dedicated LLVM
passes</a>, different for each sanitizer. Instrumentation
passes are invoked after optimization passes.</p>
</li>
<li>
<p>When producing an executable, the sanitizer specific runtime library is
<a href="https://github.com/rust-lang/rust/blob/1.55.0/compiler/rustc_codegen_ssa/src/back/link.rs#L1053-L1089">linked in</a>. The libraries are searched for in the target
libdir. First relative to the overridden system root and subsequently
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 <code>-Z build-std</code> or xargo.</p>
</li>
</ul>
<h2 id="testing-sanitizers"><a class="header" href="#testing-sanitizers">Testing sanitizers</a></h2>
<p>Sanitizers are validated by code generation tests in
<a href="https://github.com/rust-lang/rust/tree/master/tests/codegen"><code>tests/codegen/sanitize*.rs</code></a> and end-to-end functional tests in
<a href="https://github.com/rust-lang/rust/tree/master/tests/ui/sanitizer"><code>tests/ui/sanitizer/</code></a> directory.</p>
<p>Testing sanitizer functionality requires the sanitizer runtimes (built when
<code>sanitizer = true</code> in <code>bootstrap.toml</code>) and target providing support for particular
sanitizer. When sanitizer is unsupported on given target, sanitizers tests will
be ignored. This behaviour is controlled by compiletest <code>needs-sanitizer-*</code>
directives.</p>
<h2 id="enabling-sanitizer-on-a-new-target"><a class="header" href="#enabling-sanitizer-on-a-new-target">Enabling sanitizer on a new target</a></h2>
<p>To enable a sanitizer on a new target which is already supported by LLVM:</p>
<ol>
<li>Include the sanitizer in the list of <code>supported_sanitizers</code> in <a href="https://github.com/rust-lang/rust/blob/1.55.0/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs#L10-L11">the target
definition</a>. <code>rustc --target .. -Zsanitizer=..</code> should now
recognize sanitizer as supported.</li>
<li><a href="https://github.com/rust-lang/rust/blob/1ead4761e9e2f056385768614c23ffa7acb6a19e/src/bootstrap/src/core/build_steps/llvm.rs#L1073-L1111">Build the runtime for the target and include it in the libdir.</a></li>
<li><a href="https://github.com/rust-lang/rust/blob/1.55.0/src/tools/compiletest/src/util.rs#L87-L116">Teach compiletest that your target now supports the sanitizer.</a>
Tests marked with <code>needs-sanitizer-*</code> should now run on the target.</li>
<li>Run tests <code>./x test --force-rerun tests/ui/sanitize/</code> to verify.</li>
<li><a href="https://github.com/rust-lang/rust/blob/1.55.0/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile#L94">--enable-sanitizers in the CI configuration</a> to build and
distribute the sanitizer runtime as part of the release process.</li>
</ol>
<h2 id="additional-information"><a class="header" href="#additional-information">Additional Information</a></h2>
<ul>
<li><a href="https://github.com/google/sanitizers/wiki/">Sanitizers project page</a></li>
<li><a href="https://clang.llvm.org/docs/AddressSanitizer.html">AddressSanitizer in Clang</a></li>
<li><a href="https://clang.llvm.org/docs/ControlFlowIntegrity.html">ControlFlowIntegrity in Clang</a></li>
<li><a href="https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html">Hardware-assisted AddressSanitizer</a></li>
<li><a href="https://clang.llvm.org/docs/ControlFlowIntegrity.html#fsanitize-kcfi">KernelControlFlowIntegrity in Clang</a></li>
<li><a href="https://clang.llvm.org/docs/LeakSanitizer.html">LeakSanitizer in Clang</a></li>
<li><a href="https://clang.llvm.org/docs/MemorySanitizer.html">MemorySanitizer in Clang</a></li>
<li><a href="https://clang.llvm.org/docs/ThreadSanitizer.html">ThreadSanitizer in Clang</a></li>
</ul>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="llvm-coverage-instrumentation.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="debugging-support-in-rustc.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="llvm-coverage-instrumentation.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="debugging-support-in-rustc.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script>
window.playground_copyable = true;
</script>
<script src="elasticlunr.min.js"></script>
<script src="mark.min.js"></script>
<script src="searcher.js"></script>
<script src="clipboard.min.js"></script>
<script src="highlight.js"></script>
<script src="book.js"></script>
<!-- Custom JS scripts -->
<script src="mermaid.min.js"></script>
<script src="mermaid-init.js"></script>
</div>
</body>
</html>