Skip to main content

kalloc/
lib.rs

1// Copyright 2026 The Fuchsia Authors
2//
3// Use of this source code is governed by a MIT-style
4// license that can be found in the LICENSE file or at
5// https://opensource.org/licenses/MIT
6
7#![no_std]
8
9#[cfg(not(is_kernel))]
10extern crate alloc;
11
12use core::alloc::Layout;
13use core::ptr::NonNull;
14
15mod allocator;
16mod boxed;
17
18pub use allocator::{AllocError, Allocator, DefaultAllocator};
19pub use boxed::Box;
20
21/// Fallible allocation matching standard alloc interface.
22///
23/// # Safety
24///
25/// - `layout` must have non-zero size.
26#[cfg(not(is_kernel))]
27pub unsafe fn alloc(layout: Layout) -> Option<NonNull<u8>> {
28    debug_assert!(layout.size() > 0);
29    let ptr = unsafe { alloc::alloc::alloc(layout) };
30    NonNull::new(ptr)
31}
32
33/// Fallible deallocation matching standard alloc interface.
34///
35/// # Safety
36///
37/// - `ptr` is a block of memory currently allocated via this allocator and,
38/// - `layout` is the same layout that was used to allocate that block of memory.
39#[cfg(not(is_kernel))]
40pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) {
41    debug_assert!(layout.size() > 0);
42    unsafe { alloc::alloc::dealloc(ptr, layout) }
43}
44
45/// Fallible reallocation matching standard alloc interface.
46///
47/// # Safety
48///
49/// - `ptr` is allocated via this allocator,
50/// - `layout` is the same layout that was used to allocate that block of memory,
51/// - `new_size` is greater than zero,
52/// - `new_size`, when rounded up to the nearest multiple of `layout.align()`, does not overflow isize.
53#[cfg(not(is_kernel))]
54pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> Option<NonNull<u8>> {
55    debug_assert!(layout.size() > 0);
56    debug_assert!(new_size > 0);
57    let ptr = unsafe { alloc::alloc::realloc(ptr, layout, new_size) };
58    NonNull::new(ptr)
59}
60
61/// Fallible zeroed allocation matching standard alloc interface.
62///
63/// # Safety
64///
65/// - `layout` must have non-zero size.
66#[cfg(not(is_kernel))]
67pub unsafe fn alloc_zeroed(layout: Layout) -> Option<NonNull<u8>> {
68    debug_assert!(layout.size() > 0);
69    let ptr = unsafe { alloc::alloc::alloc_zeroed(layout) };
70    NonNull::new(ptr)
71}
72
73/// Fallible allocation using kernel malloc.
74///
75/// # Safety
76///
77/// - `layout` must have non-zero size.
78#[cfg(is_kernel)]
79pub unsafe fn alloc(layout: Layout) -> Option<NonNull<u8>> {
80    debug_assert!(layout.size() > 0);
81    unsafe extern "C" {
82        fn malloc(size: usize) -> *mut core::ffi::c_void;
83    }
84    let ptr = unsafe { malloc(layout.size()) as *mut u8 };
85    NonNull::new(ptr)
86}
87
88/// Fallible deallocation using kernel free.
89///
90/// # Safety
91///
92/// - `ptr` is a block of memory currently allocated via this allocator and,
93/// - `layout` is the same layout that was used to allocate that block of memory.
94#[cfg(is_kernel)]
95pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) {
96    debug_assert!(layout.size() > 0);
97    unsafe extern "C" {
98        fn free(ptr: *mut core::ffi::c_void);
99    }
100    unsafe { free(ptr as *mut core::ffi::c_void) }
101}
102
103/// Fallible reallocation using kernel realloc.
104///
105/// # Safety
106///
107/// - `ptr` is allocated via this allocator,
108/// - `layout` is the same layout that was used to allocate that block of memory,
109/// - `new_size` is greater than zero,
110/// - `new_size`, when rounded up to the nearest multiple of `layout.align()`, does not overflow isize.
111#[cfg(is_kernel)]
112pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> Option<NonNull<u8>> {
113    debug_assert!(layout.size() > 0);
114    debug_assert!(new_size > 0);
115    unsafe extern "C" {
116        fn realloc(ptr: *mut core::ffi::c_void, size: usize) -> *mut core::ffi::c_void;
117    }
118    let ptr = unsafe { realloc(ptr as *mut core::ffi::c_void, new_size) as *mut u8 };
119    NonNull::new(ptr)
120}
121
122/// Fallible zeroed allocation using kernel calloc.
123///
124/// # Safety
125///
126/// - `layout` must have non-zero size.
127#[cfg(is_kernel)]
128pub unsafe fn alloc_zeroed(layout: Layout) -> Option<NonNull<u8>> {
129    debug_assert!(layout.size() > 0);
130    unsafe extern "C" {
131        fn calloc(nmemb: usize, size: usize) -> *mut core::ffi::c_void;
132    }
133    let ptr = unsafe { calloc(1, layout.size()) as *mut u8 };
134    NonNull::new(ptr)
135}
136
137#[cfg(test)]
138mod tests {
139    use super::*;
140
141    #[test]
142    fn test_kalloc_alloc() {
143        let layout = Layout::from_size_align(10, 1).unwrap();
144        unsafe {
145            let ptr = crate::alloc(layout).unwrap();
146            crate::dealloc(ptr.as_ptr(), layout);
147        }
148    }
149
150    #[test]
151    fn test_kalloc_realloc() {
152        let layout = Layout::from_size_align(10, 1).unwrap();
153        unsafe {
154            let ptr = crate::alloc(layout).unwrap();
155            let new_ptr = crate::realloc(ptr.as_ptr(), layout, 20).unwrap();
156            crate::dealloc(new_ptr.as_ptr(), Layout::from_size_align(20, 1).unwrap());
157        }
158    }
159
160    #[test]
161    fn test_kalloc_alloc_zeroed() {
162        let layout = Layout::from_size_align(10, 1).unwrap();
163        unsafe {
164            let ptr = crate::alloc_zeroed(layout).unwrap();
165            let slice = core::slice::from_raw_parts(ptr.as_ptr(), 10);
166            assert!(slice.iter().all(|&b| b == 0));
167            crate::dealloc(ptr.as_ptr(), layout);
168        }
169    }
170}