Skip to content

Commit 7fc41d1

Browse files
committed
Auto merge of #3625 - Strophox:miri-allocation-fix, r=RalfJung
Bugfix `MiriAllocBytes` to guarantee different addresses Fix in `alloc_bytes.rs` following rust-lang/miri#3526 Currently when an allocation of `size == 0` is requested we return a `std::ptr::without_provenance_mut(align)`, but this means returned `ptr`s may overlap, which breaks things.
2 parents 88d519f + b84620f commit 7fc41d1

2 files changed

Lines changed: 24 additions & 23 deletions

File tree

‎src/tools/miri/src/alloc_bytes.rs‎

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -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:*mutu8,
2120
}
@@ -30,10 +29,15 @@ impl Clone for MiriAllocBytes {
3029

3130
implDropforMiriAllocBytes{
3231
fndrop(&mutself){
33-
ifself.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 = ifself.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

5862
implMiriAllocBytes{
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
fnalloc_with(
6467
size:usize,
6568
align:usize,
6669
alloc_fn:implFnOnce(Layout) -> *mutu8,
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-
returnErr(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
fnzeroed(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
}

‎src/tools/miri/src/lib.rs‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
#![feature(lint_reasons)]
1414
#![feature(trait_upcasting)]
1515
#![feature(strict_overflow_ops)]
16-
#![feature(strict_provenance)]
1716
// Configure clippy and other lints
1817
#![allow(
1918
clippy::collapsible_else_if,

0 commit comments

Comments
 (0)