Skip to content

Commit 234ae3e

Browse files
Expand the rest of the non-unsafe behaviors into paragraphs with examples
1 parent 9e58e07 commit 234ae3e

File tree

1 file changed

+51
-9
lines changed

1 file changed

+51
-9
lines changed

src/behavior-not-considered-unsafe.md

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,6 @@ r[not-unsafe]
66
77
Rust does not consider the following behaviors _[unsafe]_, though a programmer may (or should) find them undesirable, unexpected, or erroneous.
88

9-
r[not-unsafe.resource-leaks]
10-
- Leaks of memory and other resources
11-
r[not-unsafe.abort]
12-
- Exiting without calling destructors
13-
r[not-unsafe.aslr-bypass]
14-
- Exposing randomized executable base addresses through pointer leaks
15-
169
r[not-unsafe.deadlocks]
1710
## Deadlocks and livelocks
1811

@@ -62,6 +55,52 @@ In general, determining whether a program has deadlocked requires to solve the [
6255
r[not-unsafe.livelocks]
6356
Livelocks are a related issue where no real progress is made in a group of tasks, yet they technically continue to run. For instance, using non-blocking synchronization primitives like spinlocks or atomic variables can quickly lead to livelocks. This is in opposition to deadlocks, where tasks are blocked on resource acquisition, which is relatively easy to discern. Therefore, livelocks are much harder to detect than deadlocks, but equally undesirable.
6457

58+
r[not-unsafe.resource-leaks]
59+
## Leaks of memory and other resources
60+
61+
A leaking resource is one that is never freed, even when it is no longer needed. Among the resources commonly leaked are memory, file descriptors, and networking sockets. Resource leaks may cause the program to accumulate unused resources until certain constraints by the environment are reached, such as the system running out of memory (OOM). In this case, a variety of non-normal behavior can occur, such as program termination by the operating system, common for OOM conditions, or failure to acquire further resources of the given type, common for file descriptors and sockets.
62+
63+
> [!EXAMPLE]
64+
> Using reference counting via [Rc](`std::rc::Rc`), it is possible to construct a reference cycle, where two data structures point at each other via `Rc`. Since both hold a reference to the other, the `Rc`s always have a reference count of at least 1, and their inner values are never dropped: a memory leak. Note that while implementing the following scenario requires some unsafe code in the standard library, the safety conditions are never violated, and the program is correct as far as `Rc`'s and `RefCell`'s unsafe code is concerned.
65+
>
66+
> ```rust
67+
> use std::cell::RefCell;
68+
> use std::rc::Rc;
69+
>
70+
> struct Node(Option<Rc<RefCell<Node>>>);
71+
>
72+
> impl Node {
73+
> fn link_to_other(&mut self, other: Rc<RefCell<Node>>) {
74+
> self.0 = Some(other);
75+
> }
76+
> }
77+
>
78+
> fn main() {
79+
> let a = Rc::new(RefCell::new(Node(None)));
80+
> let b = Rc::new(RefCell::new(Node(None)));
81+
> a.borrow_mut().link_to_other(b.clone());
82+
> b.borrow_mut().link_to_other(a.clone());
83+
> // a and b are never deallocated, even when dropped here.
84+
> }
85+
> ```
86+
87+
r[not-unsafe.abort]
88+
## Exiting without calling destructors
89+
90+
When [panicking], a program may abort execution; that is, exit immediately without further activities. There are several instances in which abort on panic can happen, such as a double panic or with a compiler option to always use the abort strategy.
91+
92+
Unlike unwinding, which runs [destructors] for each object in each unwound frame, aborting does not run any destructors in any frame. Any code relying on certain destructors to run might therefore not function correctly.
93+
94+
r[not-unsafe.aslr-bypass]
95+
## Exposing randomized executable base addresses through pointer leaks
96+
97+
[Address space layout randomization] (ASLR) is a security mitigation which moves program segments to randomized (virtual) memory addresses each time the program is started. Without knowing the absolute positions of code or data in a program, this complicates binary exploitation.
98+
99+
> [!NOTE]
100+
> Whether the executable has ASLR support depends on the target, compiler flags, linker options, and more. Embedded targets usually do not support ASLR at all, while it is commonplace for "normal" targets on modern operating systems. Rust does not guarantee ASLR support, though the compiler and target documentation should specify their ASLR support.
101+
102+
When a pointer is leaked that has a fixed known offset to a segment base address, such as a [function pointer], an attacker can derive the base address regardless of ASLR, usually bypassing its protections. A leak may occur in many ways, such as by displaying the pointer’s numeric value to the user.
103+
65104
r[not-unsafe.integer-overflow]
66105
## Integer overflow
67106
@@ -103,13 +142,16 @@ Safe code may impose extra logical constraints that can be checked at neither co
103142
> }
104143
> }
105144
> ```
106-
107-
Another example are data structures like [`BinaryHeap`](`alloc::collections::binary_heap::BinaryHeap`), [`BTreeMap`](`alloc::collections::btree_map::BTreeMap`), [`BTreeSet`](`alloc::collections::btree_set::BTreeSet`), [`HashMap`](`std::collections::HashMap`), and [`HashSet`](`std::collections::HashSet`), which describe constraints on the modification of their keys while they are in the data structure. Violating such constraints is not considered unsafe, yet the program is considered erroneous and its behavior unpredictable.
145+
>
146+
> Related, data structures like [`BinaryHeap`](`alloc::collections::binary_heap::BinaryHeap`), [`BTreeMap`](`alloc::collections::btree_map::BTreeMap`), [`BTreeSet`](`alloc::collections::btree_set::BTreeSet`), [`HashMap`](`std::collections::HashMap`), and [`HashSet`](`std::collections::HashSet`) describe constraints on the modification of their keys while they are in the data structure. Violating such constraints is not considered unsafe, yet the program is considered erroneous and its behavior unpredictable.
108147
109148
[RFC 560]: https://github.com/rust-lang/rfcs/blob/master/text/0560-integer-overflow.md
110149
[unsafe]: safety.unsafe-ops
111150
[undefined]: undefined
151+
[panicking]: panic
112152
[debug_assertions]: cfg.debug_assertions
113153
[integer types]: type.numeric.int
114154
[Halting problem]: https://en.wikipedia.org/wiki/Halting_problem
115155
[tokio]: https://tokio.rs/
156+
[Address space layout randomization]: https://en.wikipedia.org/wiki/Address_space_layout_randomization
157+
[function pointer]: type.fn-pointer

0 commit comments

Comments
 (0)