Skip to content

Commit aaa142a

Browse files
shahnMark-Simulacrum
authored andcommitted
Revert "Remove checked_add in Layout::repeat"
This fixes a a segfault in safe code, a stable regression. Reported in \rust-lang#69225. This reverts commit a983e05. Also adds a test for the expected behaviour.
1 parent 00b07c6 commit aaa142a

File tree

2 files changed

+38
-6
lines changed

2 files changed

+38
-6
lines changed

src/libcore/alloc.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -240,13 +240,14 @@ impl Layout {
240240
#[unstable(feature = "alloc_layout_extra", issue = "55724")]
241241
#[inline]
242242
pub fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutErr> {
243-
// This cannot overflow. Quoting from the invariant of Layout:
244-
// > `size`, when rounded up to the nearest multiple of `align`,
245-
// > must not overflow (i.e., the rounded value must be less than
246-
// > `usize::MAX`)
247-
let padded_size = self.size() + self.padding_needed_for(self.align());
248-
let alloc_size = padded_size.checked_mul(n)
243+
// Warning, removing the checked_add here led to segfaults in #67174. Further
244+
// analysis in #69225 seems to indicate that this is an LTO-related
245+
// miscompilation, so #67174 might be able to be reapplied in the future.
246+
let padded_size = self
247+
.size()
248+
.checked_add(self.padding_needed_for(self.align()))
249249
.ok_or(LayoutErr { private: () })?;
250+
let alloc_size = padded_size.checked_mul(n).ok_or(LayoutErr { private: () })?;
250251

251252
unsafe {
252253
// self.align is already known to be valid and alloc_size has been
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Ensure we appropriately error instead of overflowing a calculation when creating a new Alloc
2+
// Layout
3+
4+
// run-fail
5+
// compile-flags: -C opt-level=3
6+
// error-pattern: index out of bounds: the len is 0 but the index is 16777216
7+
// ignore-wasm no panic or subprocess support
8+
// ignore-emscripten no panic or subprocess support
9+
10+
fn do_test(x: usize) {
11+
let arr = vec![vec![0u8; 3]];
12+
13+
let mut z = Vec::new();
14+
for arr_ref in arr {
15+
for y in 0..x {
16+
for _ in 0..1 {
17+
z.extend(std::iter::repeat(0).take(x));
18+
let a = y * x;
19+
let b = (y + 1) * x - 1;
20+
let slice = &arr_ref[a..b];
21+
eprintln!("{} {} {} {}", a, b, arr_ref.len(), slice.len());
22+
eprintln!("{:?}", slice[1 << 24]);
23+
}
24+
}
25+
}
26+
}
27+
28+
fn main() {
29+
do_test(1);
30+
do_test(2);
31+
}

0 commit comments

Comments
 (0)