Skip to content

Commit 7a0ee91

Browse files
committed
alloc: update comments around malloc() alignment
1 parent 6f4c7d9 commit 7a0ee91

File tree

1 file changed

+21
-8
lines changed

1 file changed

+21
-8
lines changed

Diff for: src/tools/miri/src/shims/alloc.rs

+21-8
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
2222
/// Returns the minimum alignment for the target architecture for allocations of the given size.
2323
fn min_align(&self, size: u64, kind: MiriMemoryKind) -> Align {
2424
let this = self.eval_context_ref();
25-
// List taken from `library/std/src/sys/pal/common/alloc.rs`.
26-
// This list should be kept in sync with the one from libstd.
27-
let min_align = match this.tcx.sess.target.arch.as_ref() {
25+
// The C standard says: "The pointer returned if the allocation succeeds is suitably aligned
26+
// so that it may be assigned to a pointer to any type of object with a fundamental
27+
// alignment requirement and size less than or equal to the size requested."
28+
// So first we need to figure out what the limits are for "fundamental alignment".
29+
// This is given by `alignof(max_align_t)`. The following list is taken from
30+
// `library/std/src/sys/pal/common/alloc.rs` (where this is called `MIN_ALIGN`) and should
31+
// be kept in sync.
32+
let max_fundamental_align = match this.tcx.sess.target.arch.as_ref() {
2833
"x86" | "arm" | "mips" | "mips32r6" | "powerpc" | "powerpc64" | "wasm32" => 8,
2934
"x86_64" | "aarch64" | "mips64" | "mips64r6" | "s390x" | "sparc64" | "loongarch64" =>
3035
16,
3136
arch => bug!("unsupported target architecture for malloc: `{}`", arch),
3237
};
33-
// Windows always aligns, even small allocations.
34-
// Source: <https://support.microsoft.com/en-us/help/286470/how-to-use-pageheap-exe-in-windows-xp-windows-2000-and-windows-server>
35-
// But jemalloc does not, so for the C heap we only align if the allocation is sufficiently big.
36-
if kind == MiriMemoryKind::WinHeap || size >= min_align {
37-
return Align::from_bytes(min_align).unwrap();
38+
// The C standard only requires sufficient alignment for any *type* with size less than or
39+
// equal to the size requested. Types one can define in standard C seem to never have an alignment
40+
// bigger than their size. So if the size is 2, then only alignment 2 is guaranteed, even if
41+
// `max_fundamental_align` is bigger.
42+
// This matches what some real-world implementations do, see e.g.
43+
// - https://github.com/jemalloc/jemalloc/issues/1533
44+
// - https://github.com/llvm/llvm-project/issues/53540
45+
// - https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2293.htm
46+
// However, Windows `HeapAlloc` always aligns, even small allocations, so it gets different treatment here.
47+
// Source: <https://learn.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-heapalloc>
48+
if kind == MiriMemoryKind::WinHeap || size >= max_fundamental_align {
49+
return Align::from_bytes(max_fundamental_align).unwrap();
3850
}
51+
// C doesn't have zero-sized types, so presumably nothing is guaranteed here.
3952
if size == 0 {
4053
return Align::ONE;
4154
}

0 commit comments

Comments
 (0)