Skip to content

Commit acb99bb

Browse files
committed
test: Add a regression test for Apple platforms aborting on free
Add a regression test for RUST-150898 to make users aware that if this test failures, they may encounter unusual behavior elsewhere.
1 parent 36ba2c7 commit acb99bb

1 file changed

Lines changed: 90 additions & 0 deletions

File tree

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// Regression test for https://github.com/rust-lang/rust/issues/150898
2+
//
3+
// This test fails on Apple platforms with versions containing an allocator
4+
// bug. If this fails with SIGABRT, you may need to upgrade your system to
5+
// avoid other unexpected behavior.
6+
//
7+
// The bug was resolved by MacOS 26.4.
8+
9+
//@ run-pass
10+
//@ compile-flags: -C opt-level=1 -C lto=off -C codegen-units=1
11+
12+
use std::ffi::c_void;
13+
use std::hint::black_box;
14+
use std::mem::transmute;
15+
use std::ptr;
16+
17+
#[link(name = "System")]
18+
unsafe extern "C" {
19+
unsafe fn malloc(size: usize) -> *mut c_void;
20+
unsafe fn free(p: *mut c_void);
21+
}
22+
23+
// Probably needed to prevent the compiler from optimizing based on it being `malloc`.
24+
#[inline(never)]
25+
#[unsafe(no_mangle)]
26+
fn allocate(capacity: usize) -> *mut c_void {
27+
let size = capacity * size_of::<Reproducer>();
28+
let ptr = unsafe { malloc(size) };
29+
if ptr.is_null() {
30+
panic!("allocation failure")
31+
}
32+
ptr
33+
}
34+
35+
#[repr(u32)]
36+
#[derive(Clone)]
37+
pub enum ABC {
38+
A,
39+
B,
40+
C,
41+
}
42+
43+
type Reproducer = Option<(ABC, i64, u64)>;
44+
45+
#[inline(never)]
46+
#[unsafe(no_mangle)]
47+
fn extend_with(ptr: *mut c_void, len: *mut usize, n: usize, value: Reproducer) {
48+
let mut ptr = unsafe { ptr.cast::<Reproducer>().add(*len) };
49+
50+
for _ in 1..n {
51+
// Curiously must be `value.clone()`, doing a copy doesn't trigger the bug
52+
unsafe { ptr::write(ptr, value.clone()) };
53+
ptr = unsafe { ptr.add(1) };
54+
}
55+
56+
if n > 0 {
57+
unsafe { ptr::write(ptr, value) };
58+
}
59+
}
60+
61+
#[inline(never)]
62+
#[unsafe(no_mangle)]
63+
fn retv() -> Reproducer {
64+
// let x = [48, 0, 3, 1, 48, 0];
65+
let x = [0, 0, 3, 0, 0, 0];
66+
unsafe { transmute(x) }
67+
}
68+
69+
#[inline(never)]
70+
#[unsafe(no_mangle)]
71+
fn foo(size: usize) {
72+
let v0 = allocate(size);
73+
extend_with(v0, &mut 0, size, retv());
74+
unsafe { free(v0) };
75+
}
76+
77+
fn main() {
78+
for i in 0..50 {
79+
println!("step {i}");
80+
81+
let s = 128;
82+
// A few more allocations seem to be necessary, probably to prime
83+
// the allocator find the bug.
84+
let v1 = allocate(black_box(s));
85+
foo(black_box(s));
86+
unsafe { free(v1) };
87+
}
88+
89+
println!("finished");
90+
}

0 commit comments

Comments
 (0)