From 7c9bfdf0a0e0ac9b1b72696369c2e259e82ed103 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Mon, 11 May 2026 19:39:05 +0200 Subject: [PATCH 1/3] refactor(syscalls): move imports --- src/syscalls/mod.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/syscalls/mod.rs b/src/syscalls/mod.rs index 53c0490422..ae1f5911d1 100644 --- a/src/syscalls/mod.rs +++ b/src/syscalls/mod.rs @@ -1,6 +1,8 @@ #![allow(clippy::result_unit_err)] +use alloc::boxed::Box; use alloc::ffi::CString; +use alloc::vec::Vec; #[cfg(all(target_os = "none", not(feature = "common-os")))] use core::alloc::{GlobalAlloc, Layout}; use core::ffi::{CStr, c_char}; @@ -223,9 +225,6 @@ pub unsafe extern "C" fn sys_free(ptr: *mut u8, size: usize, align: usize) { } pub(crate) fn get_application_parameters() -> (i32, *const *const u8, *const *const u8) { - use alloc::boxed::Box; - use alloc::vec::Vec; - let mut argv = Vec::new(); let name = Box::leak(Box::new("bin\0")).as_ptr(); From 17e0d0e6d93d1d4288ba566a7d9826324a68bb25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Mon, 11 May 2026 19:44:03 +0200 Subject: [PATCH 2/3] refactor(syscalls): move alloc syscalls into new module --- src/syscalls/alloc.rs | 155 ++++++++++++++++++++++++++++++++++++++ src/syscalls/mod.rs | 169 ++---------------------------------------- 2 files changed, 160 insertions(+), 164 deletions(-) create mode 100644 src/syscalls/alloc.rs diff --git a/src/syscalls/alloc.rs b/src/syscalls/alloc.rs new file mode 100644 index 0000000000..2014c80691 --- /dev/null +++ b/src/syscalls/alloc.rs @@ -0,0 +1,155 @@ +use core::alloc::{GlobalAlloc, Layout}; +use core::ptr; + +use crate::mm::ALLOCATOR; + +/// Interface to allocate memory from system heap +/// +/// # Errors +/// Returning a null pointer indicates that either memory is exhausted or +/// `size` and `align` do not meet this allocator's size or alignment constraints. +/// +#[hermit_macro::system] +#[unsafe(no_mangle)] +pub extern "C" fn sys_alloc(size: usize, align: usize) -> *mut u8 { + let layout_res = Layout::from_size_align(size, align); + if layout_res.is_err() || size == 0 { + warn!("__sys_alloc called with size {size:#x}, align {align:#x} is an invalid layout!"); + return ptr::null_mut(); + } + let layout = layout_res.unwrap(); + let ptr = unsafe { ALLOCATOR.alloc(layout) }; + + trace!("__sys_alloc: allocate memory at {ptr:p} (size {size:#x}, align {align:#x})"); + + ptr +} + +#[hermit_macro::system] +#[unsafe(no_mangle)] +pub extern "C" fn sys_alloc_zeroed(size: usize, align: usize) -> *mut u8 { + let layout_res = Layout::from_size_align(size, align); + if layout_res.is_err() || size == 0 { + warn!( + "__sys_alloc_zeroed called with size {size:#x}, align {align:#x} is an invalid layout!" + ); + return ptr::null_mut(); + } + let layout = layout_res.unwrap(); + let ptr = unsafe { ALLOCATOR.alloc_zeroed(layout) }; + + trace!("__sys_alloc_zeroed: allocate memory at {ptr:p} (size {size:#x}, align {align:#x})"); + + ptr +} + +#[hermit_macro::system] +#[unsafe(no_mangle)] +pub extern "C" fn sys_malloc(size: usize, align: usize) -> *mut u8 { + let layout_res = Layout::from_size_align(size, align); + if layout_res.is_err() || size == 0 { + warn!("__sys_malloc called with size {size:#x}, align {align:#x} is an invalid layout!"); + return ptr::null_mut(); + } + let layout = layout_res.unwrap(); + let ptr = unsafe { ALLOCATOR.alloc(layout) }; + + trace!("__sys_malloc: allocate memory at {ptr:p} (size {size:#x}, align {align:#x})"); + + ptr +} + +/// Shrink or grow a block of memory to the given `new_size`. The block is described by the given +/// ptr pointer and layout. If this returns a non-null pointer, then ownership of the memory block +/// referenced by ptr has been transferred to this allocator. The memory may or may not have been +/// deallocated, and should be considered unusable (unless of course it was transferred back to the +/// caller again via the return value of this method). The new memory block is allocated with +/// layout, but with the size updated to new_size. +/// If this method returns null, then ownership of the memory block has not been transferred to this +/// allocator, and the contents of the memory block are unaltered. +/// +/// # Safety +/// This function is unsafe because undefined behavior can result if the caller does not ensure all +/// of the following: +/// - `ptr` must be currently allocated via this allocator, +/// - `size` and `align` must be the same layout that was used to allocate that block of memory. +/// ToDO: verify if the same values for size and align always lead to the same layout +/// +/// # Errors +/// Returns null if the new layout does not meet the size and alignment constraints of the +/// allocator, or if reallocation otherwise fails. +#[hermit_macro::system] +#[unsafe(no_mangle)] +pub unsafe extern "C" fn sys_realloc( + ptr: *mut u8, + size: usize, + align: usize, + new_size: usize, +) -> *mut u8 { + unsafe { + let layout_res = Layout::from_size_align(size, align); + if layout_res.is_err() || size == 0 || new_size == 0 { + warn!( + "__sys_realloc called with ptr {ptr:p}, size {size:#x}, align {align:#x}, new_size {new_size:#x} is an invalid layout!" + ); + return ptr::null_mut(); + } + let layout = layout_res.unwrap(); + let new_ptr = ALLOCATOR.realloc(ptr, layout, new_size); + + if new_ptr.is_null() { + debug!( + "__sys_realloc failed to resize ptr {ptr:p} with size {size:#x}, align {align:#x}, new_size {new_size:#x} !" + ); + } else { + trace!("__sys_realloc: resized memory at {ptr:p}, new address {new_ptr:p}"); + } + new_ptr + } +} + +/// Interface to deallocate a memory region from the system heap +/// +/// # Safety +/// This function is unsafe because undefined behavior can result if the caller does not ensure all of the following: +/// - ptr must denote a block of memory currently allocated via this allocator, +/// - `size` and `align` must be the same values that were used to allocate that block of memory +/// ToDO: verify if the same values for size and align always lead to the same layout +/// +/// # Errors +/// May panic if debug assertions are enabled and invalid parameters `size` or `align` where passed. +#[hermit_macro::system] +#[unsafe(no_mangle)] +pub unsafe extern "C" fn sys_dealloc(ptr: *mut u8, size: usize, align: usize) { + unsafe { + let layout_res = Layout::from_size_align(size, align); + if layout_res.is_err() || size == 0 { + warn!( + "__sys_dealloc called with size {size:#x}, align {align:#x} is an invalid layout!" + ); + debug_assert!(layout_res.is_err(), "__sys_dealloc error: Invalid layout"); + debug_assert_ne!(size, 0, "__sys_dealloc error: size cannot be 0"); + } else { + trace!("sys_free: deallocate memory at {ptr:p} (size {size:#x})"); + } + let layout = layout_res.unwrap(); + ALLOCATOR.dealloc(ptr, layout); + } +} + +#[hermit_macro::system] +#[unsafe(no_mangle)] +pub unsafe extern "C" fn sys_free(ptr: *mut u8, size: usize, align: usize) { + unsafe { + let layout_res = Layout::from_size_align(size, align); + if layout_res.is_err() || size == 0 { + warn!("__sys_free called with size {size:#x}, align {align:#x} is an invalid layout!"); + debug_assert!(layout_res.is_err(), "__sys_free error: Invalid layout"); + debug_assert_ne!(size, 0, "__sys_free error: size cannot be 0"); + } else { + trace!("sys_free: deallocate memory at {ptr:p} (size {size:#x})"); + } + let layout = layout_res.unwrap(); + ALLOCATOR.dealloc(ptr, layout); + } +} diff --git a/src/syscalls/mod.rs b/src/syscalls/mod.rs index ae1f5911d1..19fcb89faa 100644 --- a/src/syscalls/mod.rs +++ b/src/syscalls/mod.rs @@ -1,14 +1,12 @@ #![allow(clippy::result_unit_err)] -use alloc::boxed::Box; -use alloc::ffi::CString; -use alloc::vec::Vec; -#[cfg(all(target_os = "none", not(feature = "common-os")))] -use core::alloc::{GlobalAlloc, Layout}; use core::ffi::{CStr, c_char}; use core::marker::PhantomData; use core::{ptr, slice}; +use ::alloc::boxed::Box; +use ::alloc::ffi::CString; +use ::alloc::vec::Vec; use dirent_display::Dirent64Display; pub use self::condvar::*; @@ -30,9 +28,9 @@ use crate::fd::{ dup_object, dup_object2, get_object, isatty, remove_object, }; use crate::fs::{self, FileAttr, SeekWhence}; -#[cfg(all(target_os = "none", not(feature = "common-os")))] -use crate::mm::ALLOCATOR; +#[cfg(all(target_os = "none", not(feature = "common-os")))] +mod alloc; mod condvar; mod entropy; mod futex; @@ -67,163 +65,6 @@ pub(crate) fn init() { init_entropy(); } -/// Interface to allocate memory from system heap -/// -/// # Errors -/// Returning a null pointer indicates that either memory is exhausted or -/// `size` and `align` do not meet this allocator's size or alignment constraints. -/// -#[cfg(all(target_os = "none", not(feature = "common-os")))] -#[hermit_macro::system] -#[unsafe(no_mangle)] -pub extern "C" fn sys_alloc(size: usize, align: usize) -> *mut u8 { - let layout_res = Layout::from_size_align(size, align); - if layout_res.is_err() || size == 0 { - warn!("__sys_alloc called with size {size:#x}, align {align:#x} is an invalid layout!"); - return ptr::null_mut(); - } - let layout = layout_res.unwrap(); - let ptr = unsafe { ALLOCATOR.alloc(layout) }; - - trace!("__sys_alloc: allocate memory at {ptr:p} (size {size:#x}, align {align:#x})"); - - ptr -} - -#[cfg(all(target_os = "none", not(feature = "common-os")))] -#[hermit_macro::system] -#[unsafe(no_mangle)] -pub extern "C" fn sys_alloc_zeroed(size: usize, align: usize) -> *mut u8 { - let layout_res = Layout::from_size_align(size, align); - if layout_res.is_err() || size == 0 { - warn!( - "__sys_alloc_zeroed called with size {size:#x}, align {align:#x} is an invalid layout!" - ); - return ptr::null_mut(); - } - let layout = layout_res.unwrap(); - let ptr = unsafe { ALLOCATOR.alloc_zeroed(layout) }; - - trace!("__sys_alloc_zeroed: allocate memory at {ptr:p} (size {size:#x}, align {align:#x})"); - - ptr -} - -#[cfg(all(target_os = "none", not(feature = "common-os")))] -#[hermit_macro::system] -#[unsafe(no_mangle)] -pub extern "C" fn sys_malloc(size: usize, align: usize) -> *mut u8 { - let layout_res = Layout::from_size_align(size, align); - if layout_res.is_err() || size == 0 { - warn!("__sys_malloc called with size {size:#x}, align {align:#x} is an invalid layout!"); - return ptr::null_mut(); - } - let layout = layout_res.unwrap(); - let ptr = unsafe { ALLOCATOR.alloc(layout) }; - - trace!("__sys_malloc: allocate memory at {ptr:p} (size {size:#x}, align {align:#x})"); - - ptr -} - -/// Shrink or grow a block of memory to the given `new_size`. The block is described by the given -/// ptr pointer and layout. If this returns a non-null pointer, then ownership of the memory block -/// referenced by ptr has been transferred to this allocator. The memory may or may not have been -/// deallocated, and should be considered unusable (unless of course it was transferred back to the -/// caller again via the return value of this method). The new memory block is allocated with -/// layout, but with the size updated to new_size. -/// If this method returns null, then ownership of the memory block has not been transferred to this -/// allocator, and the contents of the memory block are unaltered. -/// -/// # Safety -/// This function is unsafe because undefined behavior can result if the caller does not ensure all -/// of the following: -/// - `ptr` must be currently allocated via this allocator, -/// - `size` and `align` must be the same layout that was used to allocate that block of memory. -/// ToDO: verify if the same values for size and align always lead to the same layout -/// -/// # Errors -/// Returns null if the new layout does not meet the size and alignment constraints of the -/// allocator, or if reallocation otherwise fails. -#[cfg(all(target_os = "none", not(feature = "common-os")))] -#[hermit_macro::system] -#[unsafe(no_mangle)] -pub unsafe extern "C" fn sys_realloc( - ptr: *mut u8, - size: usize, - align: usize, - new_size: usize, -) -> *mut u8 { - unsafe { - let layout_res = Layout::from_size_align(size, align); - if layout_res.is_err() || size == 0 || new_size == 0 { - warn!( - "__sys_realloc called with ptr {ptr:p}, size {size:#x}, align {align:#x}, new_size {new_size:#x} is an invalid layout!" - ); - return ptr::null_mut(); - } - let layout = layout_res.unwrap(); - let new_ptr = ALLOCATOR.realloc(ptr, layout, new_size); - - if new_ptr.is_null() { - debug!( - "__sys_realloc failed to resize ptr {ptr:p} with size {size:#x}, align {align:#x}, new_size {new_size:#x} !" - ); - } else { - trace!("__sys_realloc: resized memory at {ptr:p}, new address {new_ptr:p}"); - } - new_ptr - } -} - -/// Interface to deallocate a memory region from the system heap -/// -/// # Safety -/// This function is unsafe because undefined behavior can result if the caller does not ensure all of the following: -/// - ptr must denote a block of memory currently allocated via this allocator, -/// - `size` and `align` must be the same values that were used to allocate that block of memory -/// ToDO: verify if the same values for size and align always lead to the same layout -/// -/// # Errors -/// May panic if debug assertions are enabled and invalid parameters `size` or `align` where passed. -#[cfg(all(target_os = "none", not(feature = "common-os")))] -#[hermit_macro::system] -#[unsafe(no_mangle)] -pub unsafe extern "C" fn sys_dealloc(ptr: *mut u8, size: usize, align: usize) { - unsafe { - let layout_res = Layout::from_size_align(size, align); - if layout_res.is_err() || size == 0 { - warn!( - "__sys_dealloc called with size {size:#x}, align {align:#x} is an invalid layout!" - ); - debug_assert!(layout_res.is_err(), "__sys_dealloc error: Invalid layout"); - debug_assert_ne!(size, 0, "__sys_dealloc error: size cannot be 0"); - } else { - trace!("sys_free: deallocate memory at {ptr:p} (size {size:#x})"); - } - let layout = layout_res.unwrap(); - ALLOCATOR.dealloc(ptr, layout); - } -} - -#[cfg(all(target_os = "none", not(feature = "common-os")))] -#[hermit_macro::system] -#[unsafe(no_mangle)] -pub unsafe extern "C" fn sys_free(ptr: *mut u8, size: usize, align: usize) { - unsafe { - let layout_res = Layout::from_size_align(size, align); - if layout_res.is_err() || size == 0 { - warn!("__sys_free called with size {size:#x}, align {align:#x} is an invalid layout!"); - debug_assert!(layout_res.is_err(), "__sys_free error: Invalid layout"); - debug_assert_ne!(size, 0, "__sys_free error: size cannot be 0"); - } else { - trace!("sys_free: deallocate memory at {ptr:p} (size {size:#x})"); - } - let layout = layout_res.unwrap(); - ALLOCATOR.dealloc(ptr, layout); - } -} - pub(crate) fn get_application_parameters() -> (i32, *const *const u8, *const *const u8) { let mut argv = Vec::new(); From 9d1304c02b4233fb046b52d28c87fbe0b4618d72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Mon, 11 May 2026 19:49:47 +0200 Subject: [PATCH 3/3] feat(syscalls): reimplement alloc syscalls with stricter requirements --- src/syscalls/alloc.rs | 144 +++++++----------------------------------- 1 file changed, 22 insertions(+), 122 deletions(-) diff --git a/src/syscalls/alloc.rs b/src/syscalls/alloc.rs index 2014c80691..8d0c141b6d 100644 --- a/src/syscalls/alloc.rs +++ b/src/syscalls/alloc.rs @@ -1,83 +1,26 @@ -use core::alloc::{GlobalAlloc, Layout}; -use core::ptr; +//! Alloc syscalls. -use crate::mm::ALLOCATOR; +use alloc::alloc::{alloc, alloc_zeroed, dealloc, realloc}; +use core::alloc::Layout; -/// Interface to allocate memory from system heap -/// -/// # Errors -/// Returning a null pointer indicates that either memory is exhausted or -/// `size` and `align` do not meet this allocator's size or alignment constraints. -/// #[hermit_macro::system] #[unsafe(no_mangle)] -pub extern "C" fn sys_alloc(size: usize, align: usize) -> *mut u8 { - let layout_res = Layout::from_size_align(size, align); - if layout_res.is_err() || size == 0 { - warn!("__sys_alloc called with size {size:#x}, align {align:#x} is an invalid layout!"); - return ptr::null_mut(); - } - let layout = layout_res.unwrap(); - let ptr = unsafe { ALLOCATOR.alloc(layout) }; - - trace!("__sys_alloc: allocate memory at {ptr:p} (size {size:#x}, align {align:#x})"); - - ptr +pub unsafe extern "C" fn sys_alloc(size: usize, align: usize) -> *mut u8 { + unsafe { alloc(layout_from_size_align(size, align)) } } #[hermit_macro::system] #[unsafe(no_mangle)] -pub extern "C" fn sys_alloc_zeroed(size: usize, align: usize) -> *mut u8 { - let layout_res = Layout::from_size_align(size, align); - if layout_res.is_err() || size == 0 { - warn!( - "__sys_alloc_zeroed called with size {size:#x}, align {align:#x} is an invalid layout!" - ); - return ptr::null_mut(); - } - let layout = layout_res.unwrap(); - let ptr = unsafe { ALLOCATOR.alloc_zeroed(layout) }; - - trace!("__sys_alloc_zeroed: allocate memory at {ptr:p} (size {size:#x}, align {align:#x})"); - - ptr +pub unsafe extern "C" fn sys_dealloc(ptr: *mut u8, size: usize, align: usize) { + unsafe { dealloc(ptr, layout_from_size_align(size, align)) } } #[hermit_macro::system] #[unsafe(no_mangle)] -pub extern "C" fn sys_malloc(size: usize, align: usize) -> *mut u8 { - let layout_res = Layout::from_size_align(size, align); - if layout_res.is_err() || size == 0 { - warn!("__sys_malloc called with size {size:#x}, align {align:#x} is an invalid layout!"); - return ptr::null_mut(); - } - let layout = layout_res.unwrap(); - let ptr = unsafe { ALLOCATOR.alloc(layout) }; - - trace!("__sys_malloc: allocate memory at {ptr:p} (size {size:#x}, align {align:#x})"); - - ptr +pub unsafe extern "C" fn sys_alloc_zeroed(size: usize, align: usize) -> *mut u8 { + unsafe { alloc_zeroed(layout_from_size_align(size, align)) } } -/// Shrink or grow a block of memory to the given `new_size`. The block is described by the given -/// ptr pointer and layout. If this returns a non-null pointer, then ownership of the memory block -/// referenced by ptr has been transferred to this allocator. The memory may or may not have been -/// deallocated, and should be considered unusable (unless of course it was transferred back to the -/// caller again via the return value of this method). The new memory block is allocated with -/// layout, but with the size updated to new_size. -/// If this method returns null, then ownership of the memory block has not been transferred to this -/// allocator, and the contents of the memory block are unaltered. -/// -/// # Safety -/// This function is unsafe because undefined behavior can result if the caller does not ensure all -/// of the following: -/// - `ptr` must be currently allocated via this allocator, -/// - `size` and `align` must be the same layout that was used to allocate that block of memory. -/// ToDO: verify if the same values for size and align always lead to the same layout -/// -/// # Errors -/// Returns null if the new layout does not meet the size and alignment constraints of the -/// allocator, or if reallocation otherwise fails. #[hermit_macro::system] #[unsafe(no_mangle)] pub unsafe extern "C" fn sys_realloc( @@ -86,70 +29,27 @@ pub unsafe extern "C" fn sys_realloc( align: usize, new_size: usize, ) -> *mut u8 { - unsafe { - let layout_res = Layout::from_size_align(size, align); - if layout_res.is_err() || size == 0 || new_size == 0 { - warn!( - "__sys_realloc called with ptr {ptr:p}, size {size:#x}, align {align:#x}, new_size {new_size:#x} is an invalid layout!" - ); - return ptr::null_mut(); - } - let layout = layout_res.unwrap(); - let new_ptr = ALLOCATOR.realloc(ptr, layout, new_size); - - if new_ptr.is_null() { - debug!( - "__sys_realloc failed to resize ptr {ptr:p} with size {size:#x}, align {align:#x}, new_size {new_size:#x} !" - ); - } else { - trace!("__sys_realloc: resized memory at {ptr:p}, new address {new_ptr:p}"); - } - new_ptr - } + unsafe { realloc(ptr, layout_from_size_align(size, align), new_size) } } -/// Interface to deallocate a memory region from the system heap -/// -/// # Safety -/// This function is unsafe because undefined behavior can result if the caller does not ensure all of the following: -/// - ptr must denote a block of memory currently allocated via this allocator, -/// - `size` and `align` must be the same values that were used to allocate that block of memory -/// ToDO: verify if the same values for size and align always lead to the same layout -/// -/// # Errors -/// May panic if debug assertions are enabled and invalid parameters `size` or `align` where passed. +/// Deprecated #[hermit_macro::system] #[unsafe(no_mangle)] -pub unsafe extern "C" fn sys_dealloc(ptr: *mut u8, size: usize, align: usize) { - unsafe { - let layout_res = Layout::from_size_align(size, align); - if layout_res.is_err() || size == 0 { - warn!( - "__sys_dealloc called with size {size:#x}, align {align:#x} is an invalid layout!" - ); - debug_assert!(layout_res.is_err(), "__sys_dealloc error: Invalid layout"); - debug_assert_ne!(size, 0, "__sys_dealloc error: size cannot be 0"); - } else { - trace!("sys_free: deallocate memory at {ptr:p} (size {size:#x})"); - } - let layout = layout_res.unwrap(); - ALLOCATOR.dealloc(ptr, layout); - } +pub unsafe extern "C" fn sys_malloc(size: usize, align: usize) -> *mut u8 { + unsafe { alloc(layout_from_size_align(size, align)) } } +/// Deprecated #[hermit_macro::system] #[unsafe(no_mangle)] pub unsafe extern "C" fn sys_free(ptr: *mut u8, size: usize, align: usize) { - unsafe { - let layout_res = Layout::from_size_align(size, align); - if layout_res.is_err() || size == 0 { - warn!("__sys_free called with size {size:#x}, align {align:#x} is an invalid layout!"); - debug_assert!(layout_res.is_err(), "__sys_free error: Invalid layout"); - debug_assert_ne!(size, 0, "__sys_free error: size cannot be 0"); - } else { - trace!("sys_free: deallocate memory at {ptr:p} (size {size:#x})"); - } - let layout = layout_res.unwrap(); - ALLOCATOR.dealloc(ptr, layout); + unsafe { dealloc(ptr, layout_from_size_align(size, align)) } +} + +unsafe fn layout_from_size_align(size: usize, align: usize) -> Layout { + if cfg!(debug_assertions) { + Layout::from_size_align(size, align).unwrap() + } else { + unsafe { Layout::from_size_align_unchecked(size, align) } } }