2015-04-20 09:41:49 -05:00
|
|
|
|
% 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
|
2015-06-09 15:49:24 -05:00
|
|
|
|
error: dereference of raw pointer requires unsafe function or block [E0133]
|
|
|
|
|
println!("raw points at {}", *raw);
|
|
|
|
|
^~~~
|
2015-04-20 09:41:49 -05:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
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
|
2015-05-31 15:35:34 -05:00
|
|
|
|
C’s `const T*` and `T*`, respectively. For more about this use, consult the
|
2015-04-20 09:41:49 -05:00
|
|
|
|
[FFI chapter][ffi].
|
|
|
|
|
|
2015-04-30 15:00:44 -05:00
|
|
|
|
[ffi]: ffi.html
|
2015-04-20 09:41:49 -05:00
|
|
|
|
|
|
|
|
|
# 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`).
|