From: Zooko Wilcox-O'Hearn Date: Wed, 25 Jun 2014 01:25:10 +0000 (+0000) Subject: Optimize out exhortations about being careful. X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=e3050ffa526a1e4ada4f963ab11e1d3ea7802edb;p=rust.git Optimize out exhortations about being careful. Yes, it is important to be careful, but repeated emphasis about it is probably not helpful — it starts to sound like you came for a tutorial but found a finger-wagging lecture. Even after I removed a few of these comments, there are still several left in the text. That's probably fine! A couple of mentions of how this is dangerous and you ought to be careful may be a good reminder to the reader. After making the edits, I reflowed the paragraphs that I had touched, using emacs's "M-x fill-paragraph", with fill-column equal to 70. --- diff --git a/src/doc/guide-unsafe.md b/src/doc/guide-unsafe.md index d78e2103dac..da577b88ac2 100644 --- a/src/doc/guide-unsafe.md +++ b/src/doc/guide-unsafe.md @@ -3,13 +3,12 @@ # Introduction Rust aims to provide safe abstractions over the low-level details of -the CPU and operating system, but sometimes one is forced to drop down -and write code at that level (those abstractions have to be created -somehow). This guide aims to provide an overview of the dangers and -power one gets with Rust's unsafe subset. +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 compilers +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) @@ -18,13 +17,12 @@ checks and do a wide range of operations, such as: - [inline assembly](#inline-assembly) Note that an `unsafe` block does not relax the rules about lifetimes -of `&` and the freezing of borrowed data, it just allows the use of -additional techniques for skirting the compiler's watchful eye. 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. +of `&` and the freezing of borrowed data. -In general, one should try to minimize the amount of unsafe code in a +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. @@ -38,17 +36,17 @@ build safe interfaces. ## References -One of Rust's biggest goals as a language is ensuring memory safety, -achieved in part via [the lifetime system](guide-lifetimes.html) which -every `&` references has associated with it. This system is how the +One of Rust's biggest features is memory safety. This is achieved in +part via [the lifetime system](guide-lifetimes.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, there's no -free lunch club. For example, `&` isn't a valid replacement for C's -pointers, and so cannot be used for FFI, in general. Additionally, -both immutable (`&`) and mutable (`&mut`) references have some -aliasing and freezing guarantees, required for memory safety. +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 @@ -56,7 +54,7 @@ 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 stronger requirement: when an object has an +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. @@ -106,19 +104,19 @@ offered by the Rust language and libraries. For example, they Fortunately, they come with a redeeming feature: the weaker guarantees mean weaker restrictions. The missing restrictions make raw pointers -appropriate as a building block for (carefully!) implementing things -like smart pointers and vectors inside libraries. For example, `*` -pointers are allowed to alias, allowing them to be used to write -shared-ownership types like reference counted and garbage collected -pointers, and even thread-safe shared memory types (`Rc` and the `Arc` -types are both implemented entirely in Rust). +appropriate as a building block for implementing things like smart +pointers and vectors inside libraries. For example, `*` pointers are +allowed to alias, allowing them to be used to write shared-ownership +types like reference counted and garbage collected pointers, and even +thread-safe shared memory types (`Rc` and the `Arc` types are both +implemented entirely in Rust). There are two things that you are required to be careful about (i.e. require an `unsafe { ... }` block) with raw pointers: - dereferencing: they can have any value: so possible results include a crash, a read of uninitialised memory, a use-after-free, or - reading data as normal (and one hopes happens). + reading data as normal. - pointer arithmetic via the `offset` [intrinsic](#intrinsics) (or `.offset` method): this intrinsic uses so-called "in-bounds" arithmetic, that is, it is only defined behaviour if the result is @@ -177,9 +175,10 @@ 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: once you've thrown away the protection of the - compiler & type-system via `unsafe { ... }` you're left with just - your wits and your `assert!()`s, any bug is potentially exploitable. +- 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 @@ -298,8 +297,8 @@ asm!(assembly template Any use of `asm` is feature gated (requires `#![feature(asm)]` on the crate to allow) and of course requires an `unsafe` block. -> **Note**: the examples here are given in x86/x86-64 assembly, but all -> platforms are supported. +> **Note**: the examples here are given in x86/x86-64 assembly, but +> all platforms are supported. ## Assembly template @@ -497,7 +496,7 @@ detects that it will overflow its stack. The example above uses the > parts of the language may never be full specified and so details may > differ wildly between implementations (and even versions of `rustc` > itself). -> +> > Furthermore, this is just an overview; the best form of > documentation for specific instances of these features are their > definitions and uses in `std`. @@ -584,8 +583,7 @@ fn main(_argc: int, _argv: **u8) -> int { ``` Note the use of `abort`: the `exchange_malloc` lang item is assumed to -return a valid pointer, and so needs to do the check -internally. +return a valid pointer, and so needs to do the check internally. Other features provided by lang items include: