@@ -127,6 +127,128 @@ pub use alloc_crate::alloc::*;
127127#[ derive( Debug , Default , Copy , Clone ) ]
128128pub struct System ;
129129
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+
130252impl System {
131253 #[ inline]
132254 fn alloc_impl ( & self , layout : Layout , zeroed : bool ) -> Result < NonNull < [ u8 ] > , AllocError > {
0 commit comments