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.
This commit is contained in:
parent
0550b79f73
commit
e3050ffa52
1 changed files with 33 additions and 35 deletions
|
@ -3,13 +3,12 @@
|
||||||
# Introduction
|
# Introduction
|
||||||
|
|
||||||
Rust aims to provide safe abstractions over the low-level details of
|
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
|
the CPU and operating system, but sometimes one needs to drop down and
|
||||||
and write code at that level (those abstractions have to be created
|
write code at that level. This guide aims to provide an overview of
|
||||||
somehow). This guide aims to provide an overview of the dangers and
|
the dangers and power one gets with Rust's unsafe subset.
|
||||||
power one gets with Rust's unsafe subset.
|
|
||||||
|
|
||||||
Rust provides an escape hatch in the form of the `unsafe { ... }`
|
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:
|
checks and do a wide range of operations, such as:
|
||||||
|
|
||||||
- dereferencing [raw pointers](#raw-pointers)
|
- dereferencing [raw pointers](#raw-pointers)
|
||||||
|
@ -18,13 +17,12 @@ checks and do a wide range of operations, such as:
|
||||||
- [inline assembly](#inline-assembly)
|
- [inline assembly](#inline-assembly)
|
||||||
|
|
||||||
Note that an `unsafe` block does not relax the rules about lifetimes
|
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
|
of `&` and the freezing of borrowed data.
|
||||||
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.
|
|
||||||
|
|
||||||
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
|
code base; preferably by using the bare minimum `unsafe` blocks to
|
||||||
build safe interfaces.
|
build safe interfaces.
|
||||||
|
|
||||||
|
@ -38,17 +36,17 @@ build safe interfaces.
|
||||||
|
|
||||||
## References
|
## References
|
||||||
|
|
||||||
One of Rust's biggest goals as a language is ensuring memory safety,
|
One of Rust's biggest features is memory safety. This is achieved in
|
||||||
achieved in part via [the lifetime system](guide-lifetimes.html) which
|
part via [the lifetime system](guide-lifetimes.html), which is how the
|
||||||
every `&` references has associated with it. This system is how the
|
|
||||||
compiler can guarantee that every `&` reference is always valid, and,
|
compiler can guarantee that every `&` reference is always valid, and,
|
||||||
for example, never pointing to freed memory.
|
for example, never pointing to freed memory.
|
||||||
|
|
||||||
These restrictions on `&` have huge advantages. However, there's no
|
These restrictions on `&` have huge advantages. However, they also
|
||||||
free lunch club. For example, `&` isn't a valid replacement for C's
|
constrain how we can use them. For example, `&` doesn't behave
|
||||||
pointers, and so cannot be used for FFI, in general. Additionally,
|
identically to C's pointers, and so cannot be used for pointers in
|
||||||
both immutable (`&`) and mutable (`&mut`) references have some
|
foreign function interfaces (FFI). Additionally, both immutable (`&`)
|
||||||
aliasing and freezing guarantees, required for memory safety.
|
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
|
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
|
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
|
mutability by replacing compile time guarantees with dynamic checks at
|
||||||
runtime.
|
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
|
`&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
|
such usable path to that object in the whole program. That is, an
|
||||||
`&mut` cannot alias with any other references.
|
`&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
|
Fortunately, they come with a redeeming feature: the weaker guarantees
|
||||||
mean weaker restrictions. The missing restrictions make raw pointers
|
mean weaker restrictions. The missing restrictions make raw pointers
|
||||||
appropriate as a building block for (carefully!) implementing things
|
appropriate as a building block for implementing things like smart
|
||||||
like smart pointers and vectors inside libraries. For example, `*`
|
pointers and vectors inside libraries. For example, `*` pointers are
|
||||||
pointers are allowed to alias, allowing them to be used to write
|
allowed to alias, allowing them to be used to write shared-ownership
|
||||||
shared-ownership types like reference counted and garbage collected
|
types like reference counted and garbage collected pointers, and even
|
||||||
pointers, and even thread-safe shared memory types (`Rc` and the `Arc`
|
thread-safe shared memory types (`Rc` and the `Arc` types are both
|
||||||
types are both implemented entirely in Rust).
|
implemented entirely in Rust).
|
||||||
|
|
||||||
There are two things that you are required to be careful about
|
There are two things that you are required to be careful about
|
||||||
(i.e. require an `unsafe { ... }` block) with raw pointers:
|
(i.e. require an `unsafe { ... }` block) with raw pointers:
|
||||||
|
|
||||||
- dereferencing: they can have any value: so possible results include
|
- dereferencing: they can have any value: so possible results include
|
||||||
a crash, a read of uninitialised memory, a use-after-free, or
|
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
|
- pointer arithmetic via the `offset` [intrinsic](#intrinsics) (or
|
||||||
`.offset` method): this intrinsic uses so-called "in-bounds"
|
`.offset` method): this intrinsic uses so-called "in-bounds"
|
||||||
arithmetic, that is, it is only defined behaviour if the result is
|
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
|
- store pointers privately (i.e. not in public fields of public
|
||||||
structs), so that you can see and control all reads and writes to
|
structs), so that you can see and control all reads and writes to
|
||||||
the pointer in one place.
|
the pointer in one place.
|
||||||
- use `assert!()` a lot: once you've thrown away the protection of the
|
- use `assert!()` a lot: since you can't rely on the protection of the
|
||||||
compiler & type-system via `unsafe { ... }` you're left with just
|
compiler & type-system to ensure that your `unsafe` code is correct
|
||||||
your wits and your `assert!()`s, any bug is potentially exploitable.
|
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
|
- implement the `Drop` for resource clean-up via a destructor, and use
|
||||||
RAII (Resource Acquisition Is Initialization). This reduces the need
|
RAII (Resource Acquisition Is Initialization). This reduces the need
|
||||||
for any manual memory management by users, and automatically ensures
|
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
|
Any use of `asm` is feature gated (requires `#![feature(asm)]` on the
|
||||||
crate to allow) and of course requires an `unsafe` block.
|
crate to allow) and of course requires an `unsafe` block.
|
||||||
|
|
||||||
> **Note**: the examples here are given in x86/x86-64 assembly, but all
|
> **Note**: the examples here are given in x86/x86-64 assembly, but
|
||||||
> platforms are supported.
|
> all platforms are supported.
|
||||||
|
|
||||||
## Assembly template
|
## 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
|
> parts of the language may never be full specified and so details may
|
||||||
> differ wildly between implementations (and even versions of `rustc`
|
> differ wildly between implementations (and even versions of `rustc`
|
||||||
> itself).
|
> itself).
|
||||||
>
|
>
|
||||||
> Furthermore, this is just an overview; the best form of
|
> Furthermore, this is just an overview; the best form of
|
||||||
> documentation for specific instances of these features are their
|
> documentation for specific instances of these features are their
|
||||||
> definitions and uses in `std`.
|
> 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
|
Note the use of `abort`: the `exchange_malloc` lang item is assumed to
|
||||||
return a valid pointer, and so needs to do the check
|
return a valid pointer, and so needs to do the check internally.
|
||||||
internally.
|
|
||||||
|
|
||||||
Other features provided by lang items include:
|
Other features provided by lang items include:
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue