Skip to content

Commit a511777

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 a511777

1 file changed

Lines changed: 91 additions & 0 deletions

File tree

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

0 commit comments

Comments
 (0)