Skip to content

Commit 5cfd1d6

Browse files
committed
move fatal alloc error handling to alloc
1 parent 5fb1362 commit 5cfd1d6

File tree

5 files changed

+204
-198
lines changed

5 files changed

+204
-198
lines changed

library/alloc/src/alloc.rs

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,196 @@ impl<T: Copy> WriteCloneIntoRaw for T {
449449
}
450450
}
451451

452+
#[cfg(all(not(no_global_oom_handling), not(test)))]
453+
use core::error::Error;
454+
455+
/// Trait for handling alloc errors for allocators which
456+
/// panic or abort instead of returning errors.
457+
#[unstable(feature = "allocator_api", issue = "32838")]
458+
#[cfg(all(not(no_global_oom_handling), not(test)))]
459+
#[rustc_specialization_trait]
460+
pub trait HandleAllocError: Error {
461+
/// Globally handle this allocation error
462+
fn handle_alloc_error(self) -> !;
463+
}
464+
465+
/// Error handling mode to use when the user of the type wants to ignore
466+
/// allocation failures, treating them as a fatal error. Functions
467+
/// performing allocation will return values directly.
468+
#[derive(Debug)]
469+
#[unstable(feature = "allocator_api", issue = "32838")]
470+
#[cfg(all(not(no_global_oom_handling), not(test)))]
471+
pub struct Fatal;
472+
473+
#[unstable(feature = "alloc_internals", issue = "none")]
474+
#[cfg(all(not(no_global_oom_handling), not(test)))]
475+
impl error_handling_sealed::Sealed for Fatal {}
476+
477+
#[unstable(feature = "allocator_api", issue = "32838")]
478+
#[cfg(all(not(no_global_oom_handling), not(test)))]
479+
impl ErrorHandling for Fatal {
480+
type Result<T, E: Error> = T;
481+
482+
fn map_result<T, E: Error>(result: Result<T, E>) -> Self::Result<T, E> {
483+
/// Hack around lack of `cfg(no_global_oom_handling)` in core.
484+
///
485+
/// Using post-monomorphization errors and specialization,
486+
/// we can enforce that any error used with `Fatal` implements
487+
/// `HandleAllocError`, without requiring that all errors used
488+
/// with fallible allocation implement it. This also allows
489+
/// for `HandleAllocError` to live with the rest of the
490+
/// global allocation handling in the `alloc` crate.
491+
trait HandleAllocErrorInternal {
492+
fn handle_alloc_error_internal(self) -> !;
493+
}
494+
impl<E: Error> HandleAllocErrorInternal for E {
495+
default fn handle_alloc_error_internal(self) -> ! {
496+
const {
497+
panic!(
498+
"user must implement `HandleAllocError` for any error type used with the `Fatal` kind of `ErrorHandling`"
499+
)
500+
}
501+
}
502+
}
503+
impl<E: HandleAllocError> HandleAllocErrorInternal for E {
504+
fn handle_alloc_error_internal(self) -> ! {
505+
self.handle_alloc_error()
506+
}
507+
}
508+
509+
result.unwrap_or_else(|e| e.handle_alloc_error_internal())
510+
}
511+
}
512+
513+
/// Wrapper around an existing allocator allowing one to
514+
/// use a fallible allocator as an infallible one.
515+
#[unstable(feature = "allocator_api", issue = "32838")]
516+
#[cfg(all(not(no_global_oom_handling), not(test)))]
517+
#[derive(Debug)]
518+
pub struct FatalAdapter<A: Allocator<ErrorHandling = Fallible>>(pub A);
519+
520+
#[unstable(feature = "allocator_api", issue = "32838")]
521+
#[cfg(all(not(no_global_oom_handling), not(test)))]
522+
unsafe impl<A: Allocator<ErrorHandling = Fallible>> Allocator for FatalAdapter<A> {
523+
fn allocate(&self, layout: Layout) -> Result<core::ptr::NonNull<[u8]>, AllocError> {
524+
self.0.allocate(layout)
525+
}
526+
527+
fn allocate_zeroed(&self, layout: Layout) -> Result<core::ptr::NonNull<[u8]>, AllocError> {
528+
self.0.allocate_zeroed(layout)
529+
}
530+
531+
unsafe fn deallocate(&self, ptr: core::ptr::NonNull<u8>, layout: Layout) {
532+
// SAFETY: the safety contract must be upheld by the caller
533+
unsafe { self.0.deallocate(ptr, layout) }
534+
}
535+
536+
unsafe fn grow(
537+
&self,
538+
ptr: core::ptr::NonNull<u8>,
539+
old_layout: Layout,
540+
new_layout: Layout,
541+
) -> Result<core::ptr::NonNull<[u8]>, AllocError> {
542+
// SAFETY: the safety contract must be upheld by the caller
543+
unsafe { self.0.grow(ptr, old_layout, new_layout) }
544+
}
545+
546+
unsafe fn grow_zeroed(
547+
&self,
548+
ptr: core::ptr::NonNull<u8>,
549+
old_layout: Layout,
550+
new_layout: Layout,
551+
) -> Result<core::ptr::NonNull<[u8]>, AllocError> {
552+
// SAFETY: the safety contract must be upheld by the caller
553+
unsafe { self.0.grow_zeroed(ptr, old_layout, new_layout) }
554+
}
555+
556+
unsafe fn shrink(
557+
&self,
558+
ptr: core::ptr::NonNull<u8>,
559+
old_layout: Layout,
560+
new_layout: Layout,
561+
) -> Result<core::ptr::NonNull<[u8]>, AllocError> {
562+
// SAFETY: the safety contract must be upheld by the caller
563+
unsafe { self.0.shrink(ptr, old_layout, new_layout) }
564+
}
565+
566+
fn by_ref(&self) -> &Self
567+
where
568+
Self: Sized,
569+
{
570+
self
571+
}
572+
573+
type ErrorHandling = Fatal;
574+
}
575+
576+
/// Wrapper around an existing allocator allowing one to
577+
/// use an infallible allocator as a fallible one.
578+
#[unstable(feature = "allocator_api", issue = "32838")]
579+
#[cfg(all(not(no_global_oom_handling), not(test)))]
580+
#[derive(Debug)]
581+
pub struct FallibleAdapter<A: Allocator<ErrorHandling = Fatal>>(pub A);
582+
583+
#[unstable(feature = "allocator_api", issue = "32838")]
584+
#[cfg(all(not(no_global_oom_handling), not(test)))]
585+
unsafe impl<A: Allocator<ErrorHandling = Fatal>> Allocator for FallibleAdapter<A> {
586+
fn allocate(&self, layout: Layout) -> Result<core::ptr::NonNull<[u8]>, AllocError> {
587+
self.0.allocate(layout)
588+
}
589+
590+
fn allocate_zeroed(&self, layout: Layout) -> Result<core::ptr::NonNull<[u8]>, AllocError> {
591+
self.0.allocate_zeroed(layout)
592+
}
593+
594+
unsafe fn deallocate(&self, ptr: core::ptr::NonNull<u8>, layout: Layout) {
595+
// SAFETY: the safety contract must be upheld by the caller
596+
unsafe { self.0.deallocate(ptr, layout) }
597+
}
598+
599+
unsafe fn grow(
600+
&self,
601+
ptr: core::ptr::NonNull<u8>,
602+
old_layout: Layout,
603+
new_layout: Layout,
604+
) -> Result<core::ptr::NonNull<[u8]>, AllocError> {
605+
// SAFETY: the safety contract must be upheld by the caller
606+
unsafe { self.0.grow(ptr, old_layout, new_layout) }
607+
}
608+
609+
unsafe fn grow_zeroed(
610+
&self,
611+
ptr: core::ptr::NonNull<u8>,
612+
old_layout: Layout,
613+
new_layout: Layout,
614+
) -> Result<core::ptr::NonNull<[u8]>, AllocError> {
615+
// SAFETY: the safety contract must be upheld by the caller
616+
unsafe { self.0.grow_zeroed(ptr, old_layout, new_layout) }
617+
}
618+
619+
unsafe fn shrink(
620+
&self,
621+
ptr: core::ptr::NonNull<u8>,
622+
old_layout: Layout,
623+
new_layout: Layout,
624+
) -> Result<core::ptr::NonNull<[u8]>, AllocError> {
625+
// SAFETY: the safety contract must be upheld by the caller
626+
unsafe { self.0.shrink(ptr, old_layout, new_layout) }
627+
}
628+
629+
fn by_ref(&self) -> &Self
630+
where
631+
Self: Sized,
632+
{
633+
self
634+
}
635+
636+
type ErrorHandling = Fallible;
637+
}
638+
639+
#[cfg(test)]
640+
pub use std::alloc::{FallibleAdapter, Fatal, FatalAdapter, HandleAllocError};
641+
452642
#[cfg(not(no_global_oom_handling))]
453643
use crate::collections::{TryReserveError, TryReserveErrorKind};
454644

library/alloc/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@
9595
#![cfg_attr(not(no_global_oom_handling), feature(const_btree_len))]
9696
#![cfg_attr(test, feature(is_sorted))]
9797
#![cfg_attr(test, feature(new_uninit))]
98+
#![feature(alloc_internals)]
9899
#![feature(alloc_layout_extra)]
99100
#![feature(allocator_api)]
100101
#![feature(array_chunks)]
@@ -115,6 +116,7 @@
115116
#![feature(const_pin)]
116117
#![feature(const_refs_to_cell)]
117118
#![feature(const_size_of_val)]
119+
#![feature(const_type_name)]
118120
#![feature(const_waker)]
119121
#![feature(core_intrinsics)]
120122
#![feature(core_panic)]

library/alloc/tests/boxed.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use core::alloc::{AllocError, Allocator, Layout, Fatal};
1+
use alloc::alloc::{AllocError, Allocator, Layout, Fatal};
22
use core::cell::Cell;
33
use core::mem::MaybeUninit;
44
use core::ptr::NonNull;

0 commit comments

Comments
 (0)