Skip to content

Commit 04ab11d

Browse files
authored
Merge pull request #26 from poliorcetics/safety-comments
Add SAFETY comments presentation
2 parents ea93474 + d91d005 commit 04ab11d

File tree

2 files changed

+80
-0
lines changed

2 files changed

+80
-0
lines changed

src/documentation/safety-comments.md

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Safety comments
2+
3+
Using [`unsafe`] blocks is often required in the Rust compiler or standard
4+
library, but this is not done without rules: each `unsafe` block should have
5+
a `SAFETY:` comment explaining why the block is safe, which invariants are
6+
used and must be respected. Below are some examples taken from the standard
7+
library:
8+
9+
[`unsafe`]: https://doc.rust-lang.org/stable/std/keyword.unsafe.html
10+
11+
## Inside `unsafe` elements
12+
13+
This one shows how an `unsafe` function can pass the requirements through to its
14+
caller with the use of documentation in a `# Safety` section while still having
15+
more invariants needed that are not required from callers. `clippy` has a
16+
lint for `# Safety` sections by the way.
17+
18+
[See the example on github][as_bytes_mut]
19+
20+
```rust
21+
/// Converts a mutable string slice to a mutable byte slice.
22+
///
23+
/// # Safety
24+
///
25+
/// The caller must ensure that the content of the slice is valid UTF-8
26+
/// before the borrow ends and the underlying `str` is used.
27+
///
28+
/// Use of a `str` whose contents are not valid UTF-8 is undefined behavior.
29+
///
30+
/// ...
31+
pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
32+
// SAFETY: the cast from `&str` to `&[u8]` is safe since `str`
33+
// has the same layout as `&[u8]` (only libstd can make this guarantee).
34+
// The pointer dereference is safe since it comes from a mutable reference which
35+
// is guaranteed to be valid for writes.
36+
unsafe { &mut *(self as *mut str as *mut [u8]) }
37+
}
38+
```
39+
40+
This example is for a function but the same principle applies to `unsafe trait`s
41+
like [`Send`] or [`Sync`] for example, though they have no `# Safety` section
42+
since their entire documentation is about why they are `unsafe`.
43+
44+
Note that in the Rust standard library, [`unsafe_op_in_unsafe_fn`] is active
45+
and so each `unsafe` operation in an `unsafe` function must be enclosed in an
46+
`unsafe` block. This makes it easier to review such functions and to document
47+
their `unsafe` parts.
48+
49+
[`Send`]: https://doc.rust-lang.org/stable/std/marker/trait.Send.html
50+
[`Sync`]: https://doc.rust-lang.org/stable/std/marker/trait.Sync.html
51+
[as_bytes_mut]: https://github.com/rust-lang/rust/blob/a08f25a7ef2800af5525762e981c24d96c14febe/library/core/src/str/mod.rs#L278
52+
[`unsafe_op_in_unsafe_fn`]: https://doc.rust-lang.org/rustc/lints/listing/allowed-by-default.html#unsafe-op-in-unsafe-fn
53+
54+
## Inside *safe* elements
55+
56+
Inside safe elements, a `SAFETY:` comment must not depend on anything from the
57+
caller beside properly constructed types and values (i.e, if your function
58+
receives a reference that is unaligned or null, it is the caller fault if it
59+
fails and not yours).
60+
61+
`SAFETY` comments in *safe* elements often rely on checks that are done before
62+
the `unsafe` block or on type invariants, like a division by `NonZeroU8` would
63+
not check for `0` before dividing.
64+
65+
[See the example on github][split_at]
66+
67+
```rust
68+
pub fn split_at(&self, mid: usize) -> (&str, &str) {
69+
// is_char_boundary checks that the index is in [0, .len()]
70+
if self.is_char_boundary(mid) {
71+
// SAFETY: just checked that `mid` is on a char boundary.
72+
unsafe { (self.get_unchecked(0..mid), self.get_unchecked(mid..self.len())) }
73+
} else {
74+
slice_error_fail(self, 0, mid)
75+
}
76+
}
77+
```
78+
79+
[split_at]: https://github.com/rust-lang/rust/blob/a08f25a7ef2800af5525762e981c24d96c14febe/library/core/src/str/mod.rs#L570

src/documentation/summary.md

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
- [doc alias policy](./doc-alias-policy.md)
2+
- [safety comments policy](./safety-comments.md)

0 commit comments

Comments
 (0)