@@ -40,36 +40,48 @@ use hyperlight_guest::exit::abort_with_code;
4040*/
4141
4242// We assume the maximum alignment for any value is the alignment of u128.
43- const MAX_ALIGN : usize = align_of :: < u128 > ( ) ;
43+ const DEFAULT_ALIGN : usize = align_of :: < u128 > ( ) ;
44+ const HEADER_LEN : usize = size_of :: < Header > ( ) ;
45+
46+ #[ repr( transparent) ]
47+ // A header that stores the layout information for the allocated memory block.
48+ struct Header ( Layout ) ;
4449
4550/// Allocates a block of memory with the given size. The memory is only guaranteed to be initialized to 0s if `zero` is true, otherwise
4651/// it may or may not be initialized.
4752///
4853/// # Safety
4954/// The returned pointer must be freed with `memory::free` when it is no longer needed, otherwise memory will leak.
50- unsafe fn alloc_helper ( size : usize , zero : bool ) -> * mut c_void {
55+ unsafe fn alloc_helper ( size : usize , alignment : usize , zero : bool ) -> * mut c_void {
5156 if size == 0 {
5257 return ptr:: null_mut ( ) ;
5358 }
5459
55- // Allocate a block that includes space for both layout information and data
56- let total_size = size
57- . checked_add ( size_of :: < Layout > ( ) )
58- . expect ( "data and layout size should not overflow in alloc" ) ;
59- let layout = Layout :: from_size_align ( total_size, MAX_ALIGN ) . expect ( "Invalid layout" ) ;
60+ let actual_align = alignment. max ( align_of :: < Header > ( ) ) ;
61+ let data_offset = HEADER_LEN . next_multiple_of ( actual_align) ;
62+
63+ let Some ( total_size) = data_offset. checked_add ( size) else {
64+ abort_with_code ( & [ ErrorCode :: MallocFailed as u8 ] ) ;
65+ } ;
66+
67+ // Create layout for entire allocation
68+ let layout =
69+ Layout :: from_size_align ( total_size, actual_align) . expect ( "Invalid layout parameters" ) ;
6070
6171 unsafe {
6272 let raw_ptr = match zero {
6373 true => alloc:: alloc:: alloc_zeroed ( layout) ,
6474 false => alloc:: alloc:: alloc ( layout) ,
6575 } ;
76+
6677 if raw_ptr. is_null ( ) {
6778 abort_with_code ( & [ ErrorCode :: MallocFailed as u8 ] ) ;
68- } else {
69- let layout_ptr = raw_ptr as * mut Layout ;
70- layout_ptr. write ( layout) ;
71- layout_ptr. add ( 1 ) as * mut c_void
7279 }
80+
81+ // Place Header immediately before the user data region
82+ let header_ptr = raw_ptr. add ( data_offset - HEADER_LEN ) . cast :: < Header > ( ) ;
83+ header_ptr. write ( Header ( layout) ) ;
84+ raw_ptr. add ( data_offset) as * mut c_void
7385 }
7486}
7587
@@ -80,7 +92,7 @@ unsafe fn alloc_helper(size: usize, zero: bool) -> *mut c_void {
8092/// The returned pointer must be freed with `memory::free` when it is no longer needed, otherwise memory will leak.
8193#[ unsafe( no_mangle) ]
8294pub unsafe extern "C" fn malloc ( size : usize ) -> * mut c_void {
83- unsafe { alloc_helper ( size, false ) }
95+ unsafe { alloc_helper ( size, DEFAULT_ALIGN , false ) }
8496}
8597
8698/// Allocates a block of memory for an array of `nmemb` elements, each of `size` bytes.
@@ -95,8 +107,22 @@ pub unsafe extern "C" fn calloc(nmemb: usize, size: usize) -> *mut c_void {
95107 . checked_mul ( size)
96108 . expect ( "nmemb * size should not overflow in calloc" ) ;
97109
98- alloc_helper ( total_size, true )
110+ alloc_helper ( total_size, DEFAULT_ALIGN , true )
111+ }
112+ }
113+
114+ /// Allocates aligned memory.
115+ ///
116+ /// # Safety
117+ /// The returned pointer must be freed with `free` when it is no longer needed.
118+ #[ unsafe( no_mangle) ]
119+ pub unsafe extern "C" fn aligned_alloc ( alignment : usize , size : usize ) -> * mut c_void {
120+ // Validate alignment
121+ if alignment == 0 || ( alignment & ( alignment - 1 ) ) != 0 {
122+ return ptr:: null_mut ( ) ;
99123 }
124+
125+ unsafe { alloc_helper ( size, alignment, false ) }
100126}
101127
102128/// Frees the memory block pointed to by `ptr`.
@@ -105,12 +131,21 @@ pub unsafe extern "C" fn calloc(nmemb: usize, size: usize) -> *mut c_void {
105131/// `ptr` must be a pointer to a memory block previously allocated by `memory::malloc`, `memory::calloc`, or `memory::realloc`.
106132#[ unsafe( no_mangle) ]
107133pub unsafe extern "C" fn free ( ptr : * mut c_void ) {
108- if !ptr. is_null ( ) {
109- unsafe {
110- let block_start = ( ptr as * const Layout ) . sub ( 1 ) ;
111- let layout = block_start. read ( ) ;
112- alloc:: alloc:: dealloc ( block_start as * mut u8 , layout)
113- }
134+ if ptr. is_null ( ) {
135+ return ;
136+ }
137+
138+ let user_ptr = ptr as * const u8 ;
139+
140+ unsafe {
141+ // Read the Header just before the user data
142+ let header_ptr = user_ptr. sub ( HEADER_LEN ) . cast :: < Header > ( ) ;
143+ let layout = header_ptr. read ( ) . 0 ;
144+
145+ // Deallocate from the original base pointer
146+ let offset = HEADER_LEN . next_multiple_of ( layout. align ( ) ) ;
147+ let raw_ptr = user_ptr. sub ( offset) as * mut u8 ;
148+ alloc:: alloc:: dealloc ( raw_ptr, layout) ;
114149 }
115150}
116151
@@ -134,26 +169,24 @@ pub unsafe extern "C" fn realloc(ptr: *mut c_void, size: usize) -> *mut c_void {
134169 return ptr:: null_mut ( ) ;
135170 }
136171
137- let total_new_size = size
138- . checked_add ( size_of :: < Layout > ( ) )
139- . expect ( "data and layout size should not overflow in realloc" ) ;
172+ let user_ptr = ptr as * const u8 ;
140173
141- let block_start = unsafe { ( ptr as * const Layout ) . sub ( 1 ) } ;
142- let old_layout = unsafe { block_start. read ( ) } ;
143- let new_layout = Layout :: from_size_align ( total_new_size, MAX_ALIGN ) . unwrap ( ) ;
174+ unsafe {
175+ let header_ptr = user_ptr. sub ( HEADER_LEN ) . cast :: < Header > ( ) ;
144176
145- let new_block_start =
146- unsafe { alloc :: alloc :: realloc ( block_start as * mut u8 , old_layout, total_new_size ) }
147- as * mut Layout ;
177+ let old_layout = header_ptr . read ( ) . 0 ;
178+ let old_offset = HEADER_LEN . next_multiple_of ( old_layout. align ( ) ) ;
179+ let old_user_size = old_layout . size ( ) - old_offset ;
148180
149- if new_block_start. is_null ( ) {
150- // Realloc failed
151- abort_with_code ( & [ ErrorCode :: MallocFailed as u8 ] ) ;
152- } else {
153- // Update the stored Layout, then return ptr to memory right after the Layout.
154- unsafe {
155- new_block_start. write ( new_layout) ;
156- new_block_start. add ( 1 ) as * mut c_void
181+ let new_ptr = alloc_helper ( size, old_layout. align ( ) , false ) ;
182+ if new_ptr. is_null ( ) {
183+ return ptr:: null_mut ( ) ;
157184 }
185+
186+ let copy_size = old_user_size. min ( size) ;
187+ ptr:: copy_nonoverlapping ( user_ptr, new_ptr as * mut u8 , copy_size) ;
188+
189+ free ( ptr) ;
190+ new_ptr
158191 }
159192}
0 commit comments