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?