Rollup merge of #24631 - steveklabnik:unsafe_guide, r=alexcrichton
Many unsafe features are now in the unstable section, so this section is really just about raw pointers now. That also makes sense for its place in the TOC. This addresses part of #12905.
This commit is contained in:
commit
9f87362308
@ -54,7 +54,7 @@
|
||||
* [Unsized Types](unsized-types.md)
|
||||
* [Deref coercions](deref-coercions.md)
|
||||
* [Macros](macros.md)
|
||||
* [`unsafe` Code](unsafe-code.md)
|
||||
* [Raw Pointers](raw-pointers.md)
|
||||
* [Nightly Rust](nightly-rust.md)
|
||||
* [Compiler Plugins](compiler-plugins.md)
|
||||
* [Inline Assembly](inline-assembly.md)
|
||||
|
122
src/doc/trpl/raw-pointers.md
Normal file
122
src/doc/trpl/raw-pointers.md
Normal file
@ -0,0 +1,122 @@
|
||||
% Raw Pointers
|
||||
|
||||
Rust has a number of different smart pointer types in its standard library, but
|
||||
there are two types that are extra-special. Much of Rust’s safety comes from
|
||||
compile-time checks, but raw pointers don’t have such guarantees, and are
|
||||
[unsafe][unsafe] to use.
|
||||
|
||||
`*const T` and `*mut T` are called ‘raw pointers’ in Rust. Sometimes, when
|
||||
writing certain kinds of libraries, you’ll need to get around Rust’s safety
|
||||
guarantees for some reason. In this case, you can use raw pointers to implement
|
||||
your library, while exposing a safe interface for your users. For example, `*`
|
||||
pointers are allowed to alias, allowing them to be used to write
|
||||
shared-ownership types, and even thread-safe shared memory types (the `Rc<T>`
|
||||
and `Arc<T>` types are both implemented entirely in Rust).
|
||||
|
||||
Here are some things to remember about raw pointers that are different than
|
||||
other pointer types. They:
|
||||
|
||||
- are not guaranteed to point to valid memory and are not even
|
||||
guaranteed to be non-null (unlike both `Box` and `&`);
|
||||
- do not have any automatic clean-up, unlike `Box`, and so require
|
||||
manual resource management;
|
||||
- are plain-old-data, that is, they don't move ownership, again unlike
|
||||
`Box`, hence the Rust compiler cannot protect against bugs like
|
||||
use-after-free;
|
||||
- lack any form of lifetimes, unlike `&`, and so the compiler cannot
|
||||
reason about dangling pointers; and
|
||||
- have no guarantees about aliasing or mutability other than mutation
|
||||
not being allowed directly through a `*const T`.
|
||||
|
||||
# Basics
|
||||
|
||||
Creating a raw pointer is perfectly safe:
|
||||
|
||||
```rust
|
||||
let x = 5;
|
||||
let raw = &x as *const i32;
|
||||
|
||||
let mut y = 10;
|
||||
let raw_mut = &mut y as *mut i32;
|
||||
```
|
||||
|
||||
However, dereferencing one is not. This won’t work:
|
||||
|
||||
```rust,ignore
|
||||
let x = 5;
|
||||
let raw = &x as *const i32;
|
||||
|
||||
println!("raw points at {}", *raw);
|
||||
```
|
||||
|
||||
It gives this error:
|
||||
|
||||
```text
|
||||
error: dereference of unsafe pointer requires unsafe function or block [E0133]
|
||||
println!("raw points at{}", *raw);
|
||||
^~~~
|
||||
```
|
||||
|
||||
When you dereference a raw pointer, you’re taking responsibility that it’s not
|
||||
pointing somewhere that would be incorrect. As such, you need `unsafe`:
|
||||
|
||||
```rust
|
||||
let x = 5;
|
||||
let raw = &x as *const i32;
|
||||
|
||||
let points_at = unsafe { *raw };
|
||||
|
||||
println!("raw points at {}", points_at);
|
||||
```
|
||||
|
||||
For more operations on raw pointers, see [their API documentation][rawapi].
|
||||
|
||||
[unsafe]: unsafe.html
|
||||
[rawapi]: ../std/primitive.pointer.html
|
||||
|
||||
# FFI
|
||||
|
||||
Raw pointers are useful for FFI: Rust’s `*const T` and `*mut T` are similar to
|
||||
C’s `const T*` and `T*`, respectfully. For more about this use, consult the
|
||||
[FFI chapter][ffi].
|
||||
|
||||
[ffi]: ffi.md
|
||||
|
||||
# References and raw pointers
|
||||
|
||||
At runtime, a raw pointer `*` and a reference pointing to the same piece of
|
||||
data have an identical representation. In fact, an `&T` reference will
|
||||
implicitly coerce to an `*const T` raw pointer in safe code and similarly for
|
||||
the `mut` variants (both coercions can be performed explicitly with,
|
||||
respectively, `value as *const T` and `value as *mut T`).
|
||||
|
||||
Going the opposite direction, from `*const` to a reference `&`, is not safe. A
|
||||
`&T` is always valid, and so, at a minimum, the raw pointer `*const T` has to
|
||||
point to a valid instance of type `T`. Furthermore, the resulting pointer must
|
||||
satisfy the aliasing and mutability laws of references. The compiler assumes
|
||||
these properties are true for any references, no matter how they are created,
|
||||
and so any conversion from raw pointers is asserting that they hold. The
|
||||
programmer *must* guarantee this.
|
||||
|
||||
The recommended method for the conversion is
|
||||
|
||||
```rust
|
||||
let i: u32 = 1;
|
||||
|
||||
// explicit cast
|
||||
let p_imm: *const u32 = &i as *const u32;
|
||||
let mut m: u32 = 2;
|
||||
|
||||
// implicit coercion
|
||||
let p_mut: *mut u32 = &mut m;
|
||||
|
||||
unsafe {
|
||||
let ref_imm: &u32 = &*p_imm;
|
||||
let ref_mut: &mut u32 = &mut *p_mut;
|
||||
}
|
||||
```
|
||||
|
||||
The `&*x` dereferencing style is preferred to using a `transmute`. The latter
|
||||
is far more powerful than necessary, and the more restricted operation is
|
||||
harder to use incorrectly; for example, it requires that `x` is a pointer
|
||||
(unlike `transmute`).
|
@ -1,82 +1,4 @@
|
||||
% Unsafe Code
|
||||
|
||||
# Introduction
|
||||
|
||||
Rust aims to provide safe abstractions over the low-level details of
|
||||
the CPU and operating system, but sometimes one needs to drop down and
|
||||
write code at that level. This guide aims to provide an overview of
|
||||
the dangers and power one gets with Rust's unsafe subset.
|
||||
|
||||
Rust provides an escape hatch in the form of the `unsafe { ... }`
|
||||
block which allows the programmer to dodge some of the compiler's
|
||||
checks and do a wide range of operations, such as:
|
||||
|
||||
- dereferencing [raw pointers](#raw-pointers)
|
||||
- calling a function via FFI ([covered by the FFI guide](ffi.html))
|
||||
- casting between types bitwise (`transmute`, aka "reinterpret cast")
|
||||
- [inline assembly](#inline-assembly)
|
||||
|
||||
Note that an `unsafe` block does not relax the rules about lifetimes
|
||||
of `&` and the freezing of borrowed data.
|
||||
|
||||
Any use of `unsafe` is the programmer saying "I know more than you" to
|
||||
the compiler, and, as such, the programmer should be very sure that
|
||||
they actually do know more about why that piece of code is valid. In
|
||||
general, one should try to minimize the amount of unsafe code in a
|
||||
code base; preferably by using the bare minimum `unsafe` blocks to
|
||||
build safe interfaces.
|
||||
|
||||
> **Note**: the low-level details of the Rust language are still in
|
||||
> flux, and there is no guarantee of stability or backwards
|
||||
> compatibility. In particular, there may be changes that do not cause
|
||||
> compilation errors, but do cause semantic changes (such as invoking
|
||||
> undefined behaviour). As such, extreme care is required.
|
||||
|
||||
# Pointers
|
||||
|
||||
## References
|
||||
|
||||
One of Rust's biggest features is memory safety. This is achieved in
|
||||
part via [the ownership system](ownership.html), which is how the
|
||||
compiler can guarantee that every `&` reference is always valid, and,
|
||||
for example, never pointing to freed memory.
|
||||
|
||||
These restrictions on `&` have huge advantages. However, they also
|
||||
constrain how we can use them. For example, `&` doesn't behave
|
||||
identically to C's pointers, and so cannot be used for pointers in
|
||||
foreign function interfaces (FFI). Additionally, both immutable (`&`)
|
||||
and mutable (`&mut`) references have some aliasing and freezing
|
||||
guarantees, required for memory safety.
|
||||
|
||||
In particular, if you have an `&T` reference, then the `T` must not be
|
||||
modified through that reference or any other reference. There are some
|
||||
standard library types, e.g. `Cell` and `RefCell`, that provide inner
|
||||
mutability by replacing compile time guarantees with dynamic checks at
|
||||
runtime.
|
||||
|
||||
An `&mut` reference has a different constraint: when an object has an
|
||||
`&mut T` pointing into it, then that `&mut` reference must be the only
|
||||
such usable path to that object in the whole program. That is, an
|
||||
`&mut` cannot alias with any other references.
|
||||
|
||||
Using `unsafe` code to incorrectly circumvent and violate these
|
||||
restrictions is undefined behaviour. For example, the following
|
||||
creates two aliasing `&mut` pointers, and is invalid.
|
||||
|
||||
```
|
||||
use std::mem;
|
||||
let mut x: u8 = 1;
|
||||
|
||||
let ref_1: &mut u8 = &mut x;
|
||||
let ref_2: &mut u8 = unsafe { mem::transmute(&mut *ref_1) };
|
||||
|
||||
// oops, ref_1 and ref_2 point to the same piece of data (x) and are
|
||||
// both usable
|
||||
*ref_1 = 10;
|
||||
*ref_2 = 20;
|
||||
```
|
||||
|
||||
## Raw pointers
|
||||
% Raw Pointers
|
||||
|
||||
Rust offers two additional pointer types (*raw pointers*), written as
|
||||
`*const T` and `*mut T`. They're an approximation of C's `const T*` and `T*`
|
||||
@ -160,24 +82,3 @@ The `&*x` dereferencing style is preferred to using a `transmute`.
|
||||
The latter is far more powerful than necessary, and the more
|
||||
restricted operation is harder to use incorrectly; for example, it
|
||||
requires that `x` is a pointer (unlike `transmute`).
|
||||
|
||||
|
||||
|
||||
## Making the unsafe safe(r)
|
||||
|
||||
There are various ways to expose a safe interface around some unsafe
|
||||
code:
|
||||
|
||||
- store pointers privately (i.e. not in public fields of public
|
||||
structs), so that you can see and control all reads and writes to
|
||||
the pointer in one place.
|
||||
- use `assert!()` a lot: since you can't rely on the protection of the
|
||||
compiler & type-system to ensure that your `unsafe` code is correct
|
||||
at compile-time, use `assert!()` to verify that it is doing the
|
||||
right thing at run-time.
|
||||
- implement the `Drop` for resource clean-up via a destructor, and use
|
||||
RAII (Resource Acquisition Is Initialization). This reduces the need
|
||||
for any manual memory management by users, and automatically ensures
|
||||
that clean-up is always run, even when the thread panics.
|
||||
- ensure that any data stored behind a raw pointer is destroyed at the
|
||||
appropriate time.
|
||||
|
Loading…
x
Reference in New Issue
Block a user