Skip to content

Commit 2ef1d13

Browse files
authored
Rollup merge of rust-lang#83706 - a1phyr:fix_vec_layout_calculation, r=JohnTitor
Fix a layout possible miscalculation in `alloc::RawVec` A layout miscalculation could happen in `RawVec` when used with a type whose size isn't a multiple of its alignment. I don't know if such type can exist in Rust, but the Layout API provides ways to manipulate such types. Anyway, it is better to calculate memory size in a consistent way.
2 parents 6b20506 + 03498aa commit 2ef1d13

File tree

1 file changed

+12
-9
lines changed

1 file changed

+12
-9
lines changed

library/alloc/src/raw_vec.rs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -260,9 +260,7 @@ impl<T, A: Allocator> RawVec<T, A> {
260260
// We have an allocated chunk of memory, so we can bypass runtime
261261
// checks to get our current layout.
262262
unsafe {
263-
let align = mem::align_of::<T>();
264-
let size = mem::size_of::<T>() * self.cap;
265-
let layout = Layout::from_size_align_unchecked(size, align);
263+
let layout = Layout::array::<T>(self.cap).unwrap_unchecked();
266264
Some((self.ptr.cast().into(), layout))
267265
}
268266
}
@@ -404,7 +402,8 @@ impl<T, A: Allocator> RawVec<T, A> {
404402

405403
fn capacity_from_bytes(excess: usize) -> usize {
406404
debug_assert_ne!(mem::size_of::<T>(), 0);
407-
excess / mem::size_of::<T>()
405+
let size_of_item = Layout::new::<T>().pad_to_align().size();
406+
excess / size_of_item
408407
}
409408

410409
fn set_ptr(&mut self, ptr: NonNull<[u8]>) {
@@ -468,13 +467,17 @@ impl<T, A: Allocator> RawVec<T, A> {
468467
assert!(amount <= self.capacity(), "Tried to shrink to a larger capacity");
469468

470469
let (ptr, layout) = if let Some(mem) = self.current_memory() { mem } else { return Ok(()) };
471-
let new_size = amount * mem::size_of::<T>();
472470

473471
let ptr = unsafe {
474-
let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
475-
self.alloc
476-
.shrink(ptr, layout, new_layout)
477-
.map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })?
472+
// `Layout::array` cannot overflow here because it would have
473+
// owerflown earlier when capacity was larger.
474+
let new_layout = Layout::array::<T>(amount).unwrap_unchecked();
475+
// We avoid `map_err` here because it bloats the amount of LLVM IR
476+
// generated.
477+
match self.alloc.shrink(ptr, layout, new_layout) {
478+
Ok(ptr) => ptr,
479+
Err(_) => Err(AllocError { layout: new_layout, non_exhaustive: () })?,
480+
}
478481
};
479482
self.set_ptr(ptr);
480483
Ok(())

0 commit comments

Comments
 (0)