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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
//! 0.9.7 H-7 — test-only allocator hooks for OOM injection.
//!
//! Replaces the system global allocator with a forwarding wrapper
//! that consults a thread-local size threshold; allocations at or
//! above the threshold return `null` (OOM) so tests can validate
//! that fsys's fallible-alloc paths (`AlignedBuf::new`,
//! `read_all_direct`, etc.) gracefully surface
//! `Error::Io(OutOfMemory)` rather than panicking.
//!
//! ## Production safety
//!
//! This module compiles only when the **internal** `oom_inject`
//! cargo feature is enabled. The feature is documented as
//! "NEVER enable in production builds" — every allocation pays
//! a thread-local lookup + comparison. Default builds do not
//! pull this code in at all; the global allocator stays the
//! system default.
//!
//! ## Test isolation
//!
//! The threshold is a `thread_local!` value. Tests on different
//! threads have independent budgets; tests on the same thread
//! run sequentially under the default test runner. The
//! `OomThreshold` drop guard restores the threshold to
//! `usize::MAX` (no failures) on scope exit, including unwinding
//! on panic — so a panicking test never poisons subsequent tests.
//! (Plain code-formatting rather than an intra-doc link because
//! this module is `#[doc(hidden)]` from the published surface and
//! rustdoc rejects same-module intra-doc links to `pub(crate)`
//! / hidden items under `-D warnings`.)
//!
//! ## Targeted injection
//!
//! Rather than the count-based "fail the Nth alloc" approach
//! (fragile — sensitive to incidental allocations in the test
//! framework, the path being tested, etc.), this module uses
//! the **size-based** approach: tests set the threshold to
//! `S` and any allocation of `>= S` bytes fails. fsys's
//! load-bearing allocations are typically large (sector-
//! aligned buffers, log-buffer slots — 4 KiB to 64 KiB);
//! ordinary `Vec`/`String`/`PathBuf` allocations are smaller
//! and pass through unaffected.
use ;
use Cell;
thread_local!
/// Forwarding allocator that respects [`OOM_THRESHOLD`].
///
/// Allocations of `< threshold` bytes go to the system
/// allocator unchanged. Allocations of `>= threshold` bytes
/// return `null` (OOM), letting `AlignedBuf::new` /
/// `Vec::try_reserve_exact` / equivalent fallible-alloc paths
/// surface clean errors.
;
// SAFETY: `OomInjectingAllocator` forwards every successful
// allocation/deallocation to `System` (the default `GlobalAlloc`
// implementation) unchanged. The only deviation from `System` is
// returning a null pointer when the requested size meets the
// thread-local threshold — which is a permitted `GlobalAlloc::alloc`
// outcome (signalling OOM). `dealloc` always forwards to `System`,
// matching the (`ptr`, `layout`) pair the caller received from us
// (i.e., from `System`). No additional invariants are introduced.
unsafe
/// RAII guard that restores [`OOM_THRESHOLD`] to its prior value
/// on drop — including panic unwinding.
///
/// Tests construct this with the desired threshold, run the code
/// under test, and the guard restores the threshold on scope
/// exit. A panic in the test body still restores cleanly because
/// Drop runs during unwinding.
///
/// ```ignore
/// #[test]
/// fn aligned_buf_handles_oom() {
/// let _guard = OomThreshold::set(2048);
/// let result = AlignedBuf::new(4096, 4096);
/// assert!(result.is_err());
/// // `_guard` drops here, threshold restored to prior value.
/// }
/// ```