@@ -127,6 +127,128 @@ pub use alloc_crate::alloc::*;
127
127
#[ derive( Debug , Default , Copy , Clone ) ]
128
128
pub struct System ;
129
129
130
+ use crate :: sys:: alloc:: System as Imp ;
131
+
132
+ // When debug assertions are not enabled, `System` just forwards down to the particular platform
133
+ // implementation.
134
+ #[ cfg( not( debug_assertions) ) ]
135
+ #[ stable( feature = "alloc_system_type" , since = "1.28.0" ) ]
136
+ unsafe impl GlobalAlloc for System {
137
+ #[ inline]
138
+ unsafe fn alloc ( & self , layout : Layout ) -> * mut u8 {
139
+ unsafe { Imp . alloc ( layout) }
140
+ }
141
+
142
+ #[ inline]
143
+ unsafe fn alloc_zeroed ( & self , layout : Layout ) -> * mut u8 {
144
+ unsafe { Imp . alloc_zeroed ( layout) }
145
+ }
146
+
147
+ #[ inline]
148
+ unsafe fn dealloc ( & self , ptr : * mut u8 , layout : Layout ) {
149
+ unsafe { Imp . dealloc ( ptr, layout) }
150
+ }
151
+
152
+ #[ inline]
153
+ unsafe fn realloc ( & self , ptr : * mut u8 , layout : Layout , new_size : usize ) -> * mut u8 {
154
+ unsafe { Imp . realloc ( ptr, layout, new_size) }
155
+ }
156
+ }
157
+
158
+ // Some system allocators (most notably any provided by calling malloc) will always return pointers
159
+ // with an alignment of 8. So for any allocation with an alignment less than 8, we increase the
160
+ // alignment to 8 and return a pointer which is offset into the allocation such that it is not
161
+ // over-aligned.
162
+ // We always bump up the size of an allocation by 8 when the alignment is less than 8.
163
+ #[ cfg( debug_assertions) ]
164
+ trait LayoutExt {
165
+ fn with_alignment_padding ( self ) -> Self ;
166
+ unsafe fn add_alignment_padding ( self , ptr : * mut u8 ) -> * mut u8 ;
167
+ unsafe fn remove_alignment_padding ( self , ptr : * mut u8 ) -> * mut u8 ;
168
+ }
169
+ #[ cfg( debug_assertions) ]
170
+ impl LayoutExt for Layout {
171
+ fn with_alignment_padding ( self ) -> Self {
172
+ if self . align ( ) < 8 {
173
+ Layout :: from_size_align ( self . size ( ) + ( 8 - self . align ( ) ) , 8 ) . unwrap ( )
174
+ } else {
175
+ self
176
+ }
177
+ }
178
+
179
+ unsafe fn add_alignment_padding ( self , ptr : * mut u8 ) -> * mut u8 {
180
+ if !ptr. is_null ( ) && self . align ( ) < 8 {
181
+ // SAFETY: This must be called on a pointer previously returned by a padded Layout,
182
+ // which will always have space to do this offset
183
+ unsafe { ptr. add ( 8 - self . align ( ) ) }
184
+ } else {
185
+ ptr
186
+ }
187
+ }
188
+
189
+ unsafe fn remove_alignment_padding ( self , ptr : * mut u8 ) -> * mut u8 {
190
+ // We cannot just do the inverse of add_alignment_padding, because if a user deallocates
191
+ // with the wrong Layout, we would use that wrong Layout here to deduce the wrong offset to
192
+ // remove from the pointer. That would turn code that works fine because the underlying
193
+ // allocator ignores the Layout (but is technically UB) into code which does worse UB or
194
+ // halts the program with an unhelpful diagnostic from the underlying allocator.
195
+ // So we have two reasonable options. We could detect and clearly report the error
196
+ // ourselves, or since we know that all our alignment adjustments involve the low 3 bits,
197
+ // we could clear those and make this allocator transparent.
198
+ // At the moment we do the latter because it is unclear how to emit an error message from
199
+ // inside an allocator.
200
+ const ALIGNMENT_MASK : usize = usize:: MAX << 3 ;
201
+ ptr. map_addr ( |addr| addr & ALIGNMENT_MASK )
202
+ }
203
+ }
204
+
205
+ // When debug assertions are enabled, we wrap the platform allocator with extra logic to help
206
+ // expose bugs.
207
+ #[ cfg( debug_assertions) ]
208
+ #[ stable( feature = "alloc_system_type" , since = "1.28.0" ) ]
209
+ unsafe impl GlobalAlloc for System {
210
+ #[ inline]
211
+ unsafe fn alloc ( & self , layout : Layout ) -> * mut u8 {
212
+ if layout. size ( ) > isize:: MAX as usize - 8 {
213
+ return ptr:: null_mut ( ) ;
214
+ }
215
+ unsafe {
216
+ let ptr = Imp . alloc ( layout. with_alignment_padding ( ) ) ;
217
+ layout. add_alignment_padding ( ptr)
218
+ }
219
+ }
220
+
221
+ #[ inline]
222
+ unsafe fn alloc_zeroed ( & self , layout : Layout ) -> * mut u8 {
223
+ unsafe {
224
+ let ptr = Imp . alloc_zeroed ( layout. with_alignment_padding ( ) ) ;
225
+ layout. add_alignment_padding ( ptr)
226
+ }
227
+ }
228
+
229
+ #[ inline]
230
+ unsafe fn dealloc ( & self , ptr : * mut u8 , layout : Layout ) {
231
+ unsafe {
232
+ let ptr = layout. remove_alignment_padding ( ptr) ;
233
+ Imp . dealloc ( ptr, layout. with_alignment_padding ( ) )
234
+ }
235
+ }
236
+
237
+ #[ inline]
238
+ unsafe fn realloc ( & self , ptr : * mut u8 , layout : Layout , new_size : usize ) -> * mut u8 {
239
+ if new_size > isize:: MAX as usize - 8 {
240
+ return ptr:: null_mut ( ) ;
241
+ }
242
+ unsafe {
243
+ let ptr = layout. remove_alignment_padding ( ptr) ;
244
+ let new_layout =
245
+ Layout :: from_size_align ( new_size, layout. align ( ) ) . unwrap ( ) . with_alignment_padding ( ) ;
246
+ let ptr = Imp . realloc ( ptr, layout. with_alignment_padding ( ) , new_layout. size ( ) ) ;
247
+ layout. add_alignment_padding ( ptr)
248
+ }
249
+ }
250
+ }
251
+
130
252
impl System {
131
253
#[ inline]
132
254
fn alloc_impl ( & self , layout : Layout , zeroed : bool ) -> Result < NonNull < [ u8 ] > , AllocError > {
0 commit comments