1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
//! An example crate showing how to safely and performantly zero out all heap allocations in a process.
//!
//!
//! This crates makes the following changes from common zeroizing alloc implementations:
//!
//! - Introduce a faster zeroization implementation (original kept behind feature "reference_impl" for perf testing)
//! - Fix a potential casting bug
//! - Remove unit tests: although passing locally, they trigger UAF and UB, leading to inconsistency, which we don't want.
//! - Used `MIRIFLAGS="-Zmiri-ignore-leaks" cargo +nightly miri test -p op-alloc`
//!
//! <https://rust.godbolt.org> was a tool used to partially verify that zeroization will NOT be optimized out at `-Copt-level=3`
use ;
/// Allocator wrapper that zeros on free
;
// Reference implementation. Performance-wise, this is the same as using the `zeroize` crate,
// because it uses the same logic:
//
// ```rust
// unsafe fn zero(ptr: *mut u8, size: usize) {
// use zeroize::Zeroize;
// core::slice::from_raw_parts_mut(ptr, size).zeroize();
// }
// ```
//
// SAFETY: exactly one callsite (below), always passes the correct size
unsafe
unsafe
// This is meant to avoid compiler optimizations while still retaining performance.
//
// By storing a function to a performant `memset(0, dest)` call, we can performantly zero out bytes
// without the compiler realizing the values being cleared aren't going to be read from again since it does
// not know either the source of the bytes or the source of our clearing function.
//
// - By loading this function pointer volatilely, we ensure the compiler does not optimize thinking about the
// source of the function pointer.
// - `#[used]` presents an extra optimization barrier since it forces the compiler to keep it around (won't take part in codegen optimization)
// until it reaches the linker. Even if the linker removes it though, its still fine because that can't optimize code that depends on it.
static WIPER: unsafe fn = clear_bytes;
// SAFETY: exactly one callsite (below), always passes the correct size
unsafe
// SAFETY: wrapper for system allocator, zeroizes on free but otherwise re-uses system logic
unsafe