@@ -14,8 +14,7 @@ pub struct MiriAllocBytes {
14
14
layout : alloc:: Layout ,
15
15
/// Pointer to the allocation contents.
16
16
/// 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.
19
18
/// * Otherwise, `self.ptr` points to memory allocated with `self.layout`.
20
19
ptr : * mut u8 ,
21
20
}
@@ -30,10 +29,15 @@ impl Clone for MiriAllocBytes {
30
29
31
30
impl Drop for MiriAllocBytes {
32
31
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) }
37
41
}
38
42
}
39
43
@@ -56,27 +60,25 @@ impl std::ops::DerefMut for MiriAllocBytes {
56
60
}
57
61
58
62
impl 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()`.
63
66
fn alloc_with (
64
67
size : usize ,
65
68
align : usize ,
66
69
alloc_fn : impl FnOnce ( Layout ) -> * mut u8 ,
67
70
) -> Result < MiriAllocBytes , Layout > {
68
71
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)
71
78
} 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
+ }
80
82
}
81
83
}
82
84
@@ -85,7 +87,7 @@ impl AllocBytes for MiriAllocBytes {
85
87
let slice = slice. into ( ) ;
86
88
let size = slice. len ( ) ;
87
89
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`.
89
91
let alloc_fn = |layout| unsafe { alloc:: alloc ( layout) } ;
90
92
let alloc_bytes = MiriAllocBytes :: alloc_with ( size, align, alloc_fn)
91
93
. unwrap_or_else ( |layout| alloc:: handle_alloc_error ( layout) ) ;
@@ -98,7 +100,7 @@ impl AllocBytes for MiriAllocBytes {
98
100
fn zeroed ( size : Size , align : Align ) -> Option < Self > {
99
101
let size = size. bytes_usize ( ) ;
100
102
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`.
102
104
let alloc_fn = |layout| unsafe { alloc:: alloc_zeroed ( layout) } ;
103
105
MiriAllocBytes :: alloc_with ( size, align, alloc_fn) . ok ( )
104
106
}
0 commit comments