@@ -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