xref: /wasmtime-44.0.1/crates/fuzzing/src/oom.rs (revision 5c68fe60)
1cf48211cSNick Fitzgerald //! Utilities for testing and fuzzing out-of-memory handling.
2cf48211cSNick Fitzgerald //!
3cf48211cSNick Fitzgerald //! Inspired by SpiderMonkey's `oomTest()` helper:
4cf48211cSNick Fitzgerald //! https://firefox-source-docs.mozilla.org/js/hacking_tips.html#how-to-debug-oomtest-failures
5cf48211cSNick Fitzgerald 
6cf48211cSNick Fitzgerald use backtrace::Backtrace;
7*5c68fe60SNick Fitzgerald use std::{
8*5c68fe60SNick Fitzgerald     alloc::GlobalAlloc,
9*5c68fe60SNick Fitzgerald     cell::Cell,
10*5c68fe60SNick Fitzgerald     mem,
11*5c68fe60SNick Fitzgerald     pin::Pin,
12*5c68fe60SNick Fitzgerald     ptr,
13*5c68fe60SNick Fitzgerald     task::{Context, Poll},
14*5c68fe60SNick Fitzgerald     time,
15*5c68fe60SNick Fitzgerald };
16*5c68fe60SNick Fitzgerald use wasmtime_core::error::{OutOfMemory, Result, bail};
17cf48211cSNick Fitzgerald 
18cf48211cSNick Fitzgerald /// An allocator for use with `OomTest`.
19cf48211cSNick Fitzgerald #[non_exhaustive]
20cf48211cSNick Fitzgerald pub struct OomTestAllocator;
21cf48211cSNick Fitzgerald 
22cf48211cSNick Fitzgerald impl OomTestAllocator {
23cf48211cSNick Fitzgerald     /// Create a new OOM test allocator.
new() -> Self24cf48211cSNick Fitzgerald     pub const fn new() -> Self {
25cf48211cSNick Fitzgerald         OomTestAllocator
26cf48211cSNick Fitzgerald     }
27cf48211cSNick Fitzgerald }
28cf48211cSNick Fitzgerald 
29cf48211cSNick Fitzgerald #[derive(Clone, Debug, Default, PartialEq, Eq)]
30cf48211cSNick Fitzgerald enum OomState {
31cf48211cSNick Fitzgerald     /// We are in code that is not part of an OOM test.
32cf48211cSNick Fitzgerald     #[default]
33cf48211cSNick Fitzgerald     OutsideOomTest,
34cf48211cSNick Fitzgerald 
35cf48211cSNick Fitzgerald     /// We are inside an OOM test and should inject an OOM when the counter
36cf48211cSNick Fitzgerald     /// reaches zero.
37755979ddSNick Fitzgerald     OomOnAlloc {
38755979ddSNick Fitzgerald         counter: u32,
39755979ddSNick Fitzgerald         allow_alloc_after: bool,
40755979ddSNick Fitzgerald     },
41cf48211cSNick Fitzgerald 
42cf48211cSNick Fitzgerald     /// We are inside an OOM test and we already injected an OOM.
43755979ddSNick Fitzgerald     DidOom { allow_alloc: bool },
44cf48211cSNick Fitzgerald }
45cf48211cSNick Fitzgerald 
46cf48211cSNick Fitzgerald thread_local! {
47cf48211cSNick Fitzgerald     static OOM_STATE: Cell<OomState> = const { Cell::new(OomState::OutsideOomTest) };
48cf48211cSNick Fitzgerald }
49cf48211cSNick Fitzgerald 
50cf48211cSNick Fitzgerald /// Set the new OOM state, returning the old state.
set_oom_state(state: OomState) -> OomState51cf48211cSNick Fitzgerald fn set_oom_state(state: OomState) -> OomState {
52cf48211cSNick Fitzgerald     OOM_STATE.with(|s| s.replace(state))
53cf48211cSNick Fitzgerald }
54cf48211cSNick Fitzgerald 
55cf48211cSNick Fitzgerald /// RAII helper to set the OOM state within a block of code and reset it upon
56cf48211cSNick Fitzgerald /// exiting that block (even if exiting via panic unwinding).
57*5c68fe60SNick Fitzgerald struct ScopedOomState<'a> {
58*5c68fe60SNick Fitzgerald     state: &'a mut OomState,
59cf48211cSNick Fitzgerald }
60cf48211cSNick Fitzgerald 
61*5c68fe60SNick Fitzgerald impl<'a> ScopedOomState<'a> {
62*5c68fe60SNick Fitzgerald     /// The OOM state will be initialized to `*state` on construction, and then
63*5c68fe60SNick Fitzgerald     /// `state` will be updated to be the old OOM state that existed when the
64*5c68fe60SNick Fitzgerald     /// original state is replaced on this type's drop.
new(state: &'a mut OomState) -> Self65*5c68fe60SNick Fitzgerald     fn new(state: &'a mut OomState) -> Self {
66*5c68fe60SNick Fitzgerald         *state = set_oom_state(mem::take(state));
67*5c68fe60SNick Fitzgerald         ScopedOomState { state }
68cf48211cSNick Fitzgerald     }
69cf48211cSNick Fitzgerald }
70cf48211cSNick Fitzgerald 
71*5c68fe60SNick Fitzgerald impl Drop for ScopedOomState<'_> {
drop(&mut self)72cf48211cSNick Fitzgerald     fn drop(&mut self) {
73*5c68fe60SNick Fitzgerald         *self.state = set_oom_state(mem::take(self.state));
74cf48211cSNick Fitzgerald     }
75cf48211cSNick Fitzgerald }
76cf48211cSNick Fitzgerald 
77cf48211cSNick Fitzgerald unsafe impl GlobalAlloc for OomTestAllocator {
alloc(&self, layout: std::alloc::Layout) -> *mut u878cf48211cSNick Fitzgerald     unsafe fn alloc(&self, layout: std::alloc::Layout) -> *mut u8 {
79cf48211cSNick Fitzgerald         let old_state = set_oom_state(OomState::OutsideOomTest);
80cf48211cSNick Fitzgerald 
81cf48211cSNick Fitzgerald         let new_state;
82cf48211cSNick Fitzgerald         let ptr;
83b236888cSNick Fitzgerald 
84b236888cSNick Fitzgerald         'outside_oom_test: {
85cf48211cSNick Fitzgerald             // NB: It's okay to log/backtrace/etc... in this block because the
86cf48211cSNick Fitzgerald             // current state is `OutsideOomTest`, so any re-entrant allocations
87cf48211cSNick Fitzgerald             // will be passed through to the system allocator.
88cf48211cSNick Fitzgerald 
89b236888cSNick Fitzgerald             // Don't panic on allocation-after-OOM attempts if we
90b236888cSNick Fitzgerald             // are already in the middle of panicking. That will
91b236888cSNick Fitzgerald             // cause an abort and we won't get as good of an error
92b236888cSNick Fitzgerald             // message for the original panic, which is most likely
93b236888cSNick Fitzgerald             // some kind of test failure.
94b236888cSNick Fitzgerald             if old_state == OomState::OutsideOomTest || std::thread::panicking() {
95b236888cSNick Fitzgerald                 new_state = old_state;
96cf48211cSNick Fitzgerald                 ptr = unsafe { std::alloc::System.alloc(layout) };
97b236888cSNick Fitzgerald                 break 'outside_oom_test;
98cf48211cSNick Fitzgerald             }
99071704b4SNick Fitzgerald 
100b236888cSNick Fitzgerald             let bt = Backtrace::new();
101b236888cSNick Fitzgerald             let bt = format!("{bt:?}");
102b236888cSNick Fitzgerald 
103b236888cSNick Fitzgerald             // XXX: `env_logger` internally buffers writes in a `Vec` which
104b236888cSNick Fitzgerald             // means our OOM tests might sporadically fail when you enable
105b236888cSNick Fitzgerald             // logging to debug stuff, so simply let the allocation through if
106b236888cSNick Fitzgerald             // `env_logger` is on the stack.
107b236888cSNick Fitzgerald             if bt.contains("env_logger") {
108b236888cSNick Fitzgerald                 new_state = old_state;
109b236888cSNick Fitzgerald                 ptr = unsafe { std::alloc::System.alloc(layout) };
110b236888cSNick Fitzgerald                 break 'outside_oom_test;
111b236888cSNick Fitzgerald             }
112b236888cSNick Fitzgerald 
113b236888cSNick Fitzgerald             match old_state {
114b236888cSNick Fitzgerald                 OomState::OutsideOomTest => unreachable!("handled above"),
115b236888cSNick Fitzgerald 
116755979ddSNick Fitzgerald                 OomState::OomOnAlloc {
117755979ddSNick Fitzgerald                     counter: 0,
118755979ddSNick Fitzgerald                     allow_alloc_after,
119755979ddSNick Fitzgerald                 } => {
120cf48211cSNick Fitzgerald                     log::trace!(
121b236888cSNick Fitzgerald                         "injecting OOM for allocation: {layout:?}\nAllocation backtrace:\n{bt}"
122cf48211cSNick Fitzgerald                     );
123755979ddSNick Fitzgerald                     new_state = OomState::DidOom {
124755979ddSNick Fitzgerald                         allow_alloc: allow_alloc_after,
125755979ddSNick Fitzgerald                     };
126cf48211cSNick Fitzgerald                     ptr = ptr::null_mut();
127cf48211cSNick Fitzgerald                 }
128071704b4SNick Fitzgerald 
129755979ddSNick Fitzgerald                 OomState::OomOnAlloc {
130755979ddSNick Fitzgerald                     counter: c,
131755979ddSNick Fitzgerald                     allow_alloc_after,
132755979ddSNick Fitzgerald                 } => {
133755979ddSNick Fitzgerald                     new_state = OomState::OomOnAlloc {
134755979ddSNick Fitzgerald                         counter: c - 1,
135755979ddSNick Fitzgerald                         allow_alloc_after,
136755979ddSNick Fitzgerald                     };
137cf48211cSNick Fitzgerald                     ptr = unsafe { std::alloc::System.alloc(layout) };
138cf48211cSNick Fitzgerald                 }
139071704b4SNick Fitzgerald 
140755979ddSNick Fitzgerald                 OomState::DidOom { allow_alloc } => {
141b236888cSNick Fitzgerald                     log::trace!("Attempt to allocate {layout:?} after OOM:\n{bt}");
142755979ddSNick Fitzgerald                     if allow_alloc {
143755979ddSNick Fitzgerald                         new_state = OomState::DidOom { allow_alloc: true };
144755979ddSNick Fitzgerald                         ptr = ptr::null_mut();
145755979ddSNick Fitzgerald                     } else {
146755979ddSNick Fitzgerald                         panic!(
147755979ddSNick Fitzgerald                             "OOM test attempted to allocate after OOM: {layout:?}\n\
148755979ddSNick Fitzgerald                              \n\
149755979ddSNick Fitzgerald                              Hint: if this is acceptable, configure the OOM test to allow allocation \
150755979ddSNick Fitzgerald                              after OOM with `OomTest::allow_alloc_after_oom`"
151755979ddSNick Fitzgerald                         )
152755979ddSNick Fitzgerald                     }
153cf48211cSNick Fitzgerald                 }
154cf48211cSNick Fitzgerald             }
155cf48211cSNick Fitzgerald         }
156cf48211cSNick Fitzgerald 
157cf48211cSNick Fitzgerald         set_oom_state(new_state);
158cf48211cSNick Fitzgerald         ptr
159cf48211cSNick Fitzgerald     }
160cf48211cSNick Fitzgerald 
dealloc(&self, ptr: *mut u8, layout: std::alloc::Layout)161cf48211cSNick Fitzgerald     unsafe fn dealloc(&self, ptr: *mut u8, layout: std::alloc::Layout) {
162cf48211cSNick Fitzgerald         unsafe {
163cf48211cSNick Fitzgerald             std::alloc::System.dealloc(ptr, layout);
164cf48211cSNick Fitzgerald         }
165cf48211cSNick Fitzgerald     }
166cf48211cSNick Fitzgerald }
167cf48211cSNick Fitzgerald 
168cf48211cSNick Fitzgerald /// A test helper that checks that some code handles OOM correctly.
169cf48211cSNick Fitzgerald ///
170cf48211cSNick Fitzgerald /// `OomTest` will only work correctly when `OomTestAllocator` is configured as
171cf48211cSNick Fitzgerald /// the global allocator.
172cf48211cSNick Fitzgerald ///
173cf48211cSNick Fitzgerald /// `OomTest` does not support reentrancy, so you cannot run an `OomTest` within
174cf48211cSNick Fitzgerald /// an `OomTest`.
175cf48211cSNick Fitzgerald ///
176cf48211cSNick Fitzgerald /// # Example
177cf48211cSNick Fitzgerald ///
178cf48211cSNick Fitzgerald /// ```no_run
179cf48211cSNick Fitzgerald /// use std::time::Duration;
180cf48211cSNick Fitzgerald /// use wasmtime::Result;
181cf48211cSNick Fitzgerald /// use wasmtime_fuzzing::oom::{OomTest, OomTestAllocator};
182cf48211cSNick Fitzgerald ///
183cf48211cSNick Fitzgerald /// #[global_allocator]
184ab78bd82SHo Kim /// static GLOBAL_ALLOCATOR: OomTestAllocator = OomTestAllocator::new();
185cf48211cSNick Fitzgerald ///
186cf48211cSNick Fitzgerald /// #[test]
187cf48211cSNick Fitzgerald /// fn my_oom_test() -> Result<()> {
188cf48211cSNick Fitzgerald ///     OomTest::new()
189cf48211cSNick Fitzgerald ///         .max_iters(1_000_000)
190cf48211cSNick Fitzgerald ///         .max_duration(Duration::from_secs(5))
191755979ddSNick Fitzgerald ///         .allow_alloc_after_oom(true)
192cf48211cSNick Fitzgerald ///         .test(|| {
193cf48211cSNick Fitzgerald ///             todo!("insert code here that should handle OOM here...")
194cf48211cSNick Fitzgerald ///         })
195cf48211cSNick Fitzgerald /// }
196cf48211cSNick Fitzgerald /// ```
197cf48211cSNick Fitzgerald pub struct OomTest {
198cf48211cSNick Fitzgerald     max_iters: Option<u32>,
199cf48211cSNick Fitzgerald     max_duration: Option<time::Duration>,
200755979ddSNick Fitzgerald     allow_alloc_after_oom: bool,
201cf48211cSNick Fitzgerald }
202cf48211cSNick Fitzgerald 
203cf48211cSNick Fitzgerald impl OomTest {
204cf48211cSNick Fitzgerald     /// Create a new OOM test.
205cf48211cSNick Fitzgerald     ///
206cf48211cSNick Fitzgerald     /// By default there is no iteration or time limit, tests will be executed
207cf48211cSNick Fitzgerald     /// until the pass (or fail).
new() -> Self208cf48211cSNick Fitzgerald     pub fn new() -> Self {
209cf48211cSNick Fitzgerald         let _ = env_logger::try_init();
210dfdd6539SNick Fitzgerald 
211dfdd6539SNick Fitzgerald         // NB: `std::backtrace::Backtrace` doesn't have ways to handle
212dfdd6539SNick Fitzgerald         // OOM. Ideally we would just disable the `"backtrace"` cargo feature,
213dfdd6539SNick Fitzgerald         // but workspace feature resolution doesn't play nice with that.
2148325e1ecSAlex Crichton         wasmtime_core::error::disable_backtrace();
215dfdd6539SNick Fitzgerald 
216cf48211cSNick Fitzgerald         OomTest {
217cf48211cSNick Fitzgerald             max_iters: None,
218cf48211cSNick Fitzgerald             max_duration: None,
219755979ddSNick Fitzgerald             allow_alloc_after_oom: false,
220cf48211cSNick Fitzgerald         }
221cf48211cSNick Fitzgerald     }
222cf48211cSNick Fitzgerald 
223cf48211cSNick Fitzgerald     /// Configure the maximum number of times to run an OOM test.
max_iters(&mut self, max_iters: u32) -> &mut Self224cf48211cSNick Fitzgerald     pub fn max_iters(&mut self, max_iters: u32) -> &mut Self {
225cf48211cSNick Fitzgerald         self.max_iters = Some(max_iters);
226cf48211cSNick Fitzgerald         self
227cf48211cSNick Fitzgerald     }
228cf48211cSNick Fitzgerald 
229cf48211cSNick Fitzgerald     /// Configure the maximum duration of time to run an OOM text.
max_duration(&mut self, max_duration: time::Duration) -> &mut Self230cf48211cSNick Fitzgerald     pub fn max_duration(&mut self, max_duration: time::Duration) -> &mut Self {
231cf48211cSNick Fitzgerald         self.max_duration = Some(max_duration);
232cf48211cSNick Fitzgerald         self
233cf48211cSNick Fitzgerald     }
234cf48211cSNick Fitzgerald 
235755979ddSNick Fitzgerald     /// Configure whether to allow allocation attempts after an OOM has already
236755979ddSNick Fitzgerald     /// been injected.
237755979ddSNick Fitzgerald     ///
238755979ddSNick Fitzgerald     /// The default is `false`.
allow_alloc_after_oom(&mut self, allow: bool) -> &mut Self239755979ddSNick Fitzgerald     pub fn allow_alloc_after_oom(&mut self, allow: bool) -> &mut Self {
240755979ddSNick Fitzgerald         self.allow_alloc_after_oom = allow;
241755979ddSNick Fitzgerald         self
242755979ddSNick Fitzgerald     }
243755979ddSNick Fitzgerald 
244cf48211cSNick Fitzgerald     /// Repeatedly run the given test function, injecting OOMs at different
245cf48211cSNick Fitzgerald     /// times and checking that it correctly handles them.
246cf48211cSNick Fitzgerald     ///
247cf48211cSNick Fitzgerald     /// The test function should not use threads, or else allocations may not be
248cf48211cSNick Fitzgerald     /// tracked correctly and OOM injection may be incorrect.
249cf48211cSNick Fitzgerald     ///
250cf48211cSNick Fitzgerald     /// The test function should return an `Err(_)` if and only if it encounters
251cf48211cSNick Fitzgerald     /// an OOM.
252cf48211cSNick Fitzgerald     ///
253cf48211cSNick Fitzgerald     /// Returns early once the test function returns `Ok(())` before an OOM has
254cf48211cSNick Fitzgerald     /// been injected.
test(&self, test_func: impl Fn() -> Result<()>) -> Result<()>255cf48211cSNick Fitzgerald     pub fn test(&self, test_func: impl Fn() -> Result<()>) -> Result<()> {
256*5c68fe60SNick Fitzgerald         let future = self.test_async(|| async { test_func() });
257*5c68fe60SNick Fitzgerald         crate::block_on(future)
258*5c68fe60SNick Fitzgerald     }
259*5c68fe60SNick Fitzgerald 
260*5c68fe60SNick Fitzgerald     /// The same as `test` but `async`.
test_async(&self, test_func: impl AsyncFn() -> Result<()>) -> Result<()>261*5c68fe60SNick Fitzgerald     pub async fn test_async(&self, test_func: impl AsyncFn() -> Result<()>) -> Result<()> {
262cf48211cSNick Fitzgerald         let start = time::Instant::now();
263cf48211cSNick Fitzgerald 
264cf48211cSNick Fitzgerald         for i in 0.. {
265cf48211cSNick Fitzgerald             if self.max_iters.is_some_and(|n| i >= n)
266cf48211cSNick Fitzgerald                 || self.max_duration.is_some_and(|d| start.elapsed() >= d)
267cf48211cSNick Fitzgerald             {
268cf48211cSNick Fitzgerald                 break;
269cf48211cSNick Fitzgerald             }
270cf48211cSNick Fitzgerald 
271cf48211cSNick Fitzgerald             log::trace!("=== Injecting OOM after {i} allocations ===");
272*5c68fe60SNick Fitzgerald 
273*5c68fe60SNick Fitzgerald             let future = std::pin::pin!(test_func());
274*5c68fe60SNick Fitzgerald             let (result, oom_state) = OomTestFuture::new(
275*5c68fe60SNick Fitzgerald                 future,
276*5c68fe60SNick Fitzgerald                 OomState::OomOnAlloc {
277755979ddSNick Fitzgerald                     counter: i,
278755979ddSNick Fitzgerald                     allow_alloc_after: self.allow_alloc_after_oom,
279*5c68fe60SNick Fitzgerald                 },
280*5c68fe60SNick Fitzgerald             )
281*5c68fe60SNick Fitzgerald             .await;
282cf48211cSNick Fitzgerald 
283*5c68fe60SNick Fitzgerald             match (result, oom_state) {
284cf48211cSNick Fitzgerald                 (_, OomState::OutsideOomTest) => unreachable!(),
285cf48211cSNick Fitzgerald 
286cf48211cSNick Fitzgerald                 // The test function completed successfully before we ran out of
287cf48211cSNick Fitzgerald                 // allocation fuel, so we're done.
288755979ddSNick Fitzgerald                 (Ok(()), OomState::OomOnAlloc { .. }) => break,
289cf48211cSNick Fitzgerald 
290cf48211cSNick Fitzgerald                 // We injected an OOM and the test function handled it
291cf48211cSNick Fitzgerald                 // correctly; continue to the next iteration.
292*5c68fe60SNick Fitzgerald                 (Err(e), OomState::DidOom { .. }) if e.is::<OutOfMemory>() => {}
293cf48211cSNick Fitzgerald 
294cf48211cSNick Fitzgerald                 // Missed OOMs.
295755979ddSNick Fitzgerald                 (Ok(()), OomState::DidOom { .. }) => {
296cf48211cSNick Fitzgerald                     bail!("OOM test function missed an OOM: returned Ok(())");
297cf48211cSNick Fitzgerald                 }
298755979ddSNick Fitzgerald                 (Err(e), OomState::DidOom { .. }) => {
299cf48211cSNick Fitzgerald                     return Err(
300cf48211cSNick Fitzgerald                         e.context("OOM test function missed an OOM: returned non-OOM error")
301cf48211cSNick Fitzgerald                     );
302cf48211cSNick Fitzgerald                 }
303cf48211cSNick Fitzgerald 
304cf48211cSNick Fitzgerald                 // Unexpected error.
305755979ddSNick Fitzgerald                 (Err(e), OomState::OomOnAlloc { .. }) => {
306cf48211cSNick Fitzgerald                     return Err(
307cf48211cSNick Fitzgerald                         e.context("OOM test function returned an error when there was no OOM")
308cf48211cSNick Fitzgerald                     );
309cf48211cSNick Fitzgerald                 }
310cf48211cSNick Fitzgerald             }
311cf48211cSNick Fitzgerald         }
312cf48211cSNick Fitzgerald 
313cf48211cSNick Fitzgerald         Ok(())
314cf48211cSNick Fitzgerald     }
315*5c68fe60SNick Fitzgerald }
316cf48211cSNick Fitzgerald 
317*5c68fe60SNick Fitzgerald struct OomTestFuture<'a, F> {
318*5c68fe60SNick Fitzgerald     inner: Pin<&'a mut F>,
319*5c68fe60SNick Fitzgerald     state: OomState,
320*5c68fe60SNick Fitzgerald }
321*5c68fe60SNick Fitzgerald 
322*5c68fe60SNick Fitzgerald impl<'a, F> OomTestFuture<'a, F> {
new(inner: Pin<&'a mut F>, state: OomState) -> Self323*5c68fe60SNick Fitzgerald     fn new(inner: Pin<&'a mut F>, state: OomState) -> Self {
324*5c68fe60SNick Fitzgerald         OomTestFuture { inner, state }
325*5c68fe60SNick Fitzgerald     }
326*5c68fe60SNick Fitzgerald }
327*5c68fe60SNick Fitzgerald 
328*5c68fe60SNick Fitzgerald impl<F> Future for OomTestFuture<'_, F>
329*5c68fe60SNick Fitzgerald where
330*5c68fe60SNick Fitzgerald     F: Future<Output = Result<()>>,
331*5c68fe60SNick Fitzgerald {
332*5c68fe60SNick Fitzgerald     type Output = (Result<()>, OomState);
333*5c68fe60SNick Fitzgerald 
poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>334*5c68fe60SNick Fitzgerald     fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
335*5c68fe60SNick Fitzgerald         log::trace!("OomTestFuture::poll: Entered ---");
336*5c68fe60SNick Fitzgerald 
337*5c68fe60SNick Fitzgerald         let result = {
338*5c68fe60SNick Fitzgerald             let OomTestFuture { inner, state } = &mut *self;
339*5c68fe60SNick Fitzgerald 
340*5c68fe60SNick Fitzgerald             let guard = ScopedOomState::new(state);
341*5c68fe60SNick Fitzgerald             assert_eq!(*guard.state, OomState::OutsideOomTest);
342*5c68fe60SNick Fitzgerald 
343*5c68fe60SNick Fitzgerald             inner.as_mut().poll(cx)
344*5c68fe60SNick Fitzgerald         };
345*5c68fe60SNick Fitzgerald 
346*5c68fe60SNick Fitzgerald         log::trace!("OomTestFuture::poll: inner result: {result:?}");
347*5c68fe60SNick Fitzgerald         log::trace!("OomTestFuture::poll: old state: {:?}", self.state);
348*5c68fe60SNick Fitzgerald 
349*5c68fe60SNick Fitzgerald         match result {
350*5c68fe60SNick Fitzgerald             Poll::Pending => {
351*5c68fe60SNick Fitzgerald                 set_oom_state(OomState::OutsideOomTest);
352*5c68fe60SNick Fitzgerald                 Poll::Pending
353*5c68fe60SNick Fitzgerald             }
354*5c68fe60SNick Fitzgerald             Poll::Ready(result) => Poll::Ready((result, mem::take(&mut self.state))),
355*5c68fe60SNick Fitzgerald         }
356cf48211cSNick Fitzgerald     }
357cf48211cSNick Fitzgerald }
358