Skip to content

Enforce that layout size fits in isize in Layout #95295

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jul 10, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 38 additions & 88 deletions library/alloc/tests/string.rs
Original file line number Diff line number Diff line change
@@ -693,12 +693,6 @@ fn test_try_reserve() {
const MAX_CAP: usize = isize::MAX as usize;
const MAX_USIZE: usize = usize::MAX;

// On 16/32-bit, we check that allocations don't exceed isize::MAX,
// on 64-bit, we assume the OS will give an OOM for such a ridiculous size.
// Any platform that succeeds for these requests is technically broken with
// ptr::offset because LLVM is the worst.
let guards_against_isize = usize::BITS < 64;

{
// Note: basic stuff is checked by test_reserve
let mut empty_string: String = String::new();
@@ -712,35 +706,19 @@ fn test_try_reserve() {
panic!("isize::MAX shouldn't trigger an overflow!");
}

if guards_against_isize {
// Check isize::MAX + 1 does count as overflow
assert_matches!(
empty_string.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()),
Err(CapacityOverflow),
"isize::MAX + 1 should trigger an overflow!"
);

// Check usize::MAX does count as overflow
assert_matches!(
empty_string.try_reserve(MAX_USIZE).map_err(|e| e.kind()),
Err(CapacityOverflow),
"usize::MAX should trigger an overflow!"
);
} else {
// Check isize::MAX + 1 is an OOM
assert_matches!(
empty_string.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()),
Err(AllocError { .. }),
"isize::MAX + 1 should trigger an OOM!"
);

// Check usize::MAX is an OOM
assert_matches!(
empty_string.try_reserve(MAX_USIZE).map_err(|e| e.kind()),
Err(AllocError { .. }),
"usize::MAX should trigger an OOM!"
);
}
// Check isize::MAX + 1 does count as overflow
assert_matches!(
empty_string.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()),
Err(CapacityOverflow),
"isize::MAX + 1 should trigger an overflow!"
);

// Check usize::MAX does count as overflow
assert_matches!(
empty_string.try_reserve(MAX_USIZE).map_err(|e| e.kind()),
Err(CapacityOverflow),
"usize::MAX should trigger an overflow!"
);
}

{
@@ -753,19 +731,13 @@ fn test_try_reserve() {
if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) {
panic!("isize::MAX shouldn't trigger an overflow!");
}
if guards_against_isize {
assert_matches!(
ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()),
Err(CapacityOverflow),
"isize::MAX + 1 should trigger an overflow!"
);
} else {
assert_matches!(
ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()),
Err(AllocError { .. }),
"isize::MAX + 1 should trigger an OOM!"
);
}

assert_matches!(
ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()),
Err(CapacityOverflow),
"isize::MAX + 1 should trigger an overflow!"
);

// Should always overflow in the add-to-len
assert_matches!(
ten_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()),
@@ -785,8 +757,6 @@ fn test_try_reserve_exact() {
const MAX_CAP: usize = isize::MAX as usize;
const MAX_USIZE: usize = usize::MAX;

let guards_against_isize = usize::BITS < 64;

{
let mut empty_string: String = String::new();

@@ -799,31 +769,17 @@ fn test_try_reserve_exact() {
panic!("isize::MAX shouldn't trigger an overflow!");
}

if guards_against_isize {
assert_matches!(
empty_string.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()),
Err(CapacityOverflow),
"isize::MAX + 1 should trigger an overflow!"
);

assert_matches!(
empty_string.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()),
Err(CapacityOverflow),
"usize::MAX should trigger an overflow!"
);
} else {
assert_matches!(
empty_string.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()),
Err(AllocError { .. }),
"isize::MAX + 1 should trigger an OOM!"
);

assert_matches!(
empty_string.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()),
Err(AllocError { .. }),
"usize::MAX should trigger an OOM!"
);
}
assert_matches!(
empty_string.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()),
Err(CapacityOverflow),
"isize::MAX + 1 should trigger an overflow!"
);

assert_matches!(
empty_string.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()),
Err(CapacityOverflow),
"usize::MAX should trigger an overflow!"
);
}

{
@@ -839,19 +795,13 @@ fn test_try_reserve_exact() {
{
panic!("isize::MAX shouldn't trigger an overflow!");
}
if guards_against_isize {
assert_matches!(
ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()),
Err(CapacityOverflow),
"isize::MAX + 1 should trigger an overflow!"
);
} else {
assert_matches!(
ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()),
Err(AllocError { .. }),
"isize::MAX + 1 should trigger an OOM!"
);
}

assert_matches!(
ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()),
Err(CapacityOverflow),
"isize::MAX + 1 should trigger an overflow!"
);

assert_matches!(
ten_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()),
Err(CapacityOverflow),
166 changes: 52 additions & 114 deletions library/alloc/tests/vec.rs
Original file line number Diff line number Diff line change
@@ -1489,12 +1489,6 @@ fn test_try_reserve() {
const MAX_CAP: usize = isize::MAX as usize;
const MAX_USIZE: usize = usize::MAX;

// On 16/32-bit, we check that allocations don't exceed isize::MAX,
// on 64-bit, we assume the OS will give an OOM for such a ridiculous size.
// Any platform that succeeds for these requests is technically broken with
// ptr::offset because LLVM is the worst.
let guards_against_isize = usize::BITS < 64;

{
// Note: basic stuff is checked by test_reserve
let mut empty_bytes: Vec<u8> = Vec::new();
@@ -1508,35 +1502,19 @@ fn test_try_reserve() {
panic!("isize::MAX shouldn't trigger an overflow!");
}

if guards_against_isize {
// Check isize::MAX + 1 does count as overflow
assert_matches!(
empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()),
Err(CapacityOverflow),
"isize::MAX + 1 should trigger an overflow!"
);

// Check usize::MAX does count as overflow
assert_matches!(
empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()),
Err(CapacityOverflow),
"usize::MAX should trigger an overflow!"
);
} else {
// Check isize::MAX + 1 is an OOM
assert_matches!(
empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()),
Err(AllocError { .. }),
"isize::MAX + 1 should trigger an OOM!"
);

// Check usize::MAX is an OOM
assert_matches!(
empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()),
Err(AllocError { .. }),
"usize::MAX should trigger an OOM!"
);
}
// Check isize::MAX + 1 does count as overflow
assert_matches!(
empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()),
Err(CapacityOverflow),
"isize::MAX + 1 should trigger an overflow!"
);

// Check usize::MAX does count as overflow
assert_matches!(
empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()),
Err(CapacityOverflow),
"usize::MAX should trigger an overflow!"
);
}

{
@@ -1549,19 +1527,13 @@ fn test_try_reserve() {
if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) {
panic!("isize::MAX shouldn't trigger an overflow!");
}
if guards_against_isize {
assert_matches!(
ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()),
Err(CapacityOverflow),
"isize::MAX + 1 should trigger an overflow!"
);
} else {
assert_matches!(
ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()),
Err(AllocError { .. }),
"isize::MAX + 1 should trigger an OOM!"
);
}

assert_matches!(
ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()),
Err(CapacityOverflow),
"isize::MAX + 1 should trigger an overflow!"
);

// Should always overflow in the add-to-len
assert_matches!(
ten_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()),
@@ -1582,19 +1554,13 @@ fn test_try_reserve() {
{
panic!("isize::MAX shouldn't trigger an overflow!");
}
if guards_against_isize {
assert_matches!(
ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()),
Err(CapacityOverflow),
"isize::MAX + 1 should trigger an overflow!"
);
} else {
assert_matches!(
ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()),
Err(AllocError { .. }),
"isize::MAX + 1 should trigger an OOM!"
);
}

assert_matches!(
ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()),
Err(CapacityOverflow),
"isize::MAX + 1 should trigger an overflow!"
);

// Should fail in the mul-by-size
assert_matches!(
ten_u32s.try_reserve(MAX_USIZE - 20).map_err(|e| e.kind()),
@@ -1614,8 +1580,6 @@ fn test_try_reserve_exact() {
const MAX_CAP: usize = isize::MAX as usize;
const MAX_USIZE: usize = usize::MAX;

let guards_against_isize = size_of::<usize>() < 8;

{
let mut empty_bytes: Vec<u8> = Vec::new();

@@ -1628,31 +1592,17 @@ fn test_try_reserve_exact() {
panic!("isize::MAX shouldn't trigger an overflow!");
}

if guards_against_isize {
assert_matches!(
empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()),
Err(CapacityOverflow),
"isize::MAX + 1 should trigger an overflow!"
);

assert_matches!(
empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()),
Err(CapacityOverflow),
"usize::MAX should trigger an overflow!"
);
} else {
assert_matches!(
empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()),
Err(AllocError { .. }),
"isize::MAX + 1 should trigger an OOM!"
);

assert_matches!(
empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()),
Err(AllocError { .. }),
"usize::MAX should trigger an OOM!"
);
}
assert_matches!(
empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()),
Err(CapacityOverflow),
"isize::MAX + 1 should trigger an overflow!"
);

assert_matches!(
empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()),
Err(CapacityOverflow),
"usize::MAX should trigger an overflow!"
);
}

{
@@ -1668,19 +1618,13 @@ fn test_try_reserve_exact() {
{
panic!("isize::MAX shouldn't trigger an overflow!");
}
if guards_against_isize {
assert_matches!(
ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()),
Err(CapacityOverflow),
"isize::MAX + 1 should trigger an overflow!"
);
} else {
assert_matches!(
ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()),
Err(AllocError { .. }),
"isize::MAX + 1 should trigger an OOM!"
);
}

assert_matches!(
ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()),
Err(CapacityOverflow),
"isize::MAX + 1 should trigger an overflow!"
);

assert_matches!(
ten_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()),
Err(CapacityOverflow),
@@ -1701,19 +1645,13 @@ fn test_try_reserve_exact() {
{
panic!("isize::MAX shouldn't trigger an overflow!");
}
if guards_against_isize {
assert_matches!(
ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()),
Err(CapacityOverflow),
"isize::MAX + 1 should trigger an overflow!"
);
} else {
assert_matches!(
ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()),
Err(AllocError { .. }),
"isize::MAX + 1 should trigger an OOM!"
);
}

assert_matches!(
ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()),
Err(CapacityOverflow),
"isize::MAX + 1 should trigger an overflow!"
);

assert_matches!(
ten_u32s.try_reserve_exact(MAX_USIZE - 20).map_err(|e| e.kind()),
Err(CapacityOverflow),
161 changes: 52 additions & 109 deletions library/alloc/tests/vec_deque.rs
Original file line number Diff line number Diff line change
@@ -2,7 +2,6 @@ use std::assert_matches::assert_matches;
use std::collections::TryReserveErrorKind::*;
use std::collections::{vec_deque::Drain, VecDeque};
use std::fmt::Debug;
use std::mem::size_of;
use std::ops::Bound::*;
use std::panic::{catch_unwind, AssertUnwindSafe};

@@ -1161,12 +1160,6 @@ fn test_try_reserve() {
const MAX_CAP: usize = (isize::MAX as usize + 1) / 2 - 1;
const MAX_USIZE: usize = usize::MAX;

// On 16/32-bit, we check that allocations don't exceed isize::MAX,
// on 64-bit, we assume the OS will give an OOM for such a ridiculous size.
// Any platform that succeeds for these requests is technically broken with
// ptr::offset because LLVM is the worst.
let guards_against_isize = size_of::<usize>() < 8;

{
// Note: basic stuff is checked by test_reserve
let mut empty_bytes: VecDeque<u8> = VecDeque::new();
@@ -1180,31 +1173,19 @@ fn test_try_reserve() {
panic!("isize::MAX shouldn't trigger an overflow!");
}

if guards_against_isize {
// Check isize::MAX + 1 does count as overflow
assert_matches!(
empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()),
Err(CapacityOverflow),
"isize::MAX + 1 should trigger an overflow!"
);

// Check usize::MAX does count as overflow
assert_matches!(
empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()),
Err(CapacityOverflow),
"usize::MAX should trigger an overflow!"
);
} else {
// Check isize::MAX is an OOM
// VecDeque starts with capacity 7, always adds 1 to the capacity
// and also rounds the number to next power of 2 so this is the
// furthest we can go without triggering CapacityOverflow
assert_matches!(
empty_bytes.try_reserve(MAX_CAP).map_err(|e| e.kind()),
Err(AllocError { .. }),
"isize::MAX + 1 should trigger an OOM!"
);
}
// Check isize::MAX + 1 does count as overflow
assert_matches!(
empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()),
Err(CapacityOverflow),
"isize::MAX + 1 should trigger an overflow!"
);

// Check usize::MAX does count as overflow
assert_matches!(
empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()),
Err(CapacityOverflow),
"usize::MAX should trigger an overflow!"
);
}

{
@@ -1217,19 +1198,13 @@ fn test_try_reserve() {
if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) {
panic!("isize::MAX shouldn't trigger an overflow!");
}
if guards_against_isize {
assert_matches!(
ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()),
Err(CapacityOverflow),
"isize::MAX + 1 should trigger an overflow!"
);
} else {
assert_matches!(
ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()),
Err(AllocError { .. }),
"isize::MAX + 1 should trigger an OOM!"
);
}

assert_matches!(
ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()),
Err(CapacityOverflow),
"isize::MAX + 1 should trigger an overflow!"
);

// Should always overflow in the add-to-len
assert_matches!(
ten_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()),
@@ -1250,19 +1225,13 @@ fn test_try_reserve() {
{
panic!("isize::MAX shouldn't trigger an overflow!");
}
if guards_against_isize {
assert_matches!(
ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()),
Err(CapacityOverflow),
"isize::MAX + 1 should trigger an overflow!"
);
} else {
assert_matches!(
ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()),
Err(AllocError { .. }),
"isize::MAX + 1 should trigger an OOM!"
);
}

assert_matches!(
ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()),
Err(CapacityOverflow),
"isize::MAX + 1 should trigger an overflow!"
);

// Should fail in the mul-by-size
assert_matches!(
ten_u32s.try_reserve(MAX_USIZE - 20).map_err(|e| e.kind()),
@@ -1282,8 +1251,6 @@ fn test_try_reserve_exact() {
const MAX_CAP: usize = (isize::MAX as usize + 1) / 2 - 1;
const MAX_USIZE: usize = usize::MAX;

let guards_against_isize = size_of::<usize>() < 8;

{
let mut empty_bytes: VecDeque<u8> = VecDeque::new();

@@ -1296,29 +1263,17 @@ fn test_try_reserve_exact() {
panic!("isize::MAX shouldn't trigger an overflow!");
}

if guards_against_isize {
assert_matches!(
empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()),
Err(CapacityOverflow),
"isize::MAX + 1 should trigger an overflow!"
);

assert_matches!(
empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()),
Err(CapacityOverflow),
"usize::MAX should trigger an overflow!"
);
} else {
// Check isize::MAX is an OOM
// VecDeque starts with capacity 7, always adds 1 to the capacity
// and also rounds the number to next power of 2 so this is the
// furthest we can go without triggering CapacityOverflow
assert_matches!(
empty_bytes.try_reserve_exact(MAX_CAP).map_err(|e| e.kind()),
Err(AllocError { .. }),
"isize::MAX + 1 should trigger an OOM!"
);
}
assert_matches!(
empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()),
Err(CapacityOverflow),
"isize::MAX + 1 should trigger an overflow!"
);

assert_matches!(
empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()),
Err(CapacityOverflow),
"usize::MAX should trigger an overflow!"
);
}

{
@@ -1334,19 +1289,13 @@ fn test_try_reserve_exact() {
{
panic!("isize::MAX shouldn't trigger an overflow!");
}
if guards_against_isize {
assert_matches!(
ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()),
Err(CapacityOverflow),
"isize::MAX + 1 should trigger an overflow!"
);
} else {
assert_matches!(
ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()),
Err(AllocError { .. }),
"isize::MAX + 1 should trigger an OOM!"
);
}

assert_matches!(
ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()),
Err(CapacityOverflow),
"isize::MAX + 1 should trigger an overflow!"
);

assert_matches!(
ten_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()),
Err(CapacityOverflow),
@@ -1367,19 +1316,13 @@ fn test_try_reserve_exact() {
{
panic!("isize::MAX shouldn't trigger an overflow!");
}
if guards_against_isize {
assert_matches!(
ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()),
Err(CapacityOverflow),
"isize::MAX + 1 should trigger an overflow!"
);
} else {
assert_matches!(
ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()),
Err(AllocError { .. }),
"isize::MAX + 1 should trigger an OOM!"
);
}

assert_matches!(
ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()),
Err(CapacityOverflow),
"isize::MAX + 1 should trigger an overflow!"
);

assert_matches!(
ten_u32s.try_reserve_exact(MAX_USIZE - 20).map_err(|e| e.kind()),
Err(CapacityOverflow),
34 changes: 14 additions & 20 deletions library/core/src/alloc/layout.rs
Original file line number Diff line number Diff line change
@@ -53,8 +53,8 @@ impl Layout {
/// * `align` must be a power of two,
///
/// * `size`, when rounded up to the nearest multiple of `align`,
/// must not overflow (i.e., the rounded value must be less than
/// or equal to `usize::MAX`).
/// must not overflow isize (i.e., the rounded value must be
/// less than or equal to `isize::MAX`).
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[rustc_const_stable(feature = "const_alloc_layout", since = "1.50.0")]
#[inline]
@@ -77,7 +77,7 @@ impl Layout {
//
// Above implies that checking for summation overflow is both
// necessary and sufficient.
if size > usize::MAX - (align - 1) {
if size > isize::MAX as usize - (align - 1) {
return Err(LayoutError);
}

@@ -277,8 +277,8 @@ impl Layout {
let pad = self.padding_needed_for(self.align());
// This cannot overflow. Quoting from the invariant of Layout:
// > `size`, when rounded up to the nearest multiple of `align`,
// > must not overflow (i.e., the rounded value must be less than
// > `usize::MAX`)
// > must not overflow isize (i.e., the rounded value must be
// > less than or equal to `isize::MAX`)
let new_size = self.size() + pad;

// SAFETY: self.align is already known to be valid and new_size has been
@@ -299,14 +299,13 @@ impl Layout {
pub fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutError> {
// This cannot overflow. Quoting from the invariant of Layout:
// > `size`, when rounded up to the nearest multiple of `align`,
// > must not overflow (i.e., the rounded value must be less than
// > `usize::MAX`)
// > must not overflow isize (i.e., the rounded value must be
// > less than or equal to `isize::MAX`)
let padded_size = self.size() + self.padding_needed_for(self.align());
let alloc_size = padded_size.checked_mul(n).ok_or(LayoutError)?;

// SAFETY: self.align is already known to be valid and alloc_size has been
// padded already.
unsafe { Ok((Layout::from_size_align_unchecked(alloc_size, self.align()), padded_size)) }
// The safe constructor is called here to enforce the isize size limit.
Layout::from_size_align(alloc_size, self.align()).map(|layout| (layout, padded_size))
}

/// Creates a layout describing the record for `self` followed by
@@ -363,6 +362,7 @@ impl Layout {
let offset = self.size().checked_add(pad).ok_or(LayoutError)?;
let new_size = offset.checked_add(next.size()).ok_or(LayoutError)?;

// The safe constructor is called here to enforce the isize size limit.
let layout = Layout::from_size_align(new_size, new_align)?;
Ok((layout, offset))
}
@@ -383,6 +383,7 @@ impl Layout {
#[inline]
pub fn repeat_packed(&self, n: usize) -> Result<Self, LayoutError> {
let size = self.size().checked_mul(n).ok_or(LayoutError)?;
// The safe constructor is called here to enforce the isize size limit.
Layout::from_size_align(size, self.align())
}

@@ -396,6 +397,7 @@ impl Layout {
#[inline]
pub fn extend_packed(&self, next: Self) -> Result<Self, LayoutError> {
let new_size = self.size().checked_add(next.size()).ok_or(LayoutError)?;
// The safe constructor is called here to enforce the isize size limit.
Layout::from_size_align(new_size, self.align())
}

@@ -406,16 +408,8 @@ impl Layout {
#[inline]
pub fn array<T>(n: usize) -> Result<Self, LayoutError> {
let array_size = mem::size_of::<T>().checked_mul(n).ok_or(LayoutError)?;

// SAFETY:
// - Size: `array_size` cannot be too big because `size_of::<T>()` must
// be a multiple of `align_of::<T>()`. Therefore, `array_size`
// rounded up to the nearest multiple of `align_of::<T>()` is just
// `array_size`. And `array_size` cannot be too big because it was
// just checked by the `checked_mul()`.
// - Alignment: `align_of::<T>()` will always give an acceptable
// (non-zero, power of two) alignment.
Ok(unsafe { Layout::from_size_align_unchecked(array_size, mem::align_of::<T>()) })
// The safe constructor is called here to enforce the isize size limit.
Layout::from_size_align(array_size, mem::align_of::<T>())
}
}