From 78f5996fcf7787930eed944a750f6ee82fc3bc22 Mon Sep 17 00:00:00 2001 From: Alex Alejandre Date: Wed, 7 Oct 2026 20:55:15 -0600 Subject: [PATCH] Protect against different vector widths (#1909) GCC aligns alloca to the widest enabled vector type (16 bytes, 32 with avx, 64 with avx-512). With AVX the block address is `lea 0x1f(%rsp)` rounded down to the nearest 32-divisible, but half the time the block starts 16 bytes higher so the function reads the stack arguments 2 slots away from where it should. Without AVX the address is `lea 0xf(%rsp)` which is the stack pointer. --- src/core/ffi.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/core/ffi.c b/src/core/ffi.c index e2c07634..8064cac6 100644 --- a/src/core/ffi.c +++ b/src/core/ffi.c @@ -1225,7 +1225,15 @@ static Janet janet_ffi_sysv64(JanetFFISignature *signature, void *function_point ret_mem = alloca(type_size(signature->ret.type)); regs[0] = (uint64_t) ret_mem; } +/* GCC aligns alloca to the widest allowed vector type (32 bytes for AVX) which can pad + * between the stack pointer and this block, but stack args start at the stack pointer, + * so we must ask for the calling convention's 16 byte alignment */ +/* Both GCC and CLANG define GNUC. */ +#if defined(__GNUC__) + uint64_t *stack = __builtin_alloca_with_align(sizeof(uint64_t) * signature->stack_count, 128); +#else uint64_t *stack = alloca(sizeof(uint64_t) * signature->stack_count); +#endif for (uint32_t i = 0; i < signature->arg_count; i++) { uint64_t *to; int32_t n = i + 2;