@@ -14,8 +14,7 @@ pub struct MiriAllocBytes {
1414 layout : alloc:: Layout ,
1515 /// Pointer to the allocation contents.
1616 /// Invariant:
17- /// * If `self.layout.size() == 0`, then `self.ptr` is some suitably aligned pointer
18- /// without provenance (and no actual memory was allocated).
17+ /// * If `self.layout.size() == 0`, then `self.ptr` was allocated with the equivalent layout with size 1.
1918 /// * Otherwise, `self.ptr` points to memory allocated with `self.layout`.
2019 ptr : * mut u8 ,
2120}
@@ -30,10 +29,15 @@ impl Clone for MiriAllocBytes {
3029
3130impl Drop for MiriAllocBytes {
3231 fn drop ( & mut self ) {
33- if self . layout . size ( ) != 0 {
34- // SAFETY: Invariant, `self.ptr` points to memory allocated with `self.layout`.
35- unsafe { alloc:: dealloc ( self . ptr , self . layout ) }
36- }
32+ // We have to reconstruct the actual layout used for allocation.
33+ // (`Deref` relies on `size` so we can't just always set it to at least 1.)
34+ let alloc_layout = if self . layout . size ( ) == 0 {
35+ Layout :: from_size_align ( 1 , self . layout . align ( ) ) . unwrap ( )
36+ } else {
37+ self . layout
38+ } ;
39+ // SAFETY: Invariant, `self.ptr` points to memory allocated with `self.layout`.
40+ unsafe { alloc:: dealloc ( self . ptr , alloc_layout) }
3741 }
3842}
3943
@@ -56,27 +60,25 @@ impl std::ops::DerefMut for MiriAllocBytes {
5660}
5761
5862impl MiriAllocBytes {
59- /// This method factors out how a `MiriAllocBytes` object is allocated,
60- /// specifically given an allocation function `alloc_fn`.
61- /// `alloc_fn` is only used if `size != 0`.
62- /// Returns `Err(layout)` if the allocation function returns a `ptr` that is `ptr.is_null()`.
63+ /// This method factors out how a `MiriAllocBytes` object is allocated, given a specific allocation function.
64+ /// If `size == 0` we allocate using a different `alloc_layout` with `size = 1`, to ensure each allocation has a unique address.
65+ /// Returns `Err(alloc_layout)` if the allocation function returns a `ptr` where `ptr.is_null()`.
6366 fn alloc_with (
6467 size : usize ,
6568 align : usize ,
6669 alloc_fn : impl FnOnce ( Layout ) -> * mut u8 ,
6770 ) -> Result < MiriAllocBytes , Layout > {
6871 let layout = Layout :: from_size_align ( size, align) . unwrap ( ) ;
69- let ptr = if size == 0 {
70- std:: ptr:: without_provenance_mut ( align)
72+ // When size is 0 we allocate 1 byte anyway, to ensure each allocation has a unique address.
73+ let alloc_layout =
74+ if size == 0 { Layout :: from_size_align ( 1 , align) . unwrap ( ) } else { layout } ;
75+ let ptr = alloc_fn ( alloc_layout) ;
76+ if ptr. is_null ( ) {
77+ Err ( alloc_layout)
7178 } else {
72- let ptr = alloc_fn ( layout) ;
73- if ptr. is_null ( ) {
74- return Err ( layout) ;
75- }
76- ptr
77- } ;
78- // SAFETY: All `MiriAllocBytes` invariants are fulfilled.
79- Ok ( Self { ptr, layout } )
79+ // SAFETY: All `MiriAllocBytes` invariants are fulfilled.
80+ Ok ( Self { ptr, layout } )
81+ }
8082 }
8183}
8284
@@ -85,7 +87,7 @@ impl AllocBytes for MiriAllocBytes {
8587 let slice = slice. into ( ) ;
8688 let size = slice. len ( ) ;
8789 let align = align. bytes_usize ( ) ;
88- // SAFETY: `alloc_fn` will only be used if `size != 0`.
90+ // SAFETY: `alloc_fn` will only be used with `size != 0`.
8991 let alloc_fn = |layout| unsafe { alloc:: alloc ( layout) } ;
9092 let alloc_bytes = MiriAllocBytes :: alloc_with ( size, align, alloc_fn)
9193 . unwrap_or_else ( |layout| alloc:: handle_alloc_error ( layout) ) ;
@@ -98,7 +100,7 @@ impl AllocBytes for MiriAllocBytes {
98100 fn zeroed ( size : Size , align : Align ) -> Option < Self > {
99101 let size = size. bytes_usize ( ) ;
100102 let align = align. bytes_usize ( ) ;
101- // SAFETY: `alloc_fn` will only be used if `size != 0`.
103+ // SAFETY: `alloc_fn` will only be used with `size != 0`.
102104 let alloc_fn = |layout| unsafe { alloc:: alloc_zeroed ( layout) } ;
103105 MiriAllocBytes :: alloc_with ( size, align, alloc_fn) . ok ( )
104106 }
0 commit comments