Skip to content

Commit 5ea21ca

Browse files
committed
support aligned_alloc for unixes support.
1 parent 7e5b9e2 commit 5ea21ca

File tree

6 files changed

+128
-0
lines changed

6 files changed

+128
-0
lines changed

src/tools/miri/src/shims/alloc.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,4 +172,42 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
172172
}
173173
}
174174
}
175+
176+
fn aligned_alloc(
177+
&mut self,
178+
align: u64,
179+
size: u64,
180+
) -> InterpResult<'tcx, Pointer<Option<Provenance>>> {
181+
let this = self.eval_context_mut();
182+
// Alignment must be a power of 2, and "supported by the implementation".
183+
// We decide that "supported by the implementation" means that the
184+
// size must be a multiple of the alignment. (This restriction seems common
185+
// enough that it is stated on <https://en.cppreference.com/w/c/memory/aligned_alloc>
186+
// as a general rule, but the actual standard has no such rule.)
187+
// If any of these are violated, we have to return NULL.
188+
// All fundamental alignments must be supported.
189+
//
190+
// macOS and Illumos are buggy in that they require the alignment
191+
// to be at least the size of a pointer, so they do not support all fundamental
192+
// alignments. We do not emulate those platform bugs.
193+
//
194+
// Linux also sets errno to EINVAL, but that's non-standard behavior that we do not
195+
// emulate.
196+
// FreeBSD says some of these cases are UB but that's violating the C standard.
197+
// http://en.cppreference.com/w/cpp/memory/c/aligned_alloc
198+
// Linux: https://linux.die.net/man/3/aligned_alloc
199+
// FreeBSD: https://man.freebsd.org/cgi/man.cgi?query=aligned_alloc&apropos=0&sektion=3&manpath=FreeBSD+9-current&format=html
200+
match size.checked_rem(align) {
201+
Some(0) if align.is_power_of_two() => {
202+
let align = align.max(this.malloc_align(size).bytes());
203+
let ptr = this.allocate_ptr(
204+
Size::from_bytes(size),
205+
Align::from_bytes(align).unwrap(),
206+
MiriMemoryKind::C.into(),
207+
)?;
208+
Ok(ptr.into())
209+
}
210+
_ => Ok(Pointer::null()),
211+
}
212+
}
175213
}

src/tools/miri/src/shims/unix/foreign_items.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
295295
}
296296
}
297297
}
298+
"aligned_alloc" => {
299+
// This is a C11 function, we assume all Unixes have it.
300+
// (MSVC explicitly does not support this.)
301+
let [align, size] =
302+
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
303+
let align = this.read_target_usize(align)?;
304+
let size = this.read_target_usize(size)?;
305+
306+
let res = this.aligned_alloc(align, size)?;
307+
this.write_pointer(res, dest)?;
308+
}
298309

299310
// Dynamic symbol loading
300311
"dlsym" => {

src/tools/miri/src/shims/wasi/foreign_items.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
2626
let result = this.posix_memalign(memptr, align, size)?;
2727
this.write_scalar(result, dest)?;
2828
}
29+
"aligned_alloc" => {
30+
let [align, size] =
31+
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
32+
let align = this.read_target_usize(align)?;
33+
let size = this.read_target_usize(size)?;
34+
35+
let res = this.aligned_alloc(align, size)?;
36+
this.write_pointer(res, dest)?;
37+
}
2938

3039
_ => return Ok(EmulateItemResult::NotSupported),
3140
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//@ignore-target-windows: Windows does not support the standard C11 aligned_alloc.
2+
3+
fn main() {
4+
// libc doesn't have this function (https://github.com/rust-lang/libc/issues/3689),
5+
// so we declare it ourselves.
6+
extern "C" {
7+
fn aligned_alloc(alignment: libc::size_t, size: libc::size_t) -> *mut libc::c_void;
8+
}
9+
10+
// Make sure even zero-sized allocations need to be freed.
11+
12+
unsafe {
13+
aligned_alloc(2, 0); //~ERROR: memory leaked
14+
}
15+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: memory leaked: ALLOC (C heap, size: 0, align: 2), allocated here:
2+
--> $DIR/aligned_alloc_size_zero_leak.rs:LL:CC
3+
|
4+
LL | aligned_alloc(2, 0);
5+
| ^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: BACKTRACE:
8+
= note: inside `main` at $DIR/aligned_alloc_size_zero_leak.rs:LL:CC
9+
10+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
11+
12+
note: the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check
13+
14+
error: aborting due to 1 previous error
15+

src/tools/miri/tests/pass-dep/libc/libc-mem.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,44 @@ fn test_reallocarray() {
241241
}
242242
}
243243

244+
#[cfg(not(target_os = "windows"))]
245+
fn test_aligned_alloc() {
246+
// libc doesn't have this function (https://github.com/rust-lang/libc/issues/3689),
247+
// so we declare it ourselves.
248+
extern "C" {
249+
fn aligned_alloc(alignment: libc::size_t, size: libc::size_t) -> *mut libc::c_void;
250+
}
251+
// size not a multiple of the alignment
252+
unsafe {
253+
let p = aligned_alloc(16, 3);
254+
assert_eq!(p, ptr::null_mut());
255+
}
256+
257+
// alignment not power of 2
258+
unsafe {
259+
let p = aligned_alloc(63, 8);
260+
assert_eq!(p, ptr::null_mut());
261+
}
262+
263+
// alignment lesser than a word but still a successful allocation
264+
unsafe {
265+
let p = aligned_alloc(1, 4);
266+
assert!(!p.is_null());
267+
assert!(p.is_aligned_to(4));
268+
libc::free(p);
269+
}
270+
271+
// repeated tests on correct alignment/size
272+
for _ in 0..16 {
273+
unsafe {
274+
let p = aligned_alloc(16, 16);
275+
assert!(!p.is_null());
276+
assert!(p.is_aligned_to(16));
277+
libc::free(p);
278+
}
279+
}
280+
}
281+
244282
fn main() {
245283
test_malloc();
246284
test_calloc();
@@ -254,6 +292,8 @@ fn main() {
254292
target_os = "wasi",
255293
)))]
256294
test_reallocarray();
295+
#[cfg(not(target_os = "windows"))]
296+
test_aligned_alloc();
257297

258298
test_memcpy();
259299
test_strcpy();

0 commit comments

Comments
 (0)