@@ -25,19 +25,42 @@ use crate::entrypoint::abort_with_code;
2525
2626extern  crate  alloc; 
2727
28- #[ no_mangle]  
29- pub  extern  "C"  fn  hlmalloc ( size :  usize )  -> * mut  c_void  { 
30-     alloc_helper ( size,  false ) 
31- } 
28+ /* 
29+     C-wrappers for Rust's registered global allocator. 
3230
33- pub  fn  alloc_helper ( size :  usize ,  zero :  bool )  -> * mut  c_void  { 
34-     // Allocate a block that includes space for both layout information and data 
31+     Each memory allocation via `malloc/calloc/realloc` is stored together with a `alloc::Layout` describing 
32+     the size and alignment of the allocation. This layout is stored just before the actual raw memory returned to the caller. 
33+ 
34+     Example: A call to malloc(64) will allocate space for both an `alloc::Layout` and 64 bytes of memory: 
35+ 
36+     ---------------------------------------------------------------------------------------- 
37+     | Layout { size: 64 + size_of::<Layout>(), ... }    |      64 bytes of memory         | ... 
38+     ---------------------------------------------------------------------------------------- 
39+                                                         ^ 
40+                                                         | 
41+                                                         | 
42+                                                     ptr returned to caller 
43+ */ 
44+ 
45+ // We assume the maximum alignment for any value is the alignment of u128. 
46+ const  MAX_ALIGN :  usize  = align_of :: < u128 > ( ) ; 
47+ 
48+ /// Allocates a block of memory with the given size. The memory is only guaranteed to be initialized to 0s if `zero` is true, otherwise 
49+ /// it may or may not be initialized. 
50+ /// 
51+ /// # Safety 
52+ /// The returned pointer must be freed with `memory::free` when it is no longer needed, otherwise memory will leak. 
53+ unsafe  fn  alloc_helper ( size :  usize ,  zero :  bool )  -> * mut  c_void  { 
3554    if  size == 0  { 
3655        return  ptr:: null_mut ( ) ; 
3756    } 
3857
39-     let  total_size = size + size_of :: < Layout > ( ) ; 
40-     let  layout = Layout :: from_size_align ( total_size,  align_of :: < usize > ( ) ) . unwrap ( ) ; 
58+     // Allocate a block that includes space for both layout information and data 
59+     let  total_size = size
60+         . checked_add ( size_of :: < Layout > ( ) ) 
61+         . expect ( "data and layout size should not overflow in alloc" ) ; 
62+     let  layout = Layout :: from_size_align ( total_size,  MAX_ALIGN ) . expect ( "Invalid layout" ) ; 
63+ 
4164    unsafe  { 
4265        let  raw_ptr = match  zero { 
4366            true  => alloc:: alloc:: alloc_zeroed ( layout) , 
@@ -53,14 +76,36 @@ pub fn alloc_helper(size: usize, zero: bool) -> *mut c_void {
5376    } 
5477} 
5578
79+ /// Allocates a block of memory with the given size. 
80+ /// The memory is not guaranteed to be initialized to 0s. 
81+ /// 
82+ /// # Safety 
83+ /// The returned pointer must be freed with `memory::free` when it is no longer needed, otherwise memory will leak. 
84+ #[ no_mangle]  
85+ pub  unsafe  extern  "C"  fn  malloc ( size :  usize )  -> * mut  c_void  { 
86+     alloc_helper ( size,  false ) 
87+ } 
88+ 
89+ /// Allocates a block of memory for an array of `nmemb` elements, each of `size` bytes. 
90+ /// The memory is initialized to 0s. 
91+ /// 
92+ /// # Safety 
93+ /// The returned pointer must be freed with `memory::free` when it is no longer needed, otherwise memory will leak. 
5694#[ no_mangle]  
57- pub  extern  "C"  fn  hlcalloc ( n :  usize ,  size :  usize )  -> * mut  c_void  { 
58-     let  total_size = n *  size; 
95+ pub  unsafe  extern  "C"  fn  calloc ( nmemb :  usize ,  size :  usize )  -> * mut  c_void  { 
96+     let  total_size = nmemb
97+         . checked_mul ( size) 
98+         . expect ( "nmemb * size should not overflow in calloc" ) ; 
99+ 
59100    alloc_helper ( total_size,  true ) 
60101} 
61102
103+ /// Frees the memory block pointed to by `ptr`. 
104+ /// 
105+ /// # Safety 
106+ /// `ptr` must be a pointer to a memory block previously allocated by `memory::malloc`, `memory::calloc`, or `memory::realloc`. 
62107#[ no_mangle]  
63- pub  extern  "C"  fn  hlfree ( ptr :  * mut  c_void )  { 
108+ pub  unsafe   extern  "C"  fn  free ( ptr :  * mut  c_void )  { 
64109    if  !ptr. is_null ( )  { 
65110        unsafe  { 
66111            let  block_start = ( ptr as  * const  Layout ) . sub ( 1 ) ; 
@@ -70,26 +115,43 @@ pub extern "C" fn hlfree(ptr: *mut c_void) {
70115    } 
71116} 
72117
118+ /// Changes the size of the memory block pointed to by `ptr` to `size` bytes. If the returned ptr is non-null, 
119+ /// any usage of the old memory block is immediately undefined behavior. 
120+ /// 
121+ /// # Safety 
122+ /// `ptr` must be a pointer to a memory block previously allocated by `memory::malloc`, `memory::calloc`, or `memory::realloc`. 
73123#[ no_mangle]  
74- pub  extern  "C"  fn  hlrealloc ( ptr :  * mut  c_void ,  size :  usize )  -> * mut  c_void  { 
124+ pub  unsafe   extern  "C"  fn  realloc ( ptr :  * mut  c_void ,  size :  usize )  -> * mut  c_void  { 
75125    if  ptr. is_null ( )  { 
76126        // If the pointer is null, treat as a malloc 
77-         return  hlmalloc ( size) ; 
127+         return  malloc ( size) ; 
128+     } 
129+ 
130+     if  size == 0  { 
131+         // If the size is 0, treat as a free and return null 
132+         free ( ptr) ; 
133+         return  ptr:: null_mut ( ) ; 
78134    } 
79135
80136    unsafe  { 
137+         let  total_new_size = size
138+             . checked_add ( size_of :: < Layout > ( ) ) 
139+             . expect ( "data and layout size should not overflow in realloc" ) ; 
140+ 
81141        let  block_start = ( ptr as  * const  Layout ) . sub ( 1 ) ; 
82-         let  layout = block_start. read ( ) ; 
83-         let  total_new_size = size + size_of :: < Layout > ( ) ; 
142+         let  old_layout = block_start. read ( ) ; 
143+         let  new_layout = Layout :: from_size_align ( total_new_size,  align_of :: < usize > ( ) ) . unwrap ( ) ; 
144+         
84145        let  new_block_start =
85-             alloc:: alloc:: realloc ( block_start as  * mut  u8 ,  layout,  total_new_size)  as  * mut  Layout ; 
146+             alloc:: alloc:: realloc ( block_start as  * mut  u8 ,  old_layout,  total_new_size) 
147+                 as  * mut  Layout ; 
86148
87149        if  new_block_start. is_null ( )  { 
88150            // Realloc failed 
89151            abort_with_code ( ErrorCode :: MallocFailed  as  i32 ) ; 
90152        }  else  { 
91-             // Return  the pointer just  after the layout information  
92-             // since old layout should still as it would have been copied 
153+             // Update  the stored Layout, then return ptr to memory right  after the Layout.  
154+             new_block_start . write ( new_layout ) ; 
93155            new_block_start. add ( 1 )  as  * mut  c_void 
94156        } 
95157    } 
0 commit comments