1+ #![ deny( unsafe_op_in_unsafe_fn) ]
2+
13use crate :: alloc:: { GlobalAlloc , Layout , System } ;
24use crate :: sys:: c;
35use crate :: sys_common:: alloc:: { realloc_fallback, MIN_ALIGN } ;
@@ -6,56 +8,87 @@ use crate::sys_common::alloc::{realloc_fallback, MIN_ALIGN};
68struct Header ( * mut u8 ) ;
79
810unsafe fn get_header < ' a > ( ptr : * mut u8 ) -> & ' a mut Header {
9- & mut * ( ptr as * mut Header ) . offset ( -1 )
11+ // SAFETY: the safety contract must be upheld by the caller
12+ unsafe { & mut * ( ptr as * mut Header ) . offset ( -1 ) }
1013}
1114
1215unsafe fn align_ptr ( ptr : * mut u8 , align : usize ) -> * mut u8 {
13- let aligned = ptr. add ( align - ( ptr as usize & ( align - 1 ) ) ) ;
14- * get_header ( aligned) = Header ( ptr) ;
15- aligned
16+ // SAFETY: the safety contract must be upheld by the caller
17+ unsafe {
18+ let aligned = ptr. add ( align - ( ptr as usize & ( align - 1 ) ) ) ;
19+ * get_header ( aligned) = Header ( ptr) ;
20+ aligned
21+ }
1622}
1723
1824#[ inline]
1925unsafe fn allocate_with_flags ( layout : Layout , flags : c:: DWORD ) -> * mut u8 {
2026 if layout. align ( ) <= MIN_ALIGN {
21- return c:: HeapAlloc ( c:: GetProcessHeap ( ) , flags, layout. size ( ) ) as * mut u8 ;
27+ // SAFETY: `layout.size()` comes from `Layout` and is valid.
28+ return unsafe { c:: HeapAlloc ( c:: GetProcessHeap ( ) , flags, layout. size ( ) ) as * mut u8 } ;
2229 }
2330
24- let size = layout. size ( ) + layout. align ( ) ;
25- let ptr = c:: HeapAlloc ( c:: GetProcessHeap ( ) , flags, size) ;
26- if ptr. is_null ( ) { ptr as * mut u8 } else { align_ptr ( ptr as * mut u8 , layout. align ( ) ) }
31+ let ptr = unsafe {
32+ // SAFETY: The caller must ensure that
33+ // `layout.size()` + `layout.size()` does not overflow.
34+ let size = layout. size ( ) + layout. align ( ) ;
35+ c:: HeapAlloc ( c:: GetProcessHeap ( ) , flags, size)
36+ } ;
37+
38+ if ptr. is_null ( ) {
39+ ptr as * mut u8
40+ } else {
41+ // SAFETY: `ptr` is a valid pointer
42+ // with enough allocated space to store the header.
43+ unsafe { align_ptr ( ptr as * mut u8 , layout. align ( ) ) }
44+ }
2745}
2846
47+ // SAFETY: All methods implemented follow the contract rules defined
48+ // in `GlobalAlloc`.
2949#[ stable( feature = "alloc_system_type" , since = "1.28.0" ) ]
3050unsafe impl GlobalAlloc for System {
3151 #[ inline]
3252 unsafe fn alloc ( & self , layout : Layout ) -> * mut u8 {
33- allocate_with_flags ( layout, 0 )
53+ // SAFETY: the safety contract for `allocate_with_flags` must be upheld by the caller.
54+ unsafe { allocate_with_flags ( layout, 0 ) }
3455 }
3556
3657 #[ inline]
3758 unsafe fn alloc_zeroed ( & self , layout : Layout ) -> * mut u8 {
38- allocate_with_flags ( layout, c:: HEAP_ZERO_MEMORY )
59+ // SAFETY: the safety contract for `allocate_with_flags must be upheld by the caller.
60+ unsafe { allocate_with_flags ( layout, c:: HEAP_ZERO_MEMORY ) }
3961 }
4062
4163 #[ inline]
4264 unsafe fn dealloc ( & self , ptr : * mut u8 , layout : Layout ) {
43- if layout. align ( ) <= MIN_ALIGN {
44- let err = c:: HeapFree ( c:: GetProcessHeap ( ) , 0 , ptr as c:: LPVOID ) ;
45- debug_assert ! ( err != 0 , "Failed to free heap memory: {}" , c:: GetLastError ( ) ) ;
46- } else {
47- let header = get_header ( ptr) ;
48- let err = c:: HeapFree ( c:: GetProcessHeap ( ) , 0 , header. 0 as c:: LPVOID ) ;
49- debug_assert ! ( err != 0 , "Failed to free heap memory: {}" , c:: GetLastError ( ) ) ;
65+ // SAFETY: HeapFree is safe if ptr was allocated by this allocator
66+ let err = unsafe {
67+ if layout. align ( ) <= MIN_ALIGN {
68+ c:: HeapFree ( c:: GetProcessHeap ( ) , 0 , ptr as c:: LPVOID ) ;
69+ } else {
70+ let header = get_header ( ptr) ;
71+ c:: HeapFree ( c:: GetProcessHeap ( ) , 0 , header. 0 as c:: LPVOID ) ;
72+ }
5073 }
74+ debug_assert ! ( err != 0 , "Failed to free heap memory: {}" , c:: GetLastError ( ) ) ;
5175 }
5276
5377 #[ inline]
5478 unsafe fn realloc ( & self , ptr : * mut u8 , layout : Layout , new_size : usize ) -> * mut u8 {
55- if layout. align ( ) <= MIN_ALIGN {
56- c:: HeapReAlloc ( c:: GetProcessHeap ( ) , 0 , ptr as c:: LPVOID , new_size) as * mut u8
57- } else {
58- realloc_fallback ( self , ptr, layout, new_size)
79+ unsafe {
80+ if layout. align ( ) <= MIN_ALIGN {
81+ // SAFETY: HeapReAlloc is safe if ptr was allocated by this allocator
82+ // and new_size is not 0.
83+ unsafe {
84+ c:: HeapReAlloc ( c:: GetProcessHeap ( ) , 0 , ptr as c:: LPVOID , new_size) as * mut u8
85+ }
86+ } else {
87+ // SAFETY: The safety contract for `realloc_fallback` must be upheld by the caller
88+ unsafe {
89+ realloc_fallback ( self , ptr, layout, new_size)
90+ }
91+ }
5992 }
6093 }
6194}
0 commit comments