|
5 | 5 |
|
6 | 6 | Unsafety |
7 | 7 | ======== |
| 8 | + |
| 9 | +.. guideline:: All unsafe code shall be contained inside a sound safe abstraction |
| 10 | + :id: gui_goekLVFUAjSM |
| 11 | + :category: required |
| 12 | + :status: draft |
| 13 | + :release: - |
| 14 | + :fls: fls_jep7p27kaqlp |
| 15 | + :decidability: undecidable |
| 16 | + :scope: module |
| 17 | + :tags: undefined-behavior |
| 18 | + |
| 19 | + A safe abstraction is considered sound, when it is impossible to build a **safe** program using |
| 20 | + the safe abstraction that invokes undefined behavior. |
| 21 | + |
| 22 | + Safe abstractions shall be kept as small as possible and only include features that cannot be built |
| 23 | + on top in safe Rust. |
| 24 | + |
| 25 | + .. rationale:: |
| 26 | + :id: rat_3FoizIv2mZ4Z |
| 27 | + :status: draft |
| 28 | + |
| 29 | + Unsound safe abstractions leak the possibility for undefined behavior to safe Rust. |
| 30 | + With violations of this rule, it would no longer suffice to only focus on unsafe modules |
| 31 | + as the root cause of undefined behavior |
| 32 | + |
| 33 | + Because safe abstractions are more difficult to review compared to safe code due to the |
| 34 | + subtle semantics of unsafe operations, their size need to be minimized. |
| 35 | + |
| 36 | + .. non_compliant_example:: |
| 37 | + :id: non_compl_ex_4Rj4YQkr1Nr4 |
| 38 | + :status: draft |
| 39 | + |
| 40 | + The following module with a safe API uses unsafe code and is therefore a safe abstraction. |
| 41 | + However, when passing a data slice with an index that is outside the range of the slice, |
| 42 | + the safe function will cause undefined behavior. |
| 43 | + |
| 44 | + .. code-block:: rust |
| 45 | +
|
| 46 | + mod bad { |
| 47 | + fn get_value(data: &[i32], index: usize) -> i32 { |
| 48 | + unsafe { |
| 49 | + data.get_unchecked(usize) |
| 50 | + } |
| 51 | + } |
| 52 | + } |
| 53 | +
|
| 54 | + .. compliant_example:: |
| 55 | + :id: compl_ex_aM7w7UbgSdvT |
| 56 | + :status: draft |
| 57 | + |
| 58 | + This safe module checks that its argument are valid, (i.e., they satisfy the safety |
| 59 | + precondition of the unsafe operation) before performing the unsafe operation. |
| 60 | + |
| 61 | + .. code-block:: rust |
| 62 | +
|
| 63 | + mod good { |
| 64 | + fn get_value(data: &[i32], index: usize) -> i32 { |
| 65 | + assert!(usize < data.len()); |
| 66 | + unsafe { |
| 67 | + data.get_unchecked(usize) |
| 68 | + } |
| 69 | + } |
| 70 | + } |
0 commit comments