auto merge of #15165 : zookoatleastauthoritycom/rust/14148-Optimize-out-exhortations-about-being-careful-2, r=huonw
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.
This commit is contained in:
commit
9e103acaba
@ -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
|
||||
@ -305,8 +304,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
|
||||
|
||||
@ -596,7 +595,7 @@ standard library itself.
|
||||
> 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`.
|
||||
@ -689,8 +688,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:
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user