From 036fb6197a93120aa1ebf70603484e55a99702ad Mon Sep 17 00:00:00 2001 From: Cameron Clark Date: Wed, 17 Dec 2025 22:19:11 +0000 Subject: [PATCH 1/2] refactor(allocator/fixed-size)!: return Result from allocation instead of panicking --- crates/oxc_allocator/src/pool/fixed_size.rs | 38 ++++++++++++++++----- crates/oxc_allocator/src/pool/mod.rs | 3 +- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/crates/oxc_allocator/src/pool/fixed_size.rs b/crates/oxc_allocator/src/pool/fixed_size.rs index 0d6be9f9cc773..766f3a5a86ace 100644 --- a/crates/oxc_allocator/src/pool/fixed_size.rs +++ b/crates/oxc_allocator/src/pool/fixed_size.rs @@ -1,5 +1,7 @@ use std::{ - alloc::{self, GlobalAlloc, Layout, System}, + alloc::{GlobalAlloc, Layout, System}, + error::Error, + fmt, mem::{self, ManuallyDrop}, ptr::NonNull, sync::{ @@ -15,6 +17,26 @@ use crate::{ generated::fixed_size_constants::{BLOCK_ALIGN, BLOCK_SIZE, RAW_METADATA_SIZE}, }; +/// Error returned when a fixed-size allocator cannot be created due to allocation failure. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct AllocError { + /// The layout of the allocation that failed. + pub layout: Layout, +} + +impl fmt::Display for AllocError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "memory allocation failed for fixed-size allocator: requested {} bytes with {} byte alignment", + self.layout.size(), + self.layout.align() + ) + } +} + +impl Error for AllocError {} + const TWO_GIB: usize = 1 << 31; const FOUR_GIB: usize = 1 << 32; @@ -53,7 +75,7 @@ impl FixedSizeAllocatorPool { // Protect against IDs wrapping around. // TODO: Does this work? Do we need it anyway? assert!(id < u32::MAX, "Created too many allocators"); - FixedSizeAllocator::new(id) + FixedSizeAllocator::try_new(id).unwrap() }); // Unwrap `FixedSizeAllocator`. @@ -187,9 +209,11 @@ struct FixedSizeAllocator { } impl FixedSizeAllocator { - /// Create a new [`FixedSizeAllocator`]. + /// Try to create a new [`FixedSizeAllocator`]. + /// + /// Returns `Err(AllocError)` if memory allocation fails. #[expect(clippy::items_after_statements)] - fn new(id: u32) -> Self { + fn try_new(id: u32) -> Result { // Only support little-endian systems. `Allocator::from_raw_parts` includes this same assertion. // This module is only compiled on 64-bit little-endian systems, so it should be impossible for // this panic to occur. But we want to make absolutely sure that if there's a mistake elsewhere, @@ -203,9 +227,7 @@ impl FixedSizeAllocator { // Allocate block of memory. // SAFETY: `ALLOC_LAYOUT` does not have zero size. let alloc_ptr = unsafe { System.alloc(ALLOC_LAYOUT) }; - let Some(alloc_ptr) = NonNull::new(alloc_ptr) else { - alloc::handle_alloc_error(ALLOC_LAYOUT); - }; + let alloc_ptr = NonNull::new(alloc_ptr).ok_or(AllocError { layout: ALLOC_LAYOUT })?; // All code in the rest of this function is infallible, so the allocation will always end up // owned by a `FixedSizeAllocator`, which takes care of freeing the memory correctly on drop @@ -254,7 +276,7 @@ impl FixedSizeAllocator { metadata_ptr.write(metadata); } - Self { allocator } + Ok(Self { allocator }) } /// Reset this [`FixedSizeAllocator`]. diff --git a/crates/oxc_allocator/src/pool/mod.rs b/crates/oxc_allocator/src/pool/mod.rs index 5c558da03de39..e9a2844893e9a 100644 --- a/crates/oxc_allocator/src/pool/mod.rs +++ b/crates/oxc_allocator/src/pool/mod.rs @@ -66,7 +66,8 @@ impl AllocatorPool { /// /// # Panics /// - /// Panics if the underlying mutex is poisoned. + /// * Panics if the underlying mutex is poisoned. + /// * Panics if a new allocator needs to be created but memory allocation fails pub fn get(&self) -> AllocatorGuard<'_> { let allocator = match &self.0 { AllocatorPoolInner::Standard(pool) => pool.get(), From 63c3286694d7ddd2e7f0f6304045ab5d4c29ce5e Mon Sep 17 00:00:00 2001 From: overlookmotel Date: Thu, 18 Dec 2025 21:17:24 +0000 Subject: [PATCH 2/2] add full stop to doc comment --- crates/oxc_allocator/src/pool/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/oxc_allocator/src/pool/mod.rs b/crates/oxc_allocator/src/pool/mod.rs index e9a2844893e9a..73d4ce7989fd6 100644 --- a/crates/oxc_allocator/src/pool/mod.rs +++ b/crates/oxc_allocator/src/pool/mod.rs @@ -67,7 +67,7 @@ impl AllocatorPool { /// # Panics /// /// * Panics if the underlying mutex is poisoned. - /// * Panics if a new allocator needs to be created but memory allocation fails + /// * Panics if a new allocator needs to be created but memory allocation fails. pub fn get(&self) -> AllocatorGuard<'_> { let allocator = match &self.0 { AllocatorPoolInner::Standard(pool) => pool.get(),