Files
docs-rust/ch20/ch20-01-unsafe-rust.html
2026-06-22 21:27:36 +05:30

607 lines
38 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Unsafe Rust</title>
</head>
<body>
<h2 id="unsafe-rust"><a class="header" href="#unsafe-rust">Unsafe Rust</a></h2>
<p>All the code weve discussed so far has had Rusts memory safety guarantees
enforced at compile time. However, Rust has a second language hidden inside it
that doesnt enforce these memory safety guarantees: Its called <em>unsafe Rust</em>
and works just like regular Rust but gives us extra superpowers.</p>
<p>Unsafe Rust exists because, by nature, static analysis is conservative. When
the compiler tries to determine whether or not code upholds the guarantees,
its better for it to reject some valid programs than to accept some invalid
programs. Although the code <em>might</em> be okay, if the Rust compiler doesnt have
enough information to be confident, it will reject the code. In these cases,
you can use unsafe code to tell the compiler, “Trust me, I know what Im
doing.” Be warned, however, that you use unsafe Rust at your own risk: If you
use unsafe code incorrectly, problems can occur due to memory unsafety, such as
null pointer dereferencing.</p>
<p>Another reason Rust has an unsafe alter ego is that the underlying computer
hardware is inherently unsafe. If Rust didnt let you do unsafe operations, you
couldnt do certain tasks. Rust needs to allow you to do low-level systems
programming, such as directly interacting with the operating system or even
writing your own operating system. Working with low-level systems programming
is one of the goals of the language. Lets explore what we can do with unsafe
Rust and how to do it.</p>
<!-- Old headings. Do not remove or links may break. -->
<p><a id="unsafe-superpowers"></a></p>
<h3 id="performing-unsafe-superpowers"><a class="header" href="#performing-unsafe-superpowers">Performing Unsafe Superpowers</a></h3>
<p>To switch to unsafe Rust, use the <code>unsafe</code> keyword and then start a new block
that holds the unsafe code. You can take five actions in unsafe Rust that you
cant in safe Rust, which we call <em>unsafe superpowers</em>. Those superpowers
include the ability to:</p>
<ol>
<li>Dereference a raw pointer.</li>
<li>Call an unsafe function or method.</li>
<li>Access or modify a mutable static variable.</li>
<li>Implement an unsafe trait.</li>
<li>Access fields of <code>union</code>s.</li>
</ol>
<p>Its important to understand that <code>unsafe</code> doesnt turn off the borrow checker
or disable any of Rusts other safety checks: If you use a reference in unsafe
code, it will still be checked. The <code>unsafe</code> keyword only gives you access to
these five features that are then not checked by the compiler for memory
safety. Youll still get some degree of safety inside an unsafe block.</p>
<p>In addition, <code>unsafe</code> does not mean the code inside the block is necessarily
dangerous or that it will definitely have memory safety problems: The intent is
that as the programmer, youll ensure that the code inside an <code>unsafe</code> block
will access memory in a valid way.</p>
<p>People are fallible and mistakes will happen, but by requiring these five
unsafe operations to be inside blocks annotated with <code>unsafe</code>, youll know that
any errors related to memory safety must be within an <code>unsafe</code> block. Keep
<code>unsafe</code> blocks small; youll be thankful later when you investigate memory
bugs.</p>
<p>To isolate unsafe code as much as possible, its best to enclose such code
within a safe abstraction and provide a safe API, which well discuss later in
the chapter when we examine unsafe functions and methods. Parts of the standard
library are implemented as safe abstractions over unsafe code that has been
audited. Wrapping unsafe code in a safe abstraction prevents uses of <code>unsafe</code>
from leaking out into all the places that you or your users might want to use
the functionality implemented with <code>unsafe</code> code, because using a safe
abstraction is safe.</p>
<p>Lets look at each of the five unsafe superpowers in turn. Well also look at
some abstractions that provide a safe interface to unsafe code.</p>
<h3 id="dereferencing-a-raw-pointer"><a class="header" href="#dereferencing-a-raw-pointer">Dereferencing a Raw Pointer</a></h3>
<p>In Chapter 4, in the <a href="../ch04/ch04-02-references-and-borrowing.html#dangling-references">“Dangling References”</a><!-- ignore
--> section, we mentioned that the compiler ensures that references are always
valid. Unsafe Rust has two new types called <em>raw pointers</em> that are similar to
references. As with references, raw pointers can be immutable or mutable and
are written as <code>*const T</code> and <code>*mut T</code>, respectively. The asterisk isnt the
dereference operator; its part of the type name. In the context of raw
pointers, <em>immutable</em> means that the pointer cant be directly assigned to
after being dereferenced.</p>
<p>Different from references and smart pointers, raw pointers:</p>
<ul>
<li>Are allowed to ignore the borrowing rules by having both immutable and
mutable pointers or multiple mutable pointers to the same location</li>
<li>Arent guaranteed to point to valid memory</li>
<li>Are allowed to be null</li>
<li>Dont implement any automatic cleanup</li>
</ul>
<p>By opting out of having Rust enforce these guarantees, you can give up
guaranteed safety in exchange for greater performance or the ability to
interface with another language or hardware where Rusts guarantees dont apply.</p>
<p>Listing 20-1 shows how to create an immutable and a mutable raw pointer.</p>
<figure class="listing" id="listing-20-1">
<pre class="playground"><code class="language-rust edition2024"><span class="boring">fn main() {
</span> let mut num = 5;
let r1 = &amp;raw const num;
let r2 = &amp;raw mut num;
<span class="boring">}</span></code></pre>
<figcaption><a href="#listing-20-1">Listing 20-1</a>: Creating raw pointers with the raw borrow operators</figcaption>
</figure>
<p>Notice that we dont include the <code>unsafe</code> keyword in this code. We can create
raw pointers in safe code; we just cant dereference raw pointers outside an
unsafe block, as youll see in a bit.</p>
<p>Weve created raw pointers by using the raw borrow operators: <code>&amp;raw const num</code>
creates a <code>*const i32</code> immutable raw pointer, and <code>&amp;raw mut num</code> creates a <code>*mut i32</code> mutable raw pointer. Because we created them directly from a local
variable, we know these particular raw pointers are valid, but we cant make
that assumption about just any raw pointer.</p>
<p>To demonstrate this, next well create a raw pointer whose validity we cant be
so certain of, using the keyword <code>as</code> to cast a value instead of using the raw
borrow operator. Listing 20-2 shows how to create a raw pointer to an arbitrary
location in memory. Trying to use arbitrary memory is undefined: There might be
data at that address or there might not, the compiler might optimize the code
so that there is no memory access, or the program might terminate with a
segmentation fault. Usually, there is no good reason to write code like this,
especially in cases where you can use a raw borrow operator instead, but it is
possible.</p>
<figure class="listing" id="listing-20-2">
<pre class="playground"><code class="language-rust edition2024"><span class="boring">fn main() {
</span> let address = 0x012345usize;
let r = address as *const i32;
<span class="boring">}</span></code></pre>
<figcaption><a href="#listing-20-2">Listing 20-2</a>: Creating a raw pointer to an arbitrary memory address</figcaption>
</figure>
<p>Recall that we can create raw pointers in safe code, but we cant dereference
raw pointers and read the data being pointed to. In Listing 20-3, we use the
dereference operator <code>*</code> on a raw pointer that requires an <code>unsafe</code> block.</p>
<figure class="listing" id="listing-20-3">
<pre class="playground"><code class="language-rust edition2024"><span class="boring">fn main() {
</span> let mut num = 5;
let r1 = &amp;raw const num;
let r2 = &amp;raw mut num;
unsafe {
println!("r1 is: {}", *r1);
println!("r2 is: {}", *r2);
}
<span class="boring">}</span></code></pre>
<figcaption><a href="#listing-20-3">Listing 20-3</a>: Dereferencing raw pointers within an <code>unsafe</code> block</figcaption>
</figure>
<p>Creating a pointer does no harm; its only when we try to access the value that
it points at that we might end up dealing with an invalid value.</p>
<p>Note also that in Listings 20-1 and 20-3, we created <code>*const i32</code> and <code>*mut i32</code> raw pointers that both pointed to the same memory location, where <code>num</code> is
stored. If we instead tried to create an immutable and a mutable reference to
<code>num</code>, the code would not have compiled because Rusts ownership rules dont
allow a mutable reference at the same time as any immutable references. With
raw pointers, we can create a mutable pointer and an immutable pointer to the
same location and change data through the mutable pointer, potentially creating
a data race. Be careful!</p>
<p>With all of these dangers, why would you ever use raw pointers? One major use
case is when interfacing with C code, as youll see in the next section.
Another case is when building up safe abstractions that the borrow checker
doesnt understand. Well introduce unsafe functions and then look at an
example of a safe abstraction that uses unsafe code.</p>
<h3 id="calling-an-unsafe-function-or-method"><a class="header" href="#calling-an-unsafe-function-or-method">Calling an Unsafe Function or Method</a></h3>
<p>The second type of operation you can perform in an unsafe block is calling
unsafe functions. Unsafe functions and methods look exactly like regular
functions and methods, but they have an extra <code>unsafe</code> before the rest of the
definition. The <code>unsafe</code> keyword in this context indicates the function has
requirements we need to uphold when we call this function, because Rust cant
guarantee weve met these requirements. By calling an unsafe function within an
<code>unsafe</code> block, were saying that weve read this functions documentation and
we take responsibility for upholding the functions contracts.</p>
<p>Here is an unsafe function named <code>dangerous</code> that doesnt do anything in its
body:</p>
<pre class="playground"><code class="language-rust edition2024"><span class="boring">fn main() {
</span> unsafe fn dangerous() {}
unsafe {
dangerous();
}
<span class="boring">}</span></code></pre>
<p>We must call the <code>dangerous</code> function within a separate <code>unsafe</code> block. If we
try to call <code>dangerous</code> without the <code>unsafe</code> block, well get an error:</p>
<pre><code class="language-console">$ cargo run
Compiling unsafe-example v0.1.0 (file:///projects/unsafe-example)
error[E0133]: call to unsafe function `dangerous` is unsafe and requires unsafe block
--&gt; src/main.rs:4:5
|
4 | dangerous();
| ^^^^^^^^^^^ call to unsafe function
|
= note: consult the function's documentation for information on how to avoid undefined behavior
For more information about this error, try `rustc --explain E0133`.
error: could not compile `unsafe-example` (bin "unsafe-example") due to 1 previous error
</code></pre>
<p>With the <code>unsafe</code> block, were asserting to Rust that weve read the functions
documentation, we understand how to use it properly, and weve verified that
were fulfilling the contract of the function.</p>
<p>To perform unsafe operations in the body of an <code>unsafe</code> function, you still
need to use an <code>unsafe</code> block, just as within a regular function, and the
compiler will warn you if you forget. This helps us keep <code>unsafe</code> blocks as
small as possible, as unsafe operations may not be needed across the whole
function body.</p>
<h4 id="creating-a-safe-abstraction-over-unsafe-code"><a class="header" href="#creating-a-safe-abstraction-over-unsafe-code">Creating a Safe Abstraction over Unsafe Code</a></h4>
<p>Just because a function contains unsafe code doesnt mean we need to mark the
entire function as unsafe. In fact, wrapping unsafe code in a safe function is
a common abstraction. As an example, lets study the <code>split_at_mut</code> function
from the standard library, which requires some unsafe code. Well explore how
we might implement it. This safe method is defined on mutable slices: It takes
one slice and makes it two by splitting the slice at the index given as an
argument. Listing 20-4 shows how to use <code>split_at_mut</code>.</p>
<figure class="listing" id="listing-20-4">
<pre class="playground"><code class="language-rust edition2024"><span class="boring">fn main() {
</span> let mut v = vec![1, 2, 3, 4, 5, 6];
let r = &amp;mut v[..];
let (a, b) = r.split_at_mut(3);
assert_eq!(a, &amp;mut [1, 2, 3]);
assert_eq!(b, &amp;mut [4, 5, 6]);
<span class="boring">}</span></code></pre>
<figcaption><a href="#listing-20-4">Listing 20-4</a>: Using the safe <code>split_at_mut</code> function</figcaption>
</figure>
<p>We cant implement this function using only safe Rust. An attempt might look
something like Listing 20-5, which wont compile. For simplicity, well
implement <code>split_at_mut</code> as a function rather than a method and only for slices
of <code>i32</code> values rather than for a generic type <code>T</code>.</p>
<figure class="listing" id="listing-20-5">
<pre><code class="language-rust ignore does_not_compile">fn split_at_mut(values: &amp;mut [i32], mid: usize) -&gt; (&amp;mut [i32], &amp;mut [i32]) {
let len = values.len();
assert!(mid &lt;= len);
(&amp;mut values[..mid], &amp;mut values[mid..])
}
<span class="boring">
</span><span class="boring">fn main() {
</span><span class="boring"> let mut vector = vec![1, 2, 3, 4, 5, 6];
</span><span class="boring"> let (left, right) = split_at_mut(&amp;mut vector, 3);
</span><span class="boring">}</span></code></pre>
<figcaption><a href="#listing-20-5">Listing 20-5</a>: An attempted implementation of <code>split_at_mut</code> using only safe Rust</figcaption>
</figure>
<p>This function first gets the total length of the slice. Then, it asserts that
the index given as a parameter is within the slice by checking whether its
less than or equal to the length. The assertion means that if we pass an index
that is greater than the length to split the slice at, the function will panic
before it attempts to use that index.</p>
<p>Then, we return two mutable slices in a tuple: one from the start of the
original slice to the <code>mid</code> index and another from <code>mid</code> to the end of the
slice.</p>
<p>When we try to compile the code in Listing 20-5, well get an error:</p>
<pre><code class="language-console">$ cargo run
Compiling unsafe-example v0.1.0 (file:///projects/unsafe-example)
error[E0499]: cannot borrow `*values` as mutable more than once at a time
--&gt; src/main.rs:6:31
|
1 | fn split_at_mut(values: &amp;mut [i32], mid: usize) -&gt; (&amp;mut [i32], &amp;mut [i32]) {
| - let's call the lifetime of this reference `'1`
...
6 | (&amp;mut values[..mid], &amp;mut values[mid..])
| --------------------------^^^^^^--------
| | | |
| | | second mutable borrow occurs here
| | first mutable borrow occurs here
| returning this value requires that `*values` is borrowed for `'1`
|
= help: use `.split_at_mut(position)` to obtain two mutable non-overlapping sub-slices
For more information about this error, try `rustc --explain E0499`.
error: could not compile `unsafe-example` (bin "unsafe-example") due to 1 previous error
</code></pre>
<p>Rusts borrow checker cant understand that were borrowing different parts of
the slice; it only knows that were borrowing from the same slice twice.
Borrowing different parts of a slice is fundamentally okay because the two
slices arent overlapping, but Rust isnt smart enough to know this. When we
know code is okay, but Rust doesnt, its time to reach for unsafe code.</p>
<p>Listing 20-6 shows how to use an <code>unsafe</code> block, a raw pointer, and some calls
to unsafe functions to make the implementation of <code>split_at_mut</code> work.</p>
<figure class="listing" id="listing-20-6">
<pre class="playground"><code class="language-rust edition2024">use std::slice;
fn split_at_mut(values: &amp;mut [i32], mid: usize) -&gt; (&amp;mut [i32], &amp;mut [i32]) {
let len = values.len();
let ptr = values.as_mut_ptr();
assert!(mid &lt;= len);
unsafe {
(
slice::from_raw_parts_mut(ptr, mid),
slice::from_raw_parts_mut(ptr.add(mid), len - mid),
)
}
}
<span class="boring">
</span><span class="boring">fn main() {
</span><span class="boring"> let mut vector = vec![1, 2, 3, 4, 5, 6];
</span><span class="boring"> let (left, right) = split_at_mut(&amp;mut vector, 3);
</span><span class="boring">}</span></code></pre>
<figcaption><a href="#listing-20-6">Listing 20-6</a>: Using unsafe code in the implementation of the <code>split_at_mut</code> function</figcaption>
</figure>
<p>Recall from <a href="../ch04/ch04-03-slices.html#the-slice-type">“The Slice Type”</a><!-- ignore --> section in
Chapter 4 that a slice is a pointer to some data and the length of the slice.
We use the <code>len</code> method to get the length of a slice and the <code>as_mut_ptr</code>
method to access the raw pointer of a slice. In this case, because we have a
mutable slice to <code>i32</code> values, <code>as_mut_ptr</code> returns a raw pointer with the type
<code>*mut i32</code>, which weve stored in the variable <code>ptr</code>.</p>
<p>We keep the assertion that the <code>mid</code> index is within the slice. Then, we get to
the unsafe code: The <code>slice::from_raw_parts_mut</code> function takes a raw pointer
and a length, and it creates a slice. We use this function to create a slice
that starts from <code>ptr</code> and is <code>mid</code> items long. Then, we call the <code>add</code> method
on <code>ptr</code> with <code>mid</code> as an argument to get a raw pointer that starts at <code>mid</code>,
and we create a slice using that pointer and the remaining number of items
after <code>mid</code> as the length.</p>
<p>The function <code>slice::from_raw_parts_mut</code> is unsafe because it takes a raw
pointer and must trust that this pointer is valid. The <code>add</code> method on raw
pointers is also unsafe because it must trust that the offset location is also
a valid pointer. Therefore, we had to put an <code>unsafe</code> block around our calls to
<code>slice::from_raw_parts_mut</code> and <code>add</code> so that we could call them. By looking at
the code and by adding the assertion that <code>mid</code> must be less than or equal to
<code>len</code>, we can tell that all the raw pointers used within the <code>unsafe</code> block
will be valid pointers to data within the slice. This is an acceptable and
appropriate use of <code>unsafe</code>.</p>
<p>Note that we dont need to mark the resultant <code>split_at_mut</code> function as
<code>unsafe</code>, and we can call this function from safe Rust. Weve created a safe
abstraction to the unsafe code with an implementation of the function that uses
<code>unsafe</code> code in a safe way, because it creates only valid pointers from the
data this function has access to.</p>
<p>In contrast, the use of <code>slice::from_raw_parts_mut</code> in Listing 20-7 would
likely crash when the slice is used. This code takes an arbitrary memory
location and creates a slice 10,000 items long.</p>
<figure class="listing" id="listing-20-7">
<pre class="playground"><code class="language-rust edition2024"><span class="boring">fn main() {
</span> use std::slice;
let address = 0x01234usize;
let r = address as *mut i32;
let values: &amp;[i32] = unsafe { slice::from_raw_parts_mut(r, 10000) };
<span class="boring">}</span></code></pre>
<figcaption><a href="#listing-20-7">Listing 20-7</a>: Creating a slice from an arbitrary memory location</figcaption>
</figure>
<p>We dont own the memory at this arbitrary location, and there is no guarantee
that the slice this code creates contains valid <code>i32</code> values. Attempting to use
<code>values</code> as though its a valid slice results in undefined behavior.</p>
<h4 id="using-extern-functions-to-call-external-code"><a class="header" href="#using-extern-functions-to-call-external-code">Using <code>extern</code> Functions to Call External Code</a></h4>
<p>Sometimes your Rust code might need to interact with code written in another
language. For this, Rust has the keyword <code>extern</code> that facilitates the creation
and use of a <em>Foreign Function Interface (FFI)</em>, which is a way for a
programming language to define functions and enable a different (foreign)
programming language to call those functions.</p>
<p>Listing 20-8 demonstrates how to set up an integration with the <code>abs</code> function
from the C standard library. Functions declared within <code>extern</code> blocks are
generally unsafe to call from Rust code, so <code>extern</code> blocks must also be marked
<code>unsafe</code>. The reason is that other languages dont enforce Rusts rules and
guarantees, and Rust cant check them, so responsibility falls on the
programmer to ensure safety.</p>
<figure class="listing" id="listing-20-8">
<span class="file-name">Filename: src/main.rs</span>
<pre class="playground"><code class="language-rust edition2024">unsafe extern "C" {
fn abs(input: i32) -&gt; i32;
}
fn main() {
unsafe {
println!("Absolute value of -3 according to C: {}", abs(-3));
}
}</code></pre>
<figcaption><a href="#listing-20-8">Listing 20-8</a>: Declaring and calling an <code>extern</code> function defined in another language</figcaption>
</figure>
<p>Within the <code>unsafe extern "C"</code> block, we list the names and signatures of
external functions from another language we want to call. The <code>"C"</code> part
defines which <em>application binary interface (ABI)</em> the external function uses:
The ABI defines how to call the function at the assembly level. The <code>"C"</code> ABI
is the most common and follows the C programming languages ABI. Information
about all the ABIs Rust supports is available in <a href="../reference/items/external-blocks.html#abi">the Rust Reference</a>.</p>
<p>Every item declared within an <code>unsafe extern</code> block is implicitly unsafe.
However, some FFI functions <em>are</em> safe to call. For example, the <code>abs</code> function
from Cs standard library does not have any memory safety considerations, and we
know it can be called with any <code>i32</code>. In cases like this, we can use the <code>safe</code>
keyword to say that this specific function is safe to call even though it is in
an <code>unsafe extern</code> block. Once we make that change, calling it no longer
requires an <code>unsafe</code> block, as shown in Listing 20-9.</p>
<figure class="listing" id="listing-20-9">
<span class="file-name">Filename: src/main.rs</span>
<pre class="playground"><code class="language-rust edition2024">unsafe extern "C" {
safe fn abs(input: i32) -&gt; i32;
}
fn main() {
println!("Absolute value of -3 according to C: {}", abs(-3));
}</code></pre>
<figcaption><a href="#listing-20-9">Listing 20-9</a>: Explicitly marking a function as <code>safe</code> within an <code>unsafe extern</code> block and calling it safely</figcaption>
</figure>
<p>Marking a function as <code>safe</code> does not inherently make it safe! Instead, it is
like a promise you are making to Rust that it is safe. It is still your
responsibility to make sure that promise is kept!</p>
<h4 id="calling-rust-functions-from-other-languages"><a class="header" href="#calling-rust-functions-from-other-languages">Calling Rust Functions from Other Languages</a></h4>
<p>We can also use <code>extern</code> to create an interface that allows other languages to
call Rust functions. Instead of creating a whole <code>extern</code> block, we add the
<code>extern</code> keyword and specify the ABI to use just before the <code>fn</code> keyword for
the relevant function. We also need to add an <code>#[unsafe(no_mangle)]</code> annotation
to tell the Rust compiler not to mangle the name of this function. <em>Mangling</em>
is when a compiler changes the name weve given a function to a different name
that contains more information for other parts of the compilation process to
consume but is less human readable. Every programming language compiler mangles
names slightly differently, so for a Rust function to be nameable by other
languages, we must disable the Rust compilers name mangling. This is unsafe
because there might be name collisions across libraries without the built-in
mangling, so it is our responsibility to make sure the name we choose is safe
to export without mangling.</p>
<p>In the following example, we make the <code>call_from_c</code> function accessible from C
code, after its compiled to a shared library and linked from C:</p>
<pre><code>#[unsafe(no_mangle)]
pub extern "C" fn call_from_c() {
println!("Just called a Rust function from C!");
}
</code></pre>
<p>This usage of <code>extern</code> requires <code>unsafe</code> only in the attribute, not on the
<code>extern</code> block.</p>
<h3 id="accessing-or-modifying-a-mutable-static-variable"><a class="header" href="#accessing-or-modifying-a-mutable-static-variable">Accessing or Modifying a Mutable Static Variable</a></h3>
<p>In this book, weve not yet talked about global variables, which Rust does
support but which can be problematic with Rusts ownership rules. If two
threads are accessing the same mutable global variable, it can cause a data
race.</p>
<p>In Rust, global variables are called <em>static</em> variables. Listing 20-10 shows an
example declaration and use of a static variable with a string slice as a
value.</p>
<figure class="listing" id="listing-20-10">
<span class="file-name">Filename: src/main.rs</span>
<pre class="playground"><code class="language-rust edition2024">static HELLO_WORLD: &amp;str = "Hello, world!";
fn main() {
println!("value is: {HELLO_WORLD}");
}</code></pre>
<figcaption><a href="#listing-20-10">Listing 20-10</a>: Defining and using an immutable static variable</figcaption>
</figure>
<p>Static variables are similar to constants, which we discussed in the
<a href="../ch03/ch03-01-variables-and-mutability.html#declaring-constants">“Declaring Constants”</a><!-- ignore --> section in Chapter 3. The
names of static variables are in <code>SCREAMING_SNAKE_CASE</code> by convention. Static
variables can only store references with the <code>'static</code> lifetime, which means
the Rust compiler can figure out the lifetime and we arent required to
annotate it explicitly. Accessing an immutable static variable is safe.</p>
<p>A subtle difference between constants and immutable static variables is that
values in a static variable have a fixed address in memory. Using the value
will always access the same data. Constants, on the other hand, are allowed to
duplicate their data whenever theyre used. Another difference is that static
variables can be mutable. Accessing and modifying mutable static variables is
<em>unsafe</em>. Listing 20-11 shows how to declare, access, and modify a mutable
static variable named <code>COUNTER</code>.</p>
<figure class="listing" id="listing-20-11">
<span class="file-name">Filename: src/main.rs</span>
<pre class="playground"><code class="language-rust edition2024">static mut COUNTER: u32 = 0;
/// SAFETY: Calling this from more than a single thread at a time is undefined
/// behavior, so you *must* guarantee you only call it from a single thread at
/// a time.
unsafe fn add_to_count(inc: u32) {
unsafe {
COUNTER += inc;
}
}
fn main() {
unsafe {
// SAFETY: This is only called from a single thread in `main`.
add_to_count(3);
println!("COUNTER: {}", *(&amp;raw const COUNTER));
}
}</code></pre>
<figcaption><a href="#listing-20-11">Listing 20-11</a>: Reading from or writing to a mutable static variable is unsafe.</figcaption>
</figure>
<p>As with regular variables, we specify mutability using the <code>mut</code> keyword. Any
code that reads or writes from <code>COUNTER</code> must be within an <code>unsafe</code> block. The
code in Listing 20-11 compiles and prints <code>COUNTER: 3</code> as we would expect
because its single threaded. Having multiple threads access <code>COUNTER</code> would
likely result in data races, so it is undefined behavior. Therefore, we need to
mark the entire function as <code>unsafe</code> and document the safety limitation so that
anyone calling the function knows what they are and are not allowed to do
safely.</p>
<p>Whenever we write an unsafe function, it is idiomatic to write a comment
starting with <code>SAFETY</code> and explaining what the caller needs to do to call the
function safely. Likewise, whenever we perform an unsafe operation, it is
idiomatic to write a comment starting with <code>SAFETY</code> to explain how the safety
rules are upheld.</p>
<p>Additionally, the compiler will deny by default any attempt to create
references to a mutable static variable through a compiler lint. You must
either explicitly opt out of that lints protections by adding an
<code>#[allow(static_mut_refs)]</code> annotation or access the mutable static variable
via a raw pointer created with one of the raw borrow operators. That includes
cases where the reference is created invisibly, as when it is used in the
<code>println!</code> in this code listing. Requiring references to static mutable
variables to be created via raw pointers helps make the safety requirements for
using them more obvious.</p>
<p>With mutable data that is globally accessible, its difficult to ensure that
there are no data races, which is why Rust considers mutable static variables
to be unsafe. Where possible, its preferable to use the concurrency techniques
and thread-safe smart pointers we discussed in Chapter 16 so that the compiler
checks that data access from different threads is done safely.</p>
<h3 id="implementing-an-unsafe-trait"><a class="header" href="#implementing-an-unsafe-trait">Implementing an Unsafe Trait</a></h3>
<p>We can use <code>unsafe</code> to implement an unsafe trait. A trait is unsafe when at
least one of its methods has some invariant that the compiler cant verify. We
declare that a trait is <code>unsafe</code> by adding the <code>unsafe</code> keyword before <code>trait</code>
and marking the implementation of the trait as <code>unsafe</code> too, as shown in
Listing 20-12.</p>
<figure class="listing" id="listing-20-12">
<pre class="playground"><code class="language-rust edition2024">unsafe trait Foo {
// methods go here
}
unsafe impl Foo for i32 {
// method implementations go here
}
<span class="boring">
</span><span class="boring">fn main() {}</span></code></pre>
<figcaption><a href="#listing-20-12">Listing 20-12</a>: Defining and implementing an unsafe trait</figcaption>
</figure>
<p>By using <code>unsafe impl</code>, were promising that well uphold the invariants that
the compiler cant verify.</p>
<p>As an example, recall the <code>Send</code> and <code>Sync</code> marker traits we discussed in the
<a href="../ch16/ch16-04-extensible-concurrency-sync-and-send.html">“Extensible Concurrency with <code>Send</code> and <code>Sync</code></a><!-- ignore -->
section in Chapter 16: The compiler implements these traits automatically if
our types are composed entirely of other types that implement <code>Send</code> and
<code>Sync</code>. If we implement a type that contains a type that does not implement
<code>Send</code> or <code>Sync</code>, such as raw pointers, and we want to mark that type as <code>Send</code>
or <code>Sync</code>, we must use <code>unsafe</code>. Rust cant verify that our type upholds the
guarantees that it can be safely sent across threads or accessed from multiple
threads; therefore, we need to do those checks manually and indicate as such
with <code>unsafe</code>.</p>
<h3 id="accessing-fields-of-a-union"><a class="header" href="#accessing-fields-of-a-union">Accessing Fields of a Union</a></h3>
<p>The final action that works only with <code>unsafe</code> is accessing fields of a union.
A <em>union</em> is similar to a <code>struct</code>, but only one declared field is used in a
particular instance at one time. Unions are primarily used to interface with
unions in C code. Accessing union fields is unsafe because Rust cant guarantee
the type of the data currently being stored in the union instance. You can
learn more about unions in <a href="../reference/items/unions.html">the Rust Reference</a>.</p>
<h3 id="using-miri-to-check-unsafe-code"><a class="header" href="#using-miri-to-check-unsafe-code">Using Miri to Check Unsafe Code</a></h3>
<p>When writing unsafe code, you might want to check that what you have written
actually is safe and correct. One of the best ways to do that is to use Miri,
an official Rust tool for detecting undefined behavior. Whereas the borrow
checker is a <em>static</em> tool that works at compile time, Miri is a <em>dynamic</em>
tool that works at runtime. It checks your code by running your program, or
its test suite, and detecting when you violate the rules it understands about
how Rust should work.</p>
<p>Using Miri requires a nightly build of Rust (which we talk about more in
<a href="../appendix/appendix-07-nightly-rust.html">Appendix G: How Rust is Made and “Nightly Rust”</a><!-- ignore -->). You
can install both a nightly version of Rust and the Miri tool by typing <code>rustup +nightly component add miri</code>. This does not change what version of Rust your
project uses; it only adds the tool to your system so you can use it when you
want to. You can run Miri on a project by typing <code>cargo +nightly miri run</code> or
<code>cargo +nightly miri test</code>.</p>
<p>For an example of how helpful this can be, consider what happens when we run it
against Listing 20-7.</p>
<pre><code class="language-console">$ cargo +nightly miri run
Compiling unsafe-example v0.1.0 (file:///projects/unsafe-example)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.01s
Running `file:///home/.rustup/toolchains/nightly/bin/cargo-miri runner target/miri/debug/unsafe-example`
warning: integer-to-pointer cast
--&gt; src/main.rs:5:13
|
5 | let r = address as *mut i32;
| ^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast
|
= help: this program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`, which means that Miri might miss pointer bugs in this program
= help: see https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation
= help: to ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead
= help: you can then set `MIRIFLAGS=-Zmiri-strict-provenance` to ensure you are not relying on `with_exposed_provenance` semantics
= help: alternatively, `MIRIFLAGS=-Zmiri-permissive-provenance` disables this warning
= note: BACKTRACE:
= note: inside `main` at src/main.rs:5:13: 5:32
error: Undefined Behavior: pointer not dereferenceable: pointer must be dereferenceable for 40000 bytes, but got 0x1234[noalloc] which is a dangling pointer (it has no provenance)
--&gt; src/main.rs:7:35
|
7 | let values: &amp;[i32] = unsafe { slice::from_raw_parts_mut(r, 10000) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: BACKTRACE:
= note: inside `main` at src/main.rs:7:35: 7:70
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to 1 previous error; 1 warning emitted
</code></pre>
<p>Miri correctly warns us that were casting an integer to a pointer, which might
be a problem, but Miri cant determine whether a problem exists because it
doesnt know how the pointer originated. Then, Miri returns an error where
Listing 20-7 has undefined behavior because we have a dangling pointer. Thanks
to Miri, we now know there is a risk of undefined behavior, and we can think
about how to make the code safe. In some cases, Miri can even make
recommendations about how to fix errors.</p>
<p>Miri doesnt catch everything you might get wrong when writing unsafe code.
Miri is a dynamic analysis tool, so it only catches problems with code that
actually gets run. That means you will need to use it in conjunction with good
testing techniques to increase your confidence about the unsafe code you have
written. Miri also does not cover every possible way your code can be unsound.</p>
<p>Put another way: If Miri <em>does</em> catch a problem, you know theres a bug, but
just because Miri <em>doesnt</em> catch a bug doesnt mean there isnt a problem. It
can catch a lot, though. Try running it on the other examples of unsafe code in
this chapter and see what it says!</p>
<p>You can learn more about Miri at <a href="https://github.com/rust-lang/miri">its GitHub repository</a>.</p>
<!-- Old headings. Do not remove or links may break. -->
<p><a id="when-to-use-unsafe-code"></a></p>
<h3 id="using-unsafe-code-correctly"><a class="header" href="#using-unsafe-code-correctly">Using Unsafe Code Correctly</a></h3>
<p>Using <code>unsafe</code> to use one of the five superpowers just discussed isnt wrong or
even frowned upon, but it is trickier to get <code>unsafe</code> code correct because the
compiler cant help uphold memory safety. When you have a reason to use
<code>unsafe</code> code, you can do so, and having the explicit <code>unsafe</code> annotation makes
it easier to track down the source of problems when they occur. Whenever you
write unsafe code, you can use Miri to help you be more confident that the code
you have written upholds Rusts rules.</p>
<p>For a much deeper exploration of how to work effectively with unsafe Rust, read
Rusts official guide for <code>unsafe</code>, <a href="https://doc.rust-lang.org/nomicon/">The Rustonomicon</a>.</p>
</body>
</html>