77use core:: alloc:: { GlobalAlloc , Layout } ;
88use core:: cell:: UnsafeCell ;
99use core:: mem:: { self , MaybeUninit } ;
10- use core:: ptr:: { NonNull , null_mut } ;
10+ use core:: ptr:: { null_mut , NonNull } ;
1111
1212#[ cfg( not( feature = "polyfill" ) ) ]
1313use core:: sync:: atomic:: { AtomicUsize , Ordering } ;
@@ -205,12 +205,13 @@ pub struct LeakError<T> {
205205/// };
206206///
207207/// let mut level: Level = BUMP.level();
208- /// let mut begin: *mut u64 ;
208+ /// let mut start: Level = BUMP.level() ;
209209/// let mut count;
210210///
211211/// match BUMP.leak_at(first, level) {
212- /// Ok((first, first_level)) => {
213- /// begin = first;
212+ /// Ok((_first, first_level)) => {
213+ /// // Note we must throw away the first pointer. Its provenance does not
214+ /// // cover the other fields. Only its level can be used.
214215/// level = first_level;
215216/// count = 1;
216217/// },
@@ -227,10 +228,12 @@ pub struct LeakError<T> {
227228/// });
228229///
229230/// unsafe {
231+ /// // Safety: we have an allocation here
232+ /// let begin = BUMP.get_unchecked(start);
230233/// // SAFETY: all `count` allocations are contiguous, begin is well aligned and no
231234/// // reference is currently pointing at any of the values. The lifetime is `'static` as
232235/// // the BUMP itself is static.
233- /// slice::from_raw_parts_mut(begin, count)
236+ /// slice::from_raw_parts_mut(begin.ptr.as_ptr() , count)
234237/// }
235238/// }
236239///
@@ -247,7 +250,7 @@ pub struct Level(pub(crate) usize);
247250///
248251/// [`Level`]: struct.Level.html
249252#[ derive( Clone , Copy , Debug , PartialEq , Eq , PartialOrd , Ord ) ]
250- pub struct Allocation < ' a , T = u8 > {
253+ pub struct Allocation < ' a , T = u8 > {
251254 /// Pointer to the uninitialized region with specified layout.
252255 pub ptr : NonNull < T > ,
253256
@@ -372,10 +375,12 @@ impl<T> Bump<T> {
372375 ///
373376 /// # Panics
374377 /// This function may panic if the provided `level` is from a different slab.
375- pub fn alloc_at ( & self , layout : Layout , level : Level )
376- -> Result < Allocation , Failure >
377- {
378- let Allocation { ptr, lifetime, level } = self . try_alloc_at ( layout, level. 0 ) ?;
378+ pub fn alloc_at ( & self , layout : Layout , level : Level ) -> Result < Allocation , Failure > {
379+ let Allocation {
380+ ptr,
381+ lifetime,
382+ level,
383+ } = self . try_alloc_at ( layout, level. 0 ) ?;
379384
380385 Ok ( Allocation {
381386 ptr : ptr. cast ( ) ,
@@ -390,9 +395,7 @@ impl<T> Bump<T> {
390395 /// bound by the lifetime of the reference to the allocator.
391396 ///
392397 /// [`Uninit`]: ../uninit/struct.Uninit.html
393- pub fn get_layout ( & self , layout : Layout )
394- -> Option < Allocation < ' _ > >
395- {
398+ pub fn get_layout ( & self , layout : Layout ) -> Option < Allocation < ' _ > > {
396399 self . try_alloc ( layout)
397400 }
398401
@@ -405,9 +408,7 @@ impl<T> Bump<T> {
405408 /// this allocation with the preceding or succeeding one.
406409 ///
407410 /// [`Uninit`]: ../uninit/struct.Uninit.html
408- pub fn get_layout_at ( & self , layout : Layout , at : Level )
409- -> Result < Allocation < ' _ > , Failure >
410- {
411+ pub fn get_layout_at ( & self , layout : Layout , at : Level ) -> Result < Allocation < ' _ > , Failure > {
411412 self . try_alloc_at ( layout, at. 0 )
412413 }
413414
@@ -438,7 +439,11 @@ impl<T> Bump<T> {
438439 }
439440
440441 let layout = Layout :: new :: < V > ( ) ;
441- let Allocation { ptr, lifetime, level, } = self . try_alloc ( layout) ?;
442+ let Allocation {
443+ ptr,
444+ lifetime,
445+ level,
446+ } = self . try_alloc ( layout) ?;
442447
443448 Some ( Allocation {
444449 ptr : ptr. cast ( ) ,
@@ -465,7 +470,11 @@ impl<T> Bump<T> {
465470 }
466471
467472 let layout = Layout :: new :: < V > ( ) ;
468- let Allocation { ptr, lifetime, level, } = self . try_alloc_at ( layout, level. 0 ) ?;
473+ let Allocation {
474+ ptr,
475+ lifetime,
476+ level,
477+ } = self . try_alloc_at ( layout, level. 0 ) ?;
469478
470479 Ok ( Allocation {
471480 // It has exactly size and alignment for `V` as requested.
@@ -531,9 +540,7 @@ impl<T> Bump<T> {
531540 /// ```
532541 pub fn leak_box < V > ( & self , val : V ) -> Option < LeakBox < ' _ , V > > {
533542 let Allocation { ptr, lifetime, .. } = self . get :: < V > ( ) ?;
534- Some ( unsafe {
535- LeakBox :: new_from_raw_non_null ( ptr, val, lifetime)
536- } )
543+ Some ( unsafe { LeakBox :: new_from_raw_non_null ( ptr, val, lifetime) } )
537544 }
538545
539546 /// Move a value into an owned allocation.
@@ -543,9 +550,7 @@ impl<T> Bump<T> {
543550 /// [`leak_box`]: #method.leak_box
544551 pub fn leak_box_at < V > ( & self , val : V , level : Level ) -> Result < LeakBox < ' _ , V > , Failure > {
545552 let Allocation { ptr, lifetime, .. } = self . get_at :: < V > ( level) ?;
546- Ok ( unsafe {
547- LeakBox :: new_from_raw_non_null ( ptr, val, lifetime)
548- } )
553+ Ok ( unsafe { LeakBox :: new_from_raw_non_null ( ptr, val, lifetime) } )
549554 }
550555
551556 /// Observe the current level.
@@ -558,16 +563,51 @@ impl<T> Bump<T> {
558563 Level ( self . consumed . load ( Ordering :: SeqCst ) )
559564 }
560565
561- fn try_alloc ( & self , layout : Layout )
562- -> Option < Allocation < ' _ > >
563- {
566+ /// Get a pointer to an existing allocation at a specific level.
567+ ///
568+ /// The resulting pointer may be used to access an arbitrary allocation starting at the pointer
569+ /// (i.e. including additional allocations immediately afterwards) but the caller is
570+ /// responsible for ensuring that these accesses do not overlap other accesses. There must be
571+ /// no more life [`LeakBox`] to any allocation being accessed this way.
572+ ///
573+ /// # Safety
574+ ///
575+ /// - The level must refer to an existing allocation, i.e. it must previously have been
576+ /// returned in [`Allocation::level`].
577+ /// - As a corollary, particular it must be in-bounds of the allocator's memory.
578+ /// - Another consequence, the result pointer must be aligned for the requested type.
579+ pub unsafe fn get_unchecked < V > ( & self , level : Level ) -> Allocation < ' _ , V > {
580+ debug_assert ! ( level. 0 <= mem:: size_of_val( & self . storage) ) ;
581+
582+ debug_assert ! (
583+ level <= self . level( ) ,
584+ "Tried to access an allocation that does not yet exist"
585+ ) ;
586+
587+ let base_ptr = self . storage . get ( ) as * mut T as * mut u8 ;
588+ let object = base_ptr. add ( level. 0 ) ;
589+ let nonnull = NonNull :: new_unchecked ( object) . cast :: < V > ( ) ;
590+
591+ debug_assert ! (
592+ nonnull. as_ptr( ) . is_aligned( ) ,
593+ "Tried to access an allocation with improper type"
594+ ) ;
595+
596+ Allocation {
597+ ptr : nonnull,
598+ lifetime : AllocTime :: default ( ) ,
599+ level,
600+ }
601+ }
602+
603+ fn try_alloc ( & self , layout : Layout ) -> Option < Allocation < ' _ > > {
564604 // Guess zero, this will fail when we try to access it and it isn't.
565605 let mut consumed = 0 ;
566606 loop {
567607 match self . try_alloc_at ( layout, consumed) {
568608 Ok ( alloc) => return Some ( alloc) ,
569609 Err ( Failure :: Exhausted ) => return None ,
570- Err ( Failure :: Mismatch { observed } ) => consumed = observed. 0 ,
610+ Err ( Failure :: Mismatch { observed } ) => consumed = observed. 0 ,
571611 }
572612 }
573613 }
@@ -580,14 +620,14 @@ impl<T> Bump<T> {
580620 ///
581621 /// # Panics
582622 /// This function panics if `expect_consumed` is larger than `length`.
583- fn try_alloc_at ( & self , layout : Layout , expect_consumed : usize )
584- -> Result < Allocation < ' _ > , Failure >
585- {
623+ fn try_alloc_at (
624+ & self ,
625+ layout : Layout ,
626+ expect_consumed : usize ,
627+ ) -> Result < Allocation < ' _ > , Failure > {
586628 assert ! ( layout. size( ) > 0 ) ;
587629 let length = mem:: size_of :: < T > ( ) ;
588- let base_ptr = self . storage . get ( )
589- as * mut T
590- as * mut u8 ;
630+ let base_ptr = self . storage . get ( ) as * mut T as * mut u8 ;
591631
592632 let alignment = layout. align ( ) ;
593633 let requested = layout. size ( ) ;
@@ -620,8 +660,10 @@ impl<T> Bump<T> {
620660 Ok ( ( ) ) => ( ) ,
621661 Err ( observed) => {
622662 // Someone else was faster, if you want it then recalculate again.
623- return Err ( Failure :: Mismatch { observed : Level ( observed) } ) ;
624- } ,
663+ return Err ( Failure :: Mismatch {
664+ observed : Level ( observed) ,
665+ } ) ;
666+ }
625667 }
626668
627669 let aligned = unsafe {
@@ -741,9 +783,7 @@ impl<T> Bump<T> {
741783 /// resource on failure.
742784 ///
743785 // #[deprecated = "Use leak_box_at and initialize it with the value. This does not move the value in the failure case."]
744- pub fn leak_at < V > ( & self , val : V , level : Level )
745- -> Result < ( & mut V , Level ) , LeakError < V > >
746- {
786+ pub fn leak_at < V > ( & self , val : V , level : Level ) -> Result < ( & mut V , Level ) , LeakError < V > > {
747787 let alloc = match self . get_at :: < V > ( level) {
748788 Ok ( alloc) => alloc,
749789 Err ( err) => return Err ( LeakError :: new ( val, err) ) ,
@@ -777,12 +817,14 @@ impl<T> Bump<T> {
777817 assert ! ( expect_consumed <= new_consumed) ;
778818 assert ! ( new_consumed <= mem:: size_of:: <T >( ) ) ;
779819
780- self . consumed . compare_exchange (
781- expect_consumed,
782- new_consumed,
783- Ordering :: SeqCst ,
784- Ordering :: SeqCst ,
785- ) . map ( drop)
820+ self . consumed
821+ . compare_exchange (
822+ expect_consumed,
823+ new_consumed,
824+ Ordering :: SeqCst ,
825+ Ordering :: SeqCst ,
826+ )
827+ . map ( drop)
786828 }
787829}
788830
@@ -844,14 +886,14 @@ impl<'alloc, T> Allocation<'alloc, T> {
844886 Allocation {
845887 ptr : NonNull :: from ( alloc) . cast ( ) ,
846888 lifetime : AllocTime :: default ( ) ,
847- level : level ,
889+ level,
848890 }
849891 }
850892}
851893
852894impl < T > LeakError < T > {
853895 fn new ( val : T , failure : Failure ) -> Self {
854- LeakError { val, failure, }
896+ LeakError { val, failure }
855897 }
856898
857899 /// Inspect the cause of this error.
@@ -866,7 +908,7 @@ impl<T> LeakError<T> {
866908}
867909
868910// SAFETY: at most one thread gets a pointer to each chunk of data.
869- unsafe impl < T > Sync for Bump < T > { }
911+ unsafe impl < T > Sync for Bump < T > { }
870912
871913unsafe impl < T > GlobalAlloc for Bump < T > {
872914 unsafe fn alloc ( & self , layout : Layout ) -> * mut u8 {
@@ -875,12 +917,7 @@ unsafe impl<T> GlobalAlloc for Bump<T> {
875917 . unwrap_or_else ( null_mut)
876918 }
877919
878- unsafe fn realloc (
879- & self ,
880- ptr : * mut u8 ,
881- current : Layout ,
882- new_size : usize ,
883- ) -> * mut u8 {
920+ unsafe fn realloc ( & self , ptr : * mut u8 , current : Layout , new_size : usize ) -> * mut u8 {
884921 let current = NonZeroLayout :: from_layout ( current. into ( ) ) . unwrap ( ) ;
885922 // As guaranteed, `new_size` is greater than 0.
886923 let new_size = core:: num:: NonZeroUsize :: new_unchecked ( new_size) ;
@@ -907,23 +944,22 @@ unsafe impl<T> GlobalAlloc for Bump<T> {
907944 }
908945}
909946
910- fn layout_reallocated ( layout : NonZeroLayout , target : core:: num:: NonZeroUsize )
911- -> Option < NonZeroLayout >
912- {
947+ fn layout_reallocated (
948+ layout : NonZeroLayout ,
949+ target : core:: num:: NonZeroUsize ,
950+ ) -> Option < NonZeroLayout > {
913951 // This may not be a valid layout.
914952 let layout = Layout :: from_size_align ( target. get ( ) , layout. align ( ) ) . ok ( ) ?;
915953 // This must succeed though, as the size was non-zero.
916954 Some ( NonZeroLayout :: from_layout ( layout. into ( ) ) . unwrap ( ) )
917955}
918956
919957unsafe impl < ' alloc , T > LocalAlloc < ' alloc > for Bump < T > {
920- fn alloc ( & ' alloc self , layout : NonZeroLayout )
921- -> Option < alloc_traits:: Allocation < ' alloc > >
922- {
958+ fn alloc ( & ' alloc self , layout : NonZeroLayout ) -> Option < alloc_traits:: Allocation < ' alloc > > {
923959 let raw_alloc = Bump :: get_layout ( self , layout. into ( ) ) ?;
924960 Some ( alloc_traits:: Allocation {
925961 ptr : raw_alloc. ptr ,
926- layout : layout ,
962+ layout,
927963 lifetime : AllocTime :: default ( ) ,
928964 } )
929965 }
@@ -945,8 +981,7 @@ unsafe impl<'alloc, T> LocalAlloc<'alloc> for Bump<T> {
945981 alloc : alloc_traits:: Allocation < ' alloc > ,
946982 layout : NonZeroLayout ,
947983 ) -> Option < alloc_traits:: Allocation < ' alloc > > {
948- if alloc. ptr . as_ptr ( ) as usize % layout. align ( ) == 0
949- && alloc. layout . size ( ) >= layout. size ( )
984+ if alloc. ptr . as_ptr ( ) as usize % layout. align ( ) == 0 && alloc. layout . size ( ) >= layout. size ( )
950985 {
951986 // Obvious fit, nothing to do.
952987 return Some ( alloc_traits:: Allocation {
@@ -963,7 +998,8 @@ unsafe impl<'alloc, T> LocalAlloc<'alloc> for Bump<T> {
963998 core:: ptr:: copy_nonoverlapping (
964999 alloc. ptr . as_ptr ( ) ,
9651000 new_alloc. ptr . as_ptr ( ) ,
966- layout. size ( ) . min ( alloc. layout . size ( ) ) . into ( ) ) ;
1001+ layout. size ( ) . min ( alloc. layout . size ( ) ) . into ( ) ,
1002+ ) ;
9671003 // No dealloc.
9681004 return Some ( new_alloc) ;
9691005 }
0 commit comments