7
7
use core:: alloc:: { GlobalAlloc , Layout } ;
8
8
use core:: cell:: UnsafeCell ;
9
9
use core:: mem:: { self , MaybeUninit } ;
10
- use core:: ptr:: { NonNull , null_mut } ;
10
+ use core:: ptr:: { null_mut , NonNull } ;
11
11
12
12
#[ cfg( not( feature = "polyfill" ) ) ]
13
13
use core:: sync:: atomic:: { AtomicUsize , Ordering } ;
@@ -205,12 +205,13 @@ pub struct LeakError<T> {
205
205
/// };
206
206
///
207
207
/// let mut level: Level = BUMP.level();
208
- /// let mut begin: *mut u64 ;
208
+ /// let mut start: Level = BUMP.level() ;
209
209
/// let mut count;
210
210
///
211
211
/// 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.
214
215
/// level = first_level;
215
216
/// count = 1;
216
217
/// },
@@ -227,10 +228,12 @@ pub struct LeakError<T> {
227
228
/// });
228
229
///
229
230
/// unsafe {
231
+ /// // Safety: we have an allocation here
232
+ /// let begin = BUMP.get_unchecked(start);
230
233
/// // SAFETY: all `count` allocations are contiguous, begin is well aligned and no
231
234
/// // reference is currently pointing at any of the values. The lifetime is `'static` as
232
235
/// // the BUMP itself is static.
233
- /// slice::from_raw_parts_mut(begin, count)
236
+ /// slice::from_raw_parts_mut(begin.ptr.as_ptr() , count)
234
237
/// }
235
238
/// }
236
239
///
@@ -247,7 +250,7 @@ pub struct Level(pub(crate) usize);
247
250
///
248
251
/// [`Level`]: struct.Level.html
249
252
#[ derive( Clone , Copy , Debug , PartialEq , Eq , PartialOrd , Ord ) ]
250
- pub struct Allocation < ' a , T = u8 > {
253
+ pub struct Allocation < ' a , T = u8 > {
251
254
/// Pointer to the uninitialized region with specified layout.
252
255
pub ptr : NonNull < T > ,
253
256
@@ -372,10 +375,12 @@ impl<T> Bump<T> {
372
375
///
373
376
/// # Panics
374
377
/// 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 ) ?;
379
384
380
385
Ok ( Allocation {
381
386
ptr : ptr. cast ( ) ,
@@ -390,9 +395,7 @@ impl<T> Bump<T> {
390
395
/// bound by the lifetime of the reference to the allocator.
391
396
///
392
397
/// [`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 < ' _ > > {
396
399
self . try_alloc ( layout)
397
400
}
398
401
@@ -405,9 +408,7 @@ impl<T> Bump<T> {
405
408
/// this allocation with the preceding or succeeding one.
406
409
///
407
410
/// [`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 > {
411
412
self . try_alloc_at ( layout, at. 0 )
412
413
}
413
414
@@ -438,7 +439,11 @@ impl<T> Bump<T> {
438
439
}
439
440
440
441
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) ?;
442
447
443
448
Some ( Allocation {
444
449
ptr : ptr. cast ( ) ,
@@ -465,7 +470,11 @@ impl<T> Bump<T> {
465
470
}
466
471
467
472
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 ) ?;
469
478
470
479
Ok ( Allocation {
471
480
// It has exactly size and alignment for `V` as requested.
@@ -531,9 +540,7 @@ impl<T> Bump<T> {
531
540
/// ```
532
541
pub fn leak_box < V > ( & self , val : V ) -> Option < LeakBox < ' _ , V > > {
533
542
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) } )
537
544
}
538
545
539
546
/// Move a value into an owned allocation.
@@ -543,9 +550,7 @@ impl<T> Bump<T> {
543
550
/// [`leak_box`]: #method.leak_box
544
551
pub fn leak_box_at < V > ( & self , val : V , level : Level ) -> Result < LeakBox < ' _ , V > , Failure > {
545
552
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) } )
549
554
}
550
555
551
556
/// Observe the current level.
@@ -558,16 +563,51 @@ impl<T> Bump<T> {
558
563
Level ( self . consumed . load ( Ordering :: SeqCst ) )
559
564
}
560
565
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 < ' _ > > {
564
604
// Guess zero, this will fail when we try to access it and it isn't.
565
605
let mut consumed = 0 ;
566
606
loop {
567
607
match self . try_alloc_at ( layout, consumed) {
568
608
Ok ( alloc) => return Some ( alloc) ,
569
609
Err ( Failure :: Exhausted ) => return None ,
570
- Err ( Failure :: Mismatch { observed } ) => consumed = observed. 0 ,
610
+ Err ( Failure :: Mismatch { observed } ) => consumed = observed. 0 ,
571
611
}
572
612
}
573
613
}
@@ -580,14 +620,14 @@ impl<T> Bump<T> {
580
620
///
581
621
/// # Panics
582
622
/// 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 > {
586
628
assert ! ( layout. size( ) > 0 ) ;
587
629
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 ;
591
631
592
632
let alignment = layout. align ( ) ;
593
633
let requested = layout. size ( ) ;
@@ -620,8 +660,10 @@ impl<T> Bump<T> {
620
660
Ok ( ( ) ) => ( ) ,
621
661
Err ( observed) => {
622
662
// 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
+ }
625
667
}
626
668
627
669
let aligned = unsafe {
@@ -741,9 +783,7 @@ impl<T> Bump<T> {
741
783
/// resource on failure.
742
784
///
743
785
// #[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 > > {
747
787
let alloc = match self . get_at :: < V > ( level) {
748
788
Ok ( alloc) => alloc,
749
789
Err ( err) => return Err ( LeakError :: new ( val, err) ) ,
@@ -777,12 +817,14 @@ impl<T> Bump<T> {
777
817
assert ! ( expect_consumed <= new_consumed) ;
778
818
assert ! ( new_consumed <= mem:: size_of:: <T >( ) ) ;
779
819
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)
786
828
}
787
829
}
788
830
@@ -844,14 +886,14 @@ impl<'alloc, T> Allocation<'alloc, T> {
844
886
Allocation {
845
887
ptr : NonNull :: from ( alloc) . cast ( ) ,
846
888
lifetime : AllocTime :: default ( ) ,
847
- level : level ,
889
+ level,
848
890
}
849
891
}
850
892
}
851
893
852
894
impl < T > LeakError < T > {
853
895
fn new ( val : T , failure : Failure ) -> Self {
854
- LeakError { val, failure, }
896
+ LeakError { val, failure }
855
897
}
856
898
857
899
/// Inspect the cause of this error.
@@ -866,7 +908,7 @@ impl<T> LeakError<T> {
866
908
}
867
909
868
910
// 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 > { }
870
912
871
913
unsafe impl < T > GlobalAlloc for Bump < T > {
872
914
unsafe fn alloc ( & self , layout : Layout ) -> * mut u8 {
@@ -875,12 +917,7 @@ unsafe impl<T> GlobalAlloc for Bump<T> {
875
917
. unwrap_or_else ( null_mut)
876
918
}
877
919
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 {
884
921
let current = NonZeroLayout :: from_layout ( current. into ( ) ) . unwrap ( ) ;
885
922
// As guaranteed, `new_size` is greater than 0.
886
923
let new_size = core:: num:: NonZeroUsize :: new_unchecked ( new_size) ;
@@ -907,23 +944,22 @@ unsafe impl<T> GlobalAlloc for Bump<T> {
907
944
}
908
945
}
909
946
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 > {
913
951
// This may not be a valid layout.
914
952
let layout = Layout :: from_size_align ( target. get ( ) , layout. align ( ) ) . ok ( ) ?;
915
953
// This must succeed though, as the size was non-zero.
916
954
Some ( NonZeroLayout :: from_layout ( layout. into ( ) ) . unwrap ( ) )
917
955
}
918
956
919
957
unsafe 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 > > {
923
959
let raw_alloc = Bump :: get_layout ( self , layout. into ( ) ) ?;
924
960
Some ( alloc_traits:: Allocation {
925
961
ptr : raw_alloc. ptr ,
926
- layout : layout ,
962
+ layout,
927
963
lifetime : AllocTime :: default ( ) ,
928
964
} )
929
965
}
@@ -945,8 +981,7 @@ unsafe impl<'alloc, T> LocalAlloc<'alloc> for Bump<T> {
945
981
alloc : alloc_traits:: Allocation < ' alloc > ,
946
982
layout : NonZeroLayout ,
947
983
) -> 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 ( )
950
985
{
951
986
// Obvious fit, nothing to do.
952
987
return Some ( alloc_traits:: Allocation {
@@ -963,7 +998,8 @@ unsafe impl<'alloc, T> LocalAlloc<'alloc> for Bump<T> {
963
998
core:: ptr:: copy_nonoverlapping (
964
999
alloc. ptr . as_ptr ( ) ,
965
1000
new_alloc. ptr . as_ptr ( ) ,
966
- layout. size ( ) . min ( alloc. layout . size ( ) ) . into ( ) ) ;
1001
+ layout. size ( ) . min ( alloc. layout . size ( ) ) . into ( ) ,
1002
+ ) ;
967
1003
// No dealloc.
968
1004
return Some ( new_alloc) ;
969
1005
}
0 commit comments