From: Sergey Kaplun via Tarantool-patches <tarantool-patches@dev.tarantool.org>
To: Sergey Bronnikov <sergeyb@tarantool.org>,
Evgeniy Temirgaleev <e.temirgaleev@tarantool.org>
Cc: tarantool-patches@dev.tarantool.org
Subject: [Tarantool-patches] [PATCH luajit] FFI/MacOS: Fix calling convention for on-stack varargs.
Date: Mon, 29 Jun 2026 16:19:14 +0300 [thread overview]
Message-ID: <20260629131914.791223-1-skaplun@tarantool.org> (raw)
From: Mike Pall <mike>
Thanks to Sergey Kaplun.
(cherry picked from commit a2bde60819d83e6f75130ac2c93ee4b3c7615800)
This commit fixes the regression introduced by the commit
82ca6844234901366c043cd103f6eae345af753c ("FFI/MacOS: Fix calling
convention for enums."). The `isva` flag is set to 0 even for vararg
functions. Thus, arguments on the stack may be aligned incorrectly,
leading to the crash.
This patch fixes the behaviour by adjusting the flag value instead of
resetting it. In addition to the original test, various tests have been
added to cover the behaviour of the vararg FFI calls.
Sergey Kaplun:
* added the description and the test for the problem
Part of tarantool/tarantool#12480
---
Branch: https://github.com/tarantool/luajit/tree/skaplun/lj-1455-macos-arm64-vararg-regression
Related issues:
* https://github.com/LuaJIT/LuaJIT/issues/1455
* https://github.com/neovim/neovim/pull/39994
* https://github.com/tarantool/tarantool/issues/12480
src/lj_ccall.c | 2 +-
...455-macos-arm64-vararg-regression.test.lua | 112 ++++++++++++++++++
2 files changed, 113 insertions(+), 1 deletion(-)
create mode 100644 test/tarantool-tests/lj-1455-macos-arm64-vararg-regression.test.lua
diff --git a/src/lj_ccall.c b/src/lj_ccall.c
index 7c3ec1e5..ed692318 100644
--- a/src/lj_ccall.c
+++ b/src/lj_ccall.c
@@ -1082,7 +1082,7 @@ static int ccall_set_args(lua_State *L, CTState *cts, CType *ct,
if (CCALL_ALIGN_STACKARG) { /* Align argument on stack. */
MSize align = (1u << ctype_align(ccall_struct_align(cts, d))) - 1;
#if LJ_TARGET_ARM64 && LJ_TARGET_OSX
- isva = ctype_isstruct(d->info);
+ isva |= ctype_isstruct(d->info);
#endif
if (rp || (CCALL_PACK_STACKARG && isva && align < CTSIZE_PTR-1))
align = CTSIZE_PTR-1;
diff --git a/test/tarantool-tests/lj-1455-macos-arm64-vararg-regression.test.lua b/test/tarantool-tests/lj-1455-macos-arm64-vararg-regression.test.lua
new file mode 100644
index 00000000..a6670cce
--- /dev/null
+++ b/test/tarantool-tests/lj-1455-macos-arm64-vararg-regression.test.lua
@@ -0,0 +1,112 @@
+local ffi = require('ffi')
+local tap = require('tap')
+
+-- The test file to test various FFI C vararg calls.
+-- luacheck: push no max_comment_line_length
+-- Originated from: https://github.com/neovim/neovim/blob/a5aa62e37b82214a1d4d1e0a54d193b155fb340c/test/unit/strings_spec.lua
+-- luacheck: pop
+-- See also: https://github.com/LuaJIT/LuaJIT/issues/1455.
+
+local test = tap.test('lj-1455-macos-arm64-vararg-regression')
+
+test:plan(45)
+
+ffi.cdef('int sprintf(char *str, const char *format, ...);')
+
+local buf = ffi.new('char[64]')
+
+local function t(expected, fmt, ...)
+ local args = {...}
+ local ctx = string.format('sprintf(buf, "%s"', fmt)
+ for _, x in ipairs(args) do
+ ctx = ctx .. ', ' .. tostring(x)
+ end
+ ctx = ctx .. string.format(') = %s', expected)
+
+ test:test(ctx, function(subtest, ...)
+ subtest:plan(2)
+ subtest:is(ffi.C.sprintf(buf, fmt, ...), #expected,
+ ctx .. ' - return status')
+ subtest:is(ffi.string(buf), expected, ctx .. ' - result string')
+ end, ...)
+end
+
+local function i(n)
+ return ffi.cast('int', n)
+end
+
+local function l(n)
+ return ffi.cast('long', n)
+end
+
+local function ll(n)
+ return ffi.cast('long long', n)
+end
+
+local function z(n)
+ return ffi.cast('ptrdiff_t', n)
+end
+
+local function u(n)
+ return ffi.cast('unsigned', n)
+end
+
+local function ul(n)
+ return ffi.cast('unsigned long', n)
+end
+
+local function ull(n)
+ return ffi.cast('unsigned long long', n)
+end
+
+local function uz(n)
+ return ffi.cast('size_t', n)
+end
+
+t('1234567', '%d', i(1234567))
+t('1234567', '%ld', l(1234567))
+t(' 1234567', '%9ld', l(1234567))
+t('1234567 ', '%-9ld', l(1234567))
+t('deadbeef', '%x', u(0xdeadbeef))
+t('one two', '%s %s', 'one', 'two')
+t('1.234000', '%f', 1.234)
+t('1.234000e+00', '%e', 1.234)
+t('inf', '%f', 1.0 / 0.0)
+t('-inf', '%f', -1.0 / 0.0)
+t('-0.000000', '%f', tonumber('-0.0'))
+t('%%%', '%%%%%%')
+t('0x87654321', '%p', ffi.cast('char *', 0x87654321))
+t('0x0087654321', '%012p', ffi.cast('char *', 0x87654321))
+t('1234567 ', '%1$*2$ld', l(1234567), i(-9))
+t('1234567 ', '%1$*2$.*3$ld', l(1234567), i(-9), i(5))
+t('1234567 ', '%1$*3$.*2$ld', l(1234567), i(5), i(-9))
+t('1234567 ', '%3$*1$.*2$ld', i(-9), i(5), l(1234567))
+t('1234567', '%1$ld', l(1234567))
+t(' 1234567', '%1$*2$ld', l(1234567), i(9))
+t('9 12345 7654321', '%2$ld %1$d %3$lu', i(12345), l(9), ul(7654321))
+t('9 1234567 7654321', '%2$d %1$ld %3$lu', l(1234567), i(9), ul(7654321))
+t('9 1234567 7654321', '%2$d %1$lld %3$lu', ll(1234567), i(9), ul(7654321))
+t('9 12345 7654321', '%2$ld %1$u %3$lu', u(12345), l(9), ul(7654321))
+t('9 1234567 7654321', '%2$d %1$lu %3$lu', ul(1234567), i(9), ul(7654321))
+t('9 1234567 7654321', '%2$d %1$llu %3$lu', ull(1234567), i(9), ul(7654321))
+t('9 deadbeef 7654321', '%2$d %1$x %3$lu', u(0xdeadbeef), i(9), ul(7654321))
+t('9 c 7654321', '%2$ld %1$c %3$lu', i(('c'):byte()), l(9), ul(7654321))
+t('9 hi 7654321', '%2$ld %1$s %3$lu', 'hi', l(9), ul(7654321))
+t('9 0.000000e+00 7654321', '%2$ld %1$e %3$lu', 0.0, l(9), ul(7654321))
+t('two one two', '%2$s %1$s %2$s', 'one', 'two', 'three')
+t('three one two', '%3$s %1$s %2$s', 'one', 'two', 'three')
+t('1234567', '%1$d', i(1234567))
+t('deadbeef', '%1$x', u(0xdeadbeef))
+t('one two', '%1$s %2$s', 'one', 'two')
+t('two one', '%2$s %1$s', 'one', 'two')
+t('1.234000', '%1$f', 1.234)
+t('1.234000e+00', '%1$e', 1.234)
+t('inf', '%1$f', 1.0 / 0.0)
+t('-inf', '%1$f', -1.0 / 0.0)
+t('-0.000000', '%1$f', tonumber('-0.0'))
+t('-1234567 -7654321', '%zd %zd', z(-1234567), z(-7654321))
+t('-7654321 -1234567', '%2$zd %1$zd', z(-1234567), z(-7654321))
+t('1234567 7654321', '%zu %zu', uz(1234567), uz(7654321))
+t('7654321 1234567', '%2$zu %1$zu', uz(1234567), uz(7654321))
+
+test:done(true)
--
2.54.0
reply other threads:[~2026-06-29 13:19 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260629131914.791223-1-skaplun@tarantool.org \
--to=tarantool-patches@dev.tarantool.org \
--cc=e.temirgaleev@tarantool.org \
--cc=sergeyb@tarantool.org \
--cc=skaplun@tarantool.org \
--subject='Re: [Tarantool-patches] [PATCH luajit] FFI/MacOS: Fix calling convention for on-stack varargs.' \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox