1 // SPDX-License-Identifier: GPL-2.0 2 3 //! So far the kernel's `Box` and `Vec` types can't be used by userspace test cases, since all users 4 //! of those types (e.g. `CString`) use kernel allocators for instantiation. 5 //! 6 //! In order to allow userspace test cases to make use of such types as well, implement the 7 //! `Cmalloc` allocator within the allocator_test module and type alias all kernel allocators to 8 //! `Cmalloc`. The `Cmalloc` allocator uses libc's `realloc()` function as allocator backend. 9 10 #![allow(missing_docs)] 11 12 use super::{flags::*, AllocError, Allocator, Flags}; 13 use core::alloc::Layout; 14 use core::cmp; 15 use core::ptr; 16 use core::ptr::NonNull; 17 18 /// The userspace allocator based on libc. 19 pub struct Cmalloc; 20 21 pub type Kmalloc = Cmalloc; 22 pub type Vmalloc = Kmalloc; 23 pub type KVmalloc = Kmalloc; 24 25 extern "C" { 26 #[link_name = "aligned_alloc"] 27 fn libc_aligned_alloc(align: usize, size: usize) -> *mut crate::ffi::c_void; 28 29 #[link_name = "free"] 30 fn libc_free(ptr: *mut crate::ffi::c_void); 31 } 32 33 // SAFETY: 34 // - memory remains valid until it is explicitly freed, 35 // - passing a pointer to a valid memory allocation created by this `Allocator` is always OK, 36 // - `realloc` provides the guarantees as provided in the `# Guarantees` section. 37 unsafe impl Allocator for Cmalloc { 38 unsafe fn realloc( 39 ptr: Option<NonNull<u8>>, 40 layout: Layout, 41 old_layout: Layout, 42 flags: Flags, 43 ) -> Result<NonNull<[u8]>, AllocError> { 44 let src = match ptr { 45 Some(src) => { 46 if old_layout.size() == 0 { 47 ptr::null_mut() 48 } else { 49 src.as_ptr() 50 } 51 } 52 None => ptr::null_mut(), 53 }; 54 55 if layout.size() == 0 { 56 // SAFETY: `src` is either NULL or was previously allocated with this `Allocator` 57 unsafe { libc_free(src.cast()) }; 58 59 return Ok(NonNull::slice_from_raw_parts( 60 crate::alloc::dangling_from_layout(layout), 61 0, 62 )); 63 } 64 65 // SAFETY: Returns either NULL or a pointer to a memory allocation that satisfies or 66 // exceeds the given size and alignment requirements. 67 let dst = unsafe { libc_aligned_alloc(layout.align(), layout.size()) } as *mut u8; 68 let dst = NonNull::new(dst).ok_or(AllocError)?; 69 70 if flags.contains(__GFP_ZERO) { 71 // SAFETY: The preceding calls to `libc_aligned_alloc` and `NonNull::new` 72 // guarantee that `dst` points to memory of at least `layout.size()` bytes. 73 unsafe { dst.as_ptr().write_bytes(0, layout.size()) }; 74 } 75 76 if !src.is_null() { 77 // SAFETY: 78 // - `src` has previously been allocated with this `Allocator`; `dst` has just been 79 // newly allocated, hence the memory regions do not overlap. 80 // - both` src` and `dst` are properly aligned and valid for reads and writes 81 unsafe { 82 ptr::copy_nonoverlapping( 83 src, 84 dst.as_ptr(), 85 cmp::min(layout.size(), old_layout.size()), 86 ) 87 }; 88 } 89 90 // SAFETY: `src` is either NULL or was previously allocated with this `Allocator` 91 unsafe { libc_free(src.cast()) }; 92 93 Ok(NonNull::slice_from_raw_parts(dst, layout.size())) 94 } 95 } 96