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 {

30293130

impl 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

}

57615862

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()`.

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

}