Tarantool development patches archive
 help / color / mirror / Atom feed
From: Sergey Kaplun via Tarantool-patches <tarantool-patches@dev.tarantool.org>
To: Sergey Bronnikov <sergeyb@tarantool.org>
Cc: tarantool-patches@dev.tarantool.org
Subject: [Tarantool-patches] [PATCH luajit] FFI: Fix constructor index resolution in JIT compiler.
Date: Mon, 16 Mar 2026 13:48:53 +0300	[thread overview]
Message-ID: <20260316104853.23901-1-skaplun@tarantool.org> (raw)

From: Mike Pall <mike>

Reported by Vladimir Davydov and Sergey Kaplun.

(cherry picked from commit 02e29995581cb568a784a9b996cd5e9139cd0737)

This patch is a follow-up for the commit
6cee1333ef2b340e1b23e3051b9f433fc803d2ff ("FFI: Resolve metamethods for
constructors, too."). It allows the use of metamethods of the objects to
be called on their constructors. Unfortunately, the JIT part isn't
updated and may cause inconsistencies since it is indexing the field of
the structure referenced by the given CType.

This patch makes the semantics of JIT the same as for the VM.

Sergey Kaplun:
* added the description and the test for the problem

Part of tarantool/tarantool#12134
---

Branch: https://github.com/tarantool/luajit/tree/skaplun/lj-1441-record-constructor-metamethod
Related issues:
* https://github.com/LuaJIT/LuaJIT/issues/1441
* https://github.com/tarantool/tarantool/issues/12134

 src/lj_crecord.c                              |  2 +
 ...441-record-constructor-metamethod.test.lua | 79 +++++++++++++++++++
 2 files changed, 81 insertions(+)
 create mode 100644 test/tarantool-tests/lj-1441-record-constructor-metamethod.test.lua

diff --git a/src/lj_crecord.c b/src/lj_crecord.c
index b016eaec..d486ee85 100644
--- a/src/lj_crecord.c
+++ b/src/lj_crecord.c
@@ -881,6 +881,8 @@ again:
 	  }
 	  J->base[0] = lj_ir_kint(J, (int32_t)fct->size);
 	  return;  /* Interpreter will throw for newindex. */
+	} else if (cd && cd->ctypeid == CTID_CTYPEID) {
+	  /* Only resolve constants and metamethods for constructors. */
 	} else if (ctype_isbitfield(fct->info)) {
 	  if (ofs)
 	    ptr = emitir(IRT(IR_ADD, IRT_PTR), ptr, lj_ir_kintp(J, ofs));
diff --git a/test/tarantool-tests/lj-1441-record-constructor-metamethod.test.lua b/test/tarantool-tests/lj-1441-record-constructor-metamethod.test.lua
new file mode 100644
index 00000000..370e49e0
--- /dev/null
+++ b/test/tarantool-tests/lj-1441-record-constructor-metamethod.test.lua
@@ -0,0 +1,79 @@
+local tap = require('tap')
+
+-- The test file to demonstrate LuaJIT's incorrect recording of
+-- the __index metamethod invocation on the cdata's constructor.
+-- See also: https://github.com/LuaJIT/LuaJIT/issues/1441.
+
+local test = tap.test('lj-1441-record-constructor-metamethod'):skipcond({
+  ['Test requires JIT enabled'] = not jit.status(),
+})
+
+test:plan(3)
+
+local ffi = require('ffi')
+
+ffi.cdef[[
+  struct test_recursive {int a;};
+  struct test_finite {int a;};
+]]
+
+local recursive_t = ffi.typeof('struct test_recursive')
+local finite_t = ffi.typeof('struct test_finite')
+
+local MAGIC = 42
+
+local function new_recursive()
+  return ffi.new(recursive_t, 0)
+end
+
+local function new_finite()
+  return ffi.new(finite_t, 0)
+end
+
+local function index_func_recursive(v)
+  -- Should raise an error (stack overflow).
+  return ffi.typeof(v).a
+end
+
+-- Special object to invoke metamethod on the cdata<ctypeid>.
+local one_more_step = new_finite()
+
+local function index_func_finite(v)
+  if v == one_more_step then
+    -- XXX: Avoid tail-calls.
+    local x = ffi.typeof(v).a
+    return x
+  else
+    return MAGIC
+  end
+end
+
+ffi.metatype(recursive_t, {
+  __index = index_func_recursive,
+})
+
+ffi.metatype(finite_t, {
+  __index = index_func_finite,
+})
+
+jit.opt.start('hotloop=1')
+
+-- Test the recursive call. Expect the stack overflow error.
+local o_rec = new_recursive()
+local result, errmsg
+for _ = 1, 4 do
+  result, errmsg = pcall(index_func_recursive, o_rec)
+end
+
+test:ok(not result, 'correct status for recursive call')
+test:like(errmsg, 'stack overflow', 'correct error message for recursive call')
+
+-- Test the finite call. Expect the specific value.
+local got
+for _ = 1, 4 do
+  got = index_func_finite(one_more_step)
+end
+
+test:is(got, MAGIC, 'correct result value on trace for finite call')
+
+test:done(true)
-- 
2.53.0


                 reply	other threads:[~2026-03-16 10:47 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=20260316104853.23901-1-skaplun@tarantool.org \
    --to=tarantool-patches@dev.tarantool.org \
    --cc=sergeyb@tarantool.org \
    --cc=skaplun@tarantool.org \
    --subject='Re: [Tarantool-patches] [PATCH luajit] FFI: Fix constructor index resolution in JIT compiler.' \
    /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