@@ -40,36 +40,49 @@ use hyperlight_guest::exit::abort_with_code;
40
40
*/
41
41
42
42
// 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
+
45
+ #[ repr( transparent) ]
46
+ // A header that stores the layout information for the allocated memory block.
47
+ struct Header ( Layout ) ;
48
+
49
+ const HEADER_LEN : usize = size_of :: < Header > ( ) ;
44
50
45
51
/// Allocates a block of memory with the given size. The memory is only guaranteed to be initialized to 0s if `zero` is true, otherwise
46
52
/// it may or may not be initialized.
47
53
///
48
54
/// # Safety
49
55
/// 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 {
56
+ unsafe fn alloc_helper ( size : usize , alignment : usize , zero : bool ) -> * mut c_void {
51
57
if size == 0 {
52
58
return ptr:: null_mut ( ) ;
53
59
}
54
60
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" ) ;
61
+ let actual_align = alignment. max ( align_of :: < Header > ( ) ) ;
62
+ let data_offset = HEADER_LEN . next_multiple_of ( actual_align) ;
63
+
64
+ let Some ( total_size) = data_offset. checked_add ( size) else {
65
+ abort_with_code ( & [ ErrorCode :: MallocFailed as u8 ] ) ;
66
+ } ;
67
+
68
+ // Create layout for entire allocation
69
+ let layout =
70
+ Layout :: from_size_align ( total_size, actual_align) . expect ( "Invalid layout parameters" ) ;
60
71
61
72
unsafe {
62
73
let raw_ptr = match zero {
63
74
true => alloc:: alloc:: alloc_zeroed ( layout) ,
64
75
false => alloc:: alloc:: alloc ( layout) ,
65
76
} ;
77
+
66
78
if raw_ptr. is_null ( ) {
67
79
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
72
80
}
81
+
82
+ // Place Header immediately before the user data region
83
+ let header_ptr = raw_ptr. add ( data_offset - HEADER_LEN ) . cast :: < Header > ( ) ;
84
+ header_ptr. write ( Header ( layout) ) ;
85
+ raw_ptr. add ( data_offset) as * mut c_void
73
86
}
74
87
}
75
88
@@ -80,7 +93,7 @@ unsafe fn alloc_helper(size: usize, zero: bool) -> *mut c_void {
80
93
/// The returned pointer must be freed with `memory::free` when it is no longer needed, otherwise memory will leak.
81
94
#[ unsafe( no_mangle) ]
82
95
pub unsafe extern "C" fn malloc ( size : usize ) -> * mut c_void {
83
- unsafe { alloc_helper ( size, false ) }
96
+ unsafe { alloc_helper ( size, DEFAULT_ALIGN , false ) }
84
97
}
85
98
86
99
/// Allocates a block of memory for an array of `nmemb` elements, each of `size` bytes.
@@ -95,22 +108,45 @@ pub unsafe extern "C" fn calloc(nmemb: usize, size: usize) -> *mut c_void {
95
108
. checked_mul ( size)
96
109
. expect ( "nmemb * size should not overflow in calloc" ) ;
97
110
98
- alloc_helper ( total_size, true )
111
+ alloc_helper ( total_size, DEFAULT_ALIGN , true )
99
112
}
100
113
}
101
114
115
+ /// Allocates aligned memory.
116
+ ///
117
+ /// # Safety
118
+ /// The returned pointer must be freed with `free` when it is no longer needed.
119
+ #[ unsafe( no_mangle) ]
120
+ pub unsafe extern "C" fn aligned_alloc ( alignment : usize , size : usize ) -> * mut c_void {
121
+ // Validate alignment
122
+ if alignment == 0 || ( alignment & ( alignment - 1 ) ) != 0 {
123
+ return ptr:: null_mut ( ) ;
124
+ }
125
+
126
+ unsafe { alloc_helper ( size, alignment, false ) }
127
+ }
128
+
102
129
/// Frees the memory block pointed to by `ptr`.
103
130
///
104
131
/// # Safety
105
132
/// `ptr` must be a pointer to a memory block previously allocated by `memory::malloc`, `memory::calloc`, or `memory::realloc`.
106
133
#[ unsafe( no_mangle) ]
107
134
pub 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
- }
135
+ if ptr. is_null ( ) {
136
+ return ;
137
+ }
138
+
139
+ let user_ptr = ptr as * const u8 ;
140
+
141
+ unsafe {
142
+ // Read the Header just before the user data
143
+ let header_ptr = user_ptr. sub ( HEADER_LEN ) . cast :: < Header > ( ) ;
144
+ let layout = header_ptr. read ( ) . 0 ;
145
+
146
+ // Deallocate from the original base pointer
147
+ let offset = HEADER_LEN . next_multiple_of ( layout. align ( ) ) ;
148
+ let raw_ptr = user_ptr. sub ( offset) as * mut u8 ;
149
+ alloc:: alloc:: dealloc ( raw_ptr, layout) ;
114
150
}
115
151
}
116
152
@@ -134,26 +170,24 @@ pub unsafe extern "C" fn realloc(ptr: *mut c_void, size: usize) -> *mut c_void {
134
170
return ptr:: null_mut ( ) ;
135
171
}
136
172
137
- let total_new_size = size
138
- . checked_add ( size_of :: < Layout > ( ) )
139
- . expect ( "data and layout size should not overflow in realloc" ) ;
173
+ let user_ptr = ptr as * const u8 ;
140
174
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 ( ) ;
175
+ unsafe {
176
+ let header_ptr = user_ptr. sub ( HEADER_LEN ) . cast :: < Header > ( ) ;
144
177
145
- let new_block_start =
146
- unsafe { alloc :: alloc :: realloc ( block_start as * mut u8 , old_layout, total_new_size ) }
147
- as * mut Layout ;
178
+ let old_layout = header_ptr . read ( ) . 0 ;
179
+ let old_offset = HEADER_LEN . next_multiple_of ( old_layout. align ( ) ) ;
180
+ let old_user_size = old_layout . size ( ) - old_offset ;
148
181
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
182
+ let new_ptr = alloc_helper ( size, old_layout. align ( ) , false ) ;
183
+ if new_ptr. is_null ( ) {
184
+ return ptr:: null_mut ( ) ;
157
185
}
186
+
187
+ let copy_size = old_user_size. min ( size) ;
188
+ ptr:: copy_nonoverlapping ( user_ptr, new_ptr as * mut u8 , copy_size) ;
189
+
190
+ free ( ptr) ;
191
+ new_ptr
158
192
}
159
193
}
0 commit comments