Auto merge of #125580 - RalfJung:miri-sync, r=RalfJung · rust-lang/rust@cdc509f
@@ -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 {
30293130impl Drop for MiriAllocBytes {
3231fn 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}
57615862impl 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(
6467size: usize,
6568align: usize,
6669alloc_fn: impl FnOnce(Layout) -> *mut u8,
6770) -> Result<MiriAllocBytes, Layout> {
6871let 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 {
8587let slice = slice.into();
8688let size = slice.len();
8789let 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`.
8991let alloc_fn = |layout| unsafe { alloc::alloc(layout) };
9092let 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 {
98100fn zeroed(size: Size, align: Align) -> Option<Self> {
99101let size = size.bytes_usize();
100102let 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`.
102104let alloc_fn = |layout| unsafe { alloc::alloc_zeroed(layout) };
103105MiriAllocBytes::alloc_with(size, align, alloc_fn).ok()
104106}