Skip to main content

static_alloc/
leaked.rs

1//! This module contains an owning wrapper of a leaked struct.
2//!
3//! FIXME(breaking): Naming. `leaking` implies the `Drop` of the value as well but we do the
4//! precise opposite.
5use alloc_traits::AllocTime;
6use core::pin::Pin;
7
8use core::{
9    alloc::Layout,
10    fmt, hash,
11    marker::PhantomData,
12    mem::{ManuallyDrop, MaybeUninit},
13    ops::{Deref, DerefMut},
14    ptr::{self, NonNull},
15};
16
17/// Zero-sized marker struct that allows running one or several methods.
18///
19/// This ensures that allocation does not exceed certain limits that would likely blow the stack
20/// and run into Rust's canary, this aborting the process.
21pub struct Alloca<T> {
22    marker: PhantomData<[T]>,
23    len: usize,
24}
25
26impl<T> Alloca<T> {
27    /// Try to create a representation, that allows functions with dynamically stack-allocated
28    /// slices.
29    pub fn new(len: usize) -> Option<Self> {
30        // Check that it's okay to create the padded layout. This is pure so it will again work
31        // when we try during `run`.
32        let _padded_layout = Layout::array::<T>(len + 1).ok()?;
33        Some(Alloca {
34            marker: PhantomData,
35            len,
36        })
37    }
38
39    fn padded_layout(&self) -> Layout {
40        Layout::array::<T>(self.len + 1).expect("Checked this in the constructor")
41    }
42
43    /// Allocate a slice of elements.
44    ///
45    /// Please note that instantiating this method relies on the optimizer, to an extent. In
46    /// particular we will create stack slots of differing sizes depending on the internal size.
47    /// This shouldn't have an effect other than moving the stack pointer for various amounts and
48    /// should never have more than one `T` in overhead. However, we can't enforce this. In theory
49    /// llvm might still reserve stack space for all variants including a probe and thus
50    /// prematurely assume we have hit the bottom of the available stack space. This is not very
51    /// likely to occur in practice.
52    pub fn run<R>(&self, run: impl FnOnce(&mut [MaybeUninit<T>]) -> R) -> R {
53        // Required size to surely have enough space for an aligned allocation.
54        let required_size = self.padded_layout().size();
55
56        if required_size <= 8 {
57            self.run_with::<[u64; 1], _, _>(run)
58        } else if required_size <= 16 {
59            self.run_with::<[u64; 2], _, _>(run)
60        } else if required_size <= 32 {
61            self.run_with::<[u64; 4], _, _>(run)
62        } else if required_size <= 64 {
63            self.run_with::<[u64; 8], _, _>(run)
64        } else if required_size <= 128 {
65            self.run_with::<[u64; 16], _, _>(run)
66        } else if required_size <= 256 {
67            self.run_with::<[u64; 32], _, _>(run)
68        } else if required_size <= 512 {
69            self.run_with::<[u64; 64], _, _>(run)
70        } else if required_size <= 1024 {
71            self.run_with::<[u64; 128], _, _>(run)
72        } else if required_size <= 2048 {
73            self.run_with::<[u64; 256], _, _>(run)
74        } else if required_size <= (1 << 12) {
75            self.run_with::<[u64; 512], _, _>(run)
76        } else if required_size <= (1 << 13) {
77            self.run_with::<[u64; 1 << 10], _, _>(run)
78        } else if required_size <= (1 << 14) {
79            self.run_with::<[u64; 1 << 11], _, _>(run)
80        } else if required_size <= (1 << 15) {
81            self.run_with::<[u64; 1 << 12], _, _>(run)
82        } else if required_size <= (1 << 16) {
83            self.run_with::<[u64; 1 << 13], _, _>(run)
84        } else if required_size <= (1 << 17) {
85            self.run_with::<[u64; 1 << 14], _, _>(run)
86        } else if required_size <= (1 << 18) {
87            self.run_with::<[u64; 1 << 15], _, _>(run)
88        } else if required_size <= (1 << 19) {
89            self.run_with::<[u64; 1 << 16], _, _>(run)
90        } else if required_size <= (1 << 20) {
91            self.run_with::<[u64; 1 << 17], _, _>(run)
92        } else {
93            panic!("Stack allocation is too big");
94        }
95    }
96
97    fn run_with<I, R, F: FnOnce(&mut [MaybeUninit<T>]) -> R>(&self, run: F) -> R {
98        use crate::unsync::Bump;
99        let mem = Bump::<I>::uninit();
100        let slot = mem.bump_array::<T>(self.len).unwrap();
101        run(LeakBox::leak(slot))
102    }
103}
104
105/// Represents an allocation within a Bump.
106///
107/// This is an owning pointer comparable to `Box`. It drops the contained value when it is dropped
108/// itself. The difference is that no deallocation logic is ever executed.
109///
110/// FIXME(non-breaking): the name is rather confusing. Maybe it should be `BumpBox` or `RefBox`?
111/// Not `StackBox` because the value's location in memory is not the defining feature.
112///
113/// # Usage
114///
115/// This box can be used to manage one valid instance constructed within the memory provided by a
116/// `MaybeUninit` instance.
117///
118/// ```
119/// use core::mem::MaybeUninit;
120/// use static_alloc::leaked::LeakBox;
121///
122/// let mut storage = MaybeUninit::uninit();
123/// let leak_box = LeakBox::from(&mut storage);
124/// // The string itself is not managed by `static_alloc`.
125/// let mut instance = LeakBox::write(leak_box, String::new());
126///
127/// instance.push_str("Hello world!");
128/// ```
129///
130/// This box is the result of allocating from one of the `Bump` allocators using its explicit API.
131///
132/// Being a box-like type, an `Option` has the same size.
133///
134/// ```
135/// use core::mem::size_of;
136/// use static_alloc::leaked::LeakBox;
137///
138/// type Boxed = LeakBox<'static, usize>;
139/// type Optional = Option<Boxed>;
140///
141/// assert_eq!(size_of::<Boxed>(), size_of::<Optional>());
142/// ```
143///
144/// TODO: On nightly the inner type should be [unsizable][unsize-coercion].
145///
146/// [unsize-coercion]: https://doc.rust-lang.org/reference/type-coercions.html#coercion-types
147pub struct LeakBox<'ctx, T: ?Sized> {
148    #[allow(unused)]
149    lifetime: AllocTime<'ctx>,
150    // Covariance should be OK.
151    pointer: NonNull<T>,
152}
153
154impl<'ctx, T> LeakBox<'ctx, T> {
155    /// Construct from a raw pointer.
156    ///
157    /// # Safety
158    ///
159    /// The allocation must be valid for a write of the value. The memory must also outlive the
160    /// lifetime `'ctx` and pointer must not be aliased by any other reference for that scope.
161    pub(crate) unsafe fn new_from_raw_non_null(
162        pointer: NonNull<T>,
163        val: T,
164        lifetime: AllocTime<'ctx>,
165    ) -> Self {
166        // SAFETY:
167        // * `ptr` points to an allocation with correct layout for `V`.
168        // * It is valid for write as it is the only pointer to it.
169        // * The allocation lives for at least `'ctx`.
170        unsafe { core::ptr::write(pointer.as_ptr(), val) };
171        Self { pointer, lifetime }
172    }
173}
174
175impl<'ctx, T: ?Sized> LeakBox<'ctx, T> {
176    /// Retrieve the raw pointer wrapped by this box.
177    ///
178    /// After this method the caller is responsible for managing the value in the place behind the
179    /// pointer. It will need to be dropped manually.
180    ///
181    /// # Usage
182    ///
183    /// You might manually drop the contained instance at a later point.
184    ///
185    /// ```
186    /// use static_alloc::{Bump, leaked::LeakBox};
187    ///
188    /// # fn fake() -> Option<()> {
189    /// let bump: Bump<[usize; 128]> = Bump::uninit();
190    /// let leak_box = bump.leak_box(String::from("Hello"))?;
191    /// let ptr = LeakBox::into_raw(leak_box);
192    ///
193    /// unsafe {
194    ///     core::ptr::drop_in_place(ptr);
195    /// }
196    /// # Some(()) }
197    /// ```
198    ///
199    /// An alternative is to later re-wrap the pointer
200    ///
201    /// ```
202    /// use static_alloc::{Bump, leaked::LeakBox};
203    ///
204    /// # fn fake() -> Option<()> {
205    /// let bump: Bump<[usize; 128]> = Bump::uninit();
206    /// let leak_box = bump.leak_box(String::from("Hello"))?;
207    /// let ptr = LeakBox::into_raw(leak_box);
208    ///
209    /// unsafe {
210    ///     let _ = LeakBox::from_raw(ptr);
211    /// };
212    /// # Some(()) }
213    /// ```
214    pub fn into_raw(this: Self) -> *mut T {
215        let this = ManuallyDrop::new(this);
216        this.pointer.as_ptr()
217    }
218
219    /// Wrap a raw pointer.
220    ///
221    /// The most immediate use is to rewrap a pointer returned from [`into_raw`].
222    ///
223    /// [`into_raw`]: #method.into_raw
224    ///
225    /// # Safety
226    ///
227    /// The pointer must point to a valid instance of `T` that is not aliased by any other
228    /// reference for the lifetime `'ctx`. In particular it must be valid aligned and initialized.
229    /// Dropping this `LeakBox` will drop the instance, which the caller must also guarantee to be
230    /// sound.
231    pub unsafe fn from_raw(pointer: *mut T) -> Self {
232        debug_assert!(
233            !pointer.is_null(),
234            "Null pointer passed to LeakBox::from_raw"
235        );
236
237        LeakBox {
238            lifetime: AllocTime::default(),
239            // Safety: caller guarantees this points to a valid instance. Null never does that.
240            pointer: unsafe { NonNull::new_unchecked(pointer) },
241        }
242    }
243
244    /// Wrap a mutable reference to a complex value as if it were owned.
245    ///
246    /// # Safety
247    ///
248    /// The value must be owned by the caller. That is, the mutable reference must not be used
249    /// after the `LeakBox` is dropped. In particular the value must not be dropped by the caller.
250    ///
251    /// # Example
252    ///
253    /// ```rust
254    /// use core::mem::ManuallyDrop;
255    /// use static_alloc::leaked::LeakBox;
256    ///
257    /// fn with_stack_drop<T>(val: T) {
258    ///     let mut val = ManuallyDrop::new(val);
259    ///     // Safety:
260    ///     // - Shadows the variable, rendering the prior inaccessible.
261    ///     // - Dropping is now the responsibility of `LeakBox`.
262    ///     let val = unsafe { LeakBox::from_mut_unchecked(&mut *val) };
263    /// }
264    ///
265    /// // Demonstrate that it is correctly dropped.
266    /// let variable = core::cell::RefCell::new(0);
267    /// with_stack_drop(variable.borrow_mut());
268    /// assert!(variable.try_borrow_mut().is_ok());
269    /// ```
270    #[allow(unused_unsafe)]
271    pub unsafe fn from_mut_unchecked(val: &'ctx mut T) -> Self {
272        // SAFETY:
273        // * Is valid instance
274        // * Not aliased as by mut reference
275        // * Dropping soundness is guaranteed by the caller.
276        // * We don't invalidate any value, nor can the caller.
277        unsafe { LeakBox::from_raw(val) }
278    }
279
280    /// Leak the instances as a mutable reference.
281    ///
282    /// After calling this method the value is no longer managed by `LeakBox`. Its Drop impl will
283    /// not be automatically called.
284    ///
285    /// # Usage
286    ///
287    /// ```
288    /// use static_alloc::{Bump, leaked::LeakBox};
289    ///
290    /// # fn fake() -> Option<()> {
291    /// let bump: Bump<[usize; 128]> = Bump::uninit();
292    /// let leak_box = bump.leak_box(String::from("Hello"))?;
293    ///
294    /// let st: &mut String = LeakBox::leak(leak_box);
295    /// # Some(()) }
296    /// ```
297    ///
298    /// You can't leak past the lifetime of the allocator.
299    ///
300    /// ```compile_fail
301    /// # use static_alloc::{Bump, leaked::LeakBox};
302    /// # fn fake() -> Option<()> {
303    /// let bump: Bump<[usize; 128]> = Bump::uninit();
304    /// let leak_box = bump.leak_box(String::from("Hello"))?;
305    /// let st: &mut String = LeakBox::leak(leak_box);
306    ///
307    /// drop(bump);
308    /// // error[E0505]: cannot move out of `bump` because it is borrowed
309    /// st.to_lowercase();
310    /// //-- borrow later used here
311    /// # Some(()) }
312    /// ```
313    pub fn leak<'a>(this: Self) -> &'a mut T
314    where
315        'ctx: 'a,
316    {
317        let pointer = LeakBox::into_raw(this);
318        // SAFETY:
319        // * The LeakBox type guarantees this is initialized and not mutably aliased.
320        // * For the lifetime 'a which is at most 'ctx.
321        unsafe { &mut *pointer }
322    }
323}
324
325impl<T: 'static> LeakBox<'static, T> {
326    /// Pin an instance that's leaked for the remaining program runtime.
327    ///
328    /// After calling this method the value can only safely be referenced mutably if it is `Unpin`,
329    /// otherwise it is only accessible behind a `Pin`. Note that this does _not_ imply that the
330    /// `Drop` glue, or explicit `Drop`-impl, is guaranteed to run.
331    ///
332    /// # Usage
333    ///
334    /// A decent portion of futures must be _pinned_ before the can be awaited inside another
335    /// future. In particular this is required for self-referential futures that store pointers
336    /// into their own object's memory. This is the case for the future type of an `asnyc fn` if
337    /// there are potentially any stack references when it is suspended/waiting on another future.
338    /// Consider this example:
339    ///
340    /// ```compile_fail
341    /// use static_alloc::{Bump, leaked::LeakBox};
342    ///
343    /// async fn example(x: usize) -> usize {
344    ///     // Holding reference across yield point.
345    ///     // This requires pinning to run this future.
346    ///     let y = &x;
347    ///     core::future::ready(()).await;
348    ///     *y
349    /// }
350    ///
351    /// static POOL: Bump<[usize; 128]> = Bump::uninit();
352    /// let mut future = POOL.leak_box(example(0))
353    ///     .expect("Enough space for small async fn");
354    ///
355    /// let usage = async move {
356    /// // error[E0277]: `GenFuture<[static generator@src/leaked.rs …]>` cannot be unpinned
357    ///     let _ = (&mut *future).await;
358    /// };
359    /// ```
360    ///
361    /// This method can be used to pin instances allocated from a global pool without requiring the
362    /// use of a macro or unsafe on the caller's part. Now, with the correct usage of `into_pin`:
363    ///
364    /// ```
365    /// use static_alloc::{Bump, leaked::LeakBox};
366    ///
367    /// async fn example(x: usize) -> usize {
368    ///     // Holding reference across yield point.
369    ///     // This requires pinning to run this future.
370    ///     let y = &x;
371    ///     core::future::ready(()).await;
372    ///     *y
373    /// }
374    ///
375    /// static POOL: Bump<[usize; 128]> = Bump::uninit();
376    /// let future = POOL.leak_box(example(0))
377    ///     .expect("Enough space for small async fn");
378    ///
379    /// // PIN this future!
380    /// let mut future = LeakBox::into_pin(future);
381    ///
382    /// let usage = async move {
383    ///     let _ = future.as_mut().await;
384    /// };
385    /// ```
386    pub fn into_pin(this: Self) -> Pin<Self> {
387        // SAFETY:
388        // * This memory is valid for `'static` duration, independent of the fate of `this` and
389        //   even when it is forgotten. This trivially implies that any Drop is called before the
390        //   memory is invalidated, as required by `Pin`.
391        unsafe { Pin::new_unchecked(this) }
392    }
393}
394
395impl<'ctx, T> LeakBox<'ctx, T> {
396    /// Remove the value, forgetting the box in the process.
397    ///
398    /// This is similar to dereferencing a box (`*leak_box`) but no deallocation is involved. This
399    /// becomes useful when the allocator turns out to have too short of a lifetime.
400    ///
401    /// # Usage
402    ///
403    /// You may want to move a long-lived value out of the current scope where it's been allocated.
404    ///
405    /// ```
406    /// # use core::cell::RefCell;
407    /// use static_alloc::{Bump, leaked::LeakBox};
408    ///
409    /// let cell = RefCell::new(0usize);
410    ///
411    /// let guard = {
412    ///     let bump: Bump<[usize; 128]> = Bump::uninit();
413    ///
414    ///     let mut leaked = bump.leak_box(cell.borrow_mut()).unwrap();
415    ///     **leaked = 1usize;
416    ///
417    ///     // Take the value, allowing use independent of the lifetime of bump
418    ///     LeakBox::take(leaked)
419    /// };
420    ///
421    /// assert!(cell.try_borrow().is_err());
422    /// drop(guard);
423    /// assert!(cell.try_borrow().is_ok());
424    /// ```
425    pub fn take(this: Self) -> T {
426        // Do not drop this.
427        let this = ManuallyDrop::new(this);
428        // SAFETY:
429        // * `ptr` points to an initialized allocation according to the constructors of `LeakBox`.
430        // * The old value is forgotten and no longer dropped.
431        unsafe { core::ptr::read(this.pointer.as_ptr()) }
432    }
433
434    /// Wrap a mutable reference to a trivial value as if it were a box.
435    ///
436    /// This is safe because such values can not have any Drop code and can be duplicated at will.
437    ///
438    /// The usefulness of this operation is questionable but the author would be delighted to hear
439    /// about any actual use case.
440    pub fn from_mut(val: &'ctx mut T) -> Self
441    where
442        T: Copy,
443    {
444        // SAFETY:
445        // * Is valid instance
446        // * Not aliased as by mut reference
447        // * Dropping is a no-op
448        // * We don't invalidate anyones value
449        unsafe { LeakBox::from_raw(val) }
450    }
451}
452
453impl<'ctx, T> LeakBox<'ctx, MaybeUninit<T>> {
454    /// Write a value into this box, initializing it.
455    ///
456    /// This can be used to delay the computation of a value until after an allocation succeeded
457    /// while maintaining all types necessary for a safe initialization.
458    ///
459    /// # Usage
460    ///
461    /// ```
462    /// # fn some_expensive_operation() -> [u8; 4] { [0u8; 4] }
463    /// # use core::mem::MaybeUninit;
464    /// #
465    /// # fn fake_main() -> Option<()> {
466    /// #
467    /// use static_alloc::{Bump, leaked::LeakBox};
468    ///
469    /// let bump: Bump<[usize; 128]> = Bump::uninit();
470    /// let memory = bump.leak_box(MaybeUninit::uninit())?;
471    ///
472    /// let value = LeakBox::write(memory, some_expensive_operation());
473    /// # Some(()) } fn main() {}
474    /// ```
475    pub fn write(mut this: Self, val: T) -> LeakBox<'ctx, T> {
476        unsafe {
477            // SAFETY: MaybeUninit<T> is valid for writing a T.
478            ptr::write(this.as_mut_ptr(), val);
479            // SAFETY: initialized by the write before.
480            LeakBox::assume_init(this)
481        }
482    }
483
484    /// Converts to `LeakBox<T>`.
485    ///
486    /// # Safety
487    ///
488    /// The value must have been initialized as required by `MaybeUninit::assume_init`. Calling
489    /// this when the content is not yet fully initialized causes immediate undefined behavior.
490    pub unsafe fn assume_init(this: Self) -> LeakBox<'ctx, T> {
491        LeakBox {
492            pointer: this.pointer.cast(),
493            lifetime: this.lifetime,
494        }
495    }
496}
497
498impl<'ctx, T: ?Sized> Deref for LeakBox<'ctx, T> {
499    type Target = T;
500
501    fn deref(&self) -> &Self::Target {
502        // SAFETY: constructor guarantees this is initialized and not mutably aliased.
503        unsafe { self.pointer.as_ref() }
504    }
505}
506
507impl<'ctx, T: ?Sized> DerefMut for LeakBox<'ctx, T> {
508    fn deref_mut(&mut self) -> &mut Self::Target {
509        // SAFETY: constructor guarantees this is initialized and not aliased.
510        unsafe { self.pointer.as_mut() }
511    }
512}
513
514impl<T: ?Sized> Drop for LeakBox<'_, T> {
515    fn drop(&mut self) {
516        // SAFETY: constructor guarantees this was initialized.
517        unsafe { ptr::drop_in_place(self.pointer.as_ptr()) }
518    }
519}
520
521/// Construct a LeakBox to an existing MaybeUninit.
522///
523/// The MaybeUninit type is special in that we can treat any unique reference to an owned value as
524/// an owned value itself since it has no representational invariants.
525impl<'ctx, T> From<&'ctx mut MaybeUninit<T>> for LeakBox<'ctx, MaybeUninit<T>> {
526    fn from(uninit: &'ctx mut MaybeUninit<T>) -> Self {
527        // SAFETY:
528        // * An instance of MaybeUninit is always valid.
529        // * The mut references means it can not be aliased.
530        // * Dropping a MaybeUninit is a no-op and can not invalidate any validity or security
531        //   invariants of this MaybeUninit or the contained T.
532        unsafe { LeakBox::from_raw(uninit) }
533    }
534}
535
536/// Construct a LeakBox to an existing slice of MaybeUninit.
537impl<'ctx, T> From<&'ctx mut [MaybeUninit<T>]> for LeakBox<'ctx, [MaybeUninit<T>]> {
538    fn from(uninit: &'ctx mut [MaybeUninit<T>]) -> Self {
539        // SAFETY:
540        // * An instance of MaybeUninit is always valid.
541        // * The mut references means it can not be aliased.
542        // * Dropping a MaybeUninit is a no-op and can not invalidate any validity or security
543        //   invariants of this MaybeUninit or the contained T.
544        unsafe { LeakBox::from_raw(uninit) }
545    }
546}
547
548impl<T: ?Sized> AsRef<T> for LeakBox<'_, T> {
549    fn as_ref(&self) -> &T {
550        self
551    }
552}
553
554impl<T: ?Sized> AsMut<T> for LeakBox<'_, T> {
555    fn as_mut(&mut self) -> &mut T {
556        self
557    }
558}
559
560impl<T: fmt::Debug + ?Sized> fmt::Debug for LeakBox<'_, T> {
561    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
562        self.as_ref().fmt(f)
563    }
564}
565
566impl<T: fmt::Display + ?Sized> fmt::Display for LeakBox<'_, T> {
567    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
568        self.as_ref().fmt(f)
569    }
570}
571
572impl<T: ?Sized> fmt::Pointer for LeakBox<'_, T> {
573    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
574        self.pointer.fmt(f)
575    }
576}
577
578impl<T: hash::Hash + ?Sized> hash::Hash for LeakBox<'_, T> {
579    fn hash<H: hash::Hasher>(&self, h: &mut H) {
580        self.as_ref().hash(h)
581    }
582}
583
584// TODO: iterators, read, write?