Skip to content

Commit 1a71d4f

Browse files
committed
remove example about safe/unsafe trust relation
1 parent ae661f3 commit 1a71d4f

File tree

3 files changed

+2
-235
lines changed

3 files changed

+2
-235
lines changed

examples/src/generalities.rs

Lines changed: 0 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -30,53 +30,3 @@ impl<T> Vec<T> {
3030
}
3131
}
3232
// ANCHOR_END: make_room
33-
34-
// ANCHOR: Locatable
35-
trait Locatable {
36-
/// Find object of type `Self` in the buffer `buf`.
37-
/// Returns the index of the first byte representing
38-
/// an object of type `Self`
39-
fn locate_instance_into(buf: &[u8]) -> Option<usize>;
40-
41-
fn find(buf: &[u8]) -> Option<Self>
42-
where
43-
Self: Sized,
44-
{
45-
let start = Self::locate_instance_into(buf)?;
46-
unsafe {
47-
let ptr: *const Self = buf.as_ptr().add(start).cast();
48-
Some(ptr.read_unaligned())
49-
}
50-
}
51-
}
52-
// ANCHOR_END: Locatable
53-
#[cfg(feature = "OK")]
54-
mod ok {
55-
use super::*;
56-
// ANCHOR: Locatable_bool_OK
57-
impl Locatable for bool {
58-
fn locate_instance_into(buf: &[u8]) -> Option<usize> {
59-
buf.iter().position(|u| *u == 0 || *u == 1)
60-
}
61-
}
62-
// ANCHOR_END: Locatable_bool_OK
63-
}
64-
#[cfg(feature = "KO")]
65-
mod bad {
66-
use super::*;
67-
// ANCHOR: Locatable_bool_KO
68-
impl Locatable for bool {
69-
fn locate_instance_into(buf: &[u8]) -> Option<usize> {
70-
buf.iter().position(|u| *u == 0 || *u == 1).map(|n| n + 100)
71-
}
72-
}
73-
// ANCHOR_END: Locatable_bool_KO
74-
75-
// ANCHOR: Locatable_UB
76-
fn use_locatable() {
77-
let buf = [4, 1, 99];
78-
let located_bool: Option<bool> = bool::find(&buf); // UB here!
79-
println!("{:?}", located_bool)
80-
}
81-
// ANCHOR_END: Locatable_UB
82-
}

src/en/unsafe/generalities.md

Lines changed: 1 addition & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ without an `unsafe` block must be marked as `unsafe` if it breaks these
119119
invariants. The choice and knowledge of these invariants are therefore crucial
120120
for secure development.
121121

122-
### Example 1: Preserving a type invariant
122+
## Example: Preserving a type invariant
123123

124124
The following code comes from the [Rustonomicon](https://doc.rust-lang.org/nomicon/working-with-unsafe.html).
125125
It could be used to implement a custom `Vec` type.
@@ -137,91 +137,3 @@ This invariant can be broken with *safe* code. For instance
137137
```
138138

139139
This function may be necessary for internal use, but it should not be exposed in the API, or it should be marked with the `unsafe` keyword, because its use can lead to UB.
140-
141-
### Example 2: Trust relationship between *safe* and *unsafe*
142-
143-
In the Rust paradigm:
144-
145-
> `unsafe`-free code cannot go wrong
146-
147-
which means it cannot result in UB.
148-
This property is lost when developers use *unsafe* code, so they are responsible for not producing UB in any scenario.
149-
Consequently, even *safe* functions must be handled carefully in *unsafe* contexts.
150-
151-
Suppose one wants to propose an API to find an object of a given type in memory.
152-
This API could require implementing the following trait:
153-
154-
```rust bad
155-
{{#include ../../../examples/src/generalities.rs:Locatable}}
156-
```
157-
158-
This trait can be implemented **without** using `unsafe`.
159-
160-
For instance, the `bool` type can implement this trait as follows:
161-
162-
```rust,ignore align
163-
{{#include ../../../examples/src/generalities.rs:Locatable_bool_OK}}
164-
```
165-
166-
<div class="warning">
167-
168-
The `Locatable`'s API is harmful for two reasons:
169-
170-
* If the `Locatable` implementation does not give the index of an object of type `T`, the `read_unaligned` may produce UB.
171-
* If the `Locatable` implementation gives an out-of-bounds index or an index for which part of the object is out of bounds, the subsequent buffer overflow is UB.
172-
173-
</div>
174-
175-
For instance, the following `Locatable` implementation is incorrect, **but** it is the responsibility of the API author to take it into account.
176-
177-
```rust align bad
178-
{{#include ../../../examples/src/generalities.rs:Locatable_bool_KO}}
179-
```
180-
181-
The following program produces UB.
182-
183-
```rust,ignore align ub
184-
{{#include ../../../examples/src/generalities.rs:Locatable_UB}}
185-
```
186-
187-
The UB-detecting tool `miri` reports the following:
188-
189-
```default
190-
$ cargo +nightly miri r --bin overflow
191-
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.01s
192-
Running `/home/user/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/cargo-miri runner target/miri/x86_64-unknown-linux-gnu/debug/overflow`
193-
error: Undefined Behavior: in-bounds pointer arithmetic failed: attempting to offset pointer by 101 bytes, but got alloc249 which is only 3 bytes from the end of the allocation
194-
--> src/overflow.rs:16:29
195-
|
196-
16 | let ptr: *const T = buf.as_ptr().add(start).cast();
197-
| ^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
198-
|
199-
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
200-
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
201-
help: alloc249 was allocated here:
202-
--> src/overflow.rs:22:9
203-
|
204-
22 | let buf = [4, 1, 99];
205-
| ^^^
206-
= note: BACKTRACE (of the first span):
207-
= note: inside `find::<bool>` at src/overflow.rs:16:29: 16:52
208-
note: inside `main`
209-
--> src/overflow.rs:23:38
210-
|
211-
23 | let located_bool: Option<bool> = find(&buf); // UB here!
212-
| ^^^^^^^^^^
213-
214-
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
215-
216-
error: aborting due to 1 previous error
217-
```
218-
219-
This example shows that developers using `unsafe` blocks
220-
cannot assume that *safe* functions or traits they use are well implemented, and thus must prevent UB in case these *safe* functions have bad behavior.
221-
222-
If they cannot protect their function against poorly implemented *safe* functions or traits, they have two options:
223-
224-
* Mark the function they *write* as `unsafe`: thus, it is the user's responsibility to provide correct arguments (by checking the `unsafe` function's documentation).
225-
* Mark the traits they *use* as `unsafe`: thus, it is the user's responsibility to implement the trait properly (again, by reading the trait documentation).
226-
227-
More examples can be found in [@rust-book] (in the [Unsafe Rust](https://doc.rust-lang.org/book/ch20-01-unsafe-rust.html) chapter) or the [nomicon](https://doc.rust-lang.org/nomicon/safe-unsafe-meaning.html).

src/fr/unsafe/generalities.md

Lines changed: 1 addition & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ tout code `unsafe` DOIT être encapsulé de manière :
133133

134134
Ainsi, une fonction utilisant des opérations `unsafe` peut-être sûre (et donc sans marque `unsafe`) si les opérations `unsafe` ne présentent pas d'*UB* étant donnés les invariants du composant (typiquement l'invariant de type pour une méthode). Inversement, une fonction sans bloc `unsafe` doit être marquée `unsafe` si elle casse ces invariants. Le choix et la connaissance de ces invariants sont donc cruciaux pour le développement sécurisé.
135135

136-
### Exemple 1 : préservation d'un invariant de type
136+
## Exemple : préservation d'un invariant de type
137137

138138
La protection des invariants d'une bibliothèque est primordiale pour se prémunir de
139139
bugs en général, d'*UB* en particulier.
@@ -158,98 +158,3 @@ Or, il est possible de casser cet invariant avec du code *safe*. Par exemple, co
158158
Si elle peut être tout à fait légitime pour du code *interne* à l'API,
159159
cette méthode ne doit pas être exposée par l'API ou alors doit être annotée
160160
par `unsafe` car elle peut conduire à des *UB* (même si elle ne comporte pas de blocs *unsafe*s).
161-
162-
### Exemple 2 : relation de confiance *safe*/*unsafe*
163-
164-
La relation de confiance entre le code *safe* et le code `unsafe` est délicate.
165-
Dans un composant logiciel, le code `unsafe` doit être écrit de manière à ce qu'aucun usage *safe* du composant ne puisse conduire à des *UB*.
166-
167-
Le cas suivant illustre ce principe.
168-
On souhaite ici proposer une API générique permettant de localiser un objet dans une zone mémoire.
169-
On demande donc à l'utilisateur de l'API de fournir une implémentation à ce trait :
170-
171-
```rust,ignore bad
172-
{{#include ../../../examples/src/generalities.rs:Locatable}}
173-
```
174-
175-
L'implémentation d'un tel trait peut être réalisée en utilisant du code **sans** `unsafe`.
176-
177-
Par exemple, on peut implémenter ce trait pour le type `bool` comme suit :
178-
179-
```rust,ignore align
180-
{{#include ../../../examples/src/generalities.rs:Locatable_bool_OK}}
181-
```
182-
183-
<div class="warning">
184-
185-
L'API du trait `Locatable` est mauvaise pour deux raisons :
186-
187-
* si l'implémentation de `Locatable` ne donne pas l'index d'un objet de type `T`, alors la fonction `read_unaligned` peut produire un *UB*.
188-
* si l'implémentation de `Locatable` renvoie un index en dehors du tableau ou un index tel que l'objet de type `T` ne soit pas entièrement contenu dans le tableau, alors un dépassement de tableau se produit.
189-
190-
</div>
191-
192-
Par exemple, cette implémentation de `Locatable` est fautive alors qu'elle n'est pas `unsafe` :
193-
194-
```rust,ignore align bad
195-
{{#include ../../../examples/src/generalities.rs:Locatable_bool_KO}}
196-
```
197-
198-
L'exécution du programme suivant produit un *UB* :
199-
200-
```rust,ignore align ub
201-
{{#include ../../../examples/src/generalities.rs:Locatable_UB}}
202-
```
203-
204-
Voici le retour obtenu avec l'outil de détection de comportement indéfini `miri` :
205-
206-
```default
207-
$ cargo +nightly miri r --bin overflow
208-
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.01s
209-
Running `/home/user/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/cargo-miri runner target/miri/x86_64-unknown-linux-gnu/debug/overflow`
210-
error: Undefined Behavior: in-bounds pointer arithmetic failed: attempting to offset pointer by 101 bytes, but got alloc249 which is only 3 bytes from the end of the allocation
211-
--> src/overflow.rs:16:29
212-
|
213-
16 | let ptr: *const T = buf.as_ptr().add(start).cast();
214-
| ^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
215-
|
216-
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
217-
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
218-
help: alloc249 was allocated here:
219-
--> src/overflow.rs:22:9
220-
|
221-
22 | let buf = [4, 1, 99];
222-
| ^^^
223-
= note: BACKTRACE (of the first span):
224-
= note: inside `find::<bool>` at src/overflow.rs:16:29: 16:52
225-
note: inside `main`
226-
--> src/overflow.rs:23:38
227-
|
228-
23 | let located_bool: Option<bool> = find(&buf); // UB here!
229-
| ^^^^^^^^^^
230-
231-
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
232-
233-
error: aborting due to 1 previous error
234-
```
235-
236-
Dans cet exemple, il est rappelé que la responsabilité de l'exécution *safe*
237-
(sans *UB*) d'un code Rust incombe à la personne utilisant des blocs *unsafe*.
238-
239-
S'il n'est pas possible de se protéger contre les fonctions/traits *safe*s lors de l'écriture d'une fonction contenant un bloc *unsafe*, deux solutions sont possibles :
240-
241-
* marquer la fonction comme *unsafe* : ainsi la responsabilité de sa bonne exécution revient à la personne utilisant cette fonction, notamment en l'obligeant à vérifier dans la documentation de la fonction que les arguments fournis répondent bien à la spécification de la fonction
242-
* marquer le trait dont dépend la fonction comme *unsafe* : ainsi, de même, la responsabilité de la bonne exécution du programme revient à l'implémenteur du trait en s'assurant que l'implémentation répond bien aux spécifications du trait (présente dans sa documentation).
243-
244-
On pourra se référer à [@rust-book] (au chapitre [Unsafe Rust](https://doc.rust-lang.org/book/ch20-01-unsafe-rust.html)) où au [nomicon](https://doc.rust-lang.org/nomicon/safe-unsafe-meaning.html) pour d'autres exemples.
245-
246-
<!--
247-
Dans ce cas particulier, la solution la plus adaptée est sans doute de marquer le trait `Locatable` comme `unsafe` :
248-
249-
```rust
250-
{{#include ../../../examples/unsafe2/src/fix.rs::14}}
251-
```
252-
253-
Le supertrait `Copy` permet de s'assurer que le type peut être copié par une simple lecture mémoire.
254-
Une alternative serait de l'ajouter aux conditions de sûreté du trait.
255-
-->

0 commit comments

Comments
 (0)