diff --git a/src/doc/trpl/SUMMARY.md b/src/doc/trpl/SUMMARY.md index f2d1666048d89..04edb6830848f 100644 --- a/src/doc/trpl/SUMMARY.md +++ b/src/doc/trpl/SUMMARY.md @@ -54,7 +54,7 @@ * [Associated Types](associated-types.md) * [Unsized Types](unsized-types.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) diff --git a/src/doc/trpl/raw-pointers.md b/src/doc/trpl/raw-pointers.md new file mode 100644 index 0000000000000..ab6ff18501ed5 --- /dev/null +++ b/src/doc/trpl/raw-pointers.md @@ -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` +and `Arc` 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`). diff --git a/src/doc/trpl/unsafe-code.md b/src/doc/trpl/unsafe-code.md index b641f2b104a72..dd166034b541e 100644 --- a/src/doc/trpl/unsafe-code.md +++ b/src/doc/trpl/unsafe-code.md @@ -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.