-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Closed
Description
Originally reported by @locker.
Assume we have the following two chunks of code:
/tmp/ffi_meta1.lua:
local ffi = require('ffi')
ffi.cdef[[
struct test {int a;};
]]
local test_t = ffi.typeof('struct test')
local function index_func(v)
-- Should raise an error (stack overflow).
return ffi.typeof(v).a
end
ffi.metatype(test_t, {
__index = index_func
})
local function newobj()
return ffi.new(test_t, 0)
end
local o1 = newobj()
jit.flush()
jit.opt.start('hotloop=1')
local r, e
for _ = 1, 4 do
r, e = pcall(index_func, o1)
end
print(r,e)src/luajit /tmp/ffi_meta1.lua
LuaJIT ASSERT lj_record.c:165: rec_check_slots: slot 2 type mismatch: stack type 4 vs IR type 19
Aborted (core dumped) src/luajit /tmp/ffi_meta1.lua
src/luajit -joff /tmp/ffi_meta1.lua
false stack overflow/tmp/ffi_meta2.lua (the same, but avoid recursion and stack overflow):
local ffi = require('ffi')
ffi.cdef[[
struct test {int a;};
]]
local test_t = ffi.typeof('struct test')
local function newobj()
return ffi.new(test_t, 0)
end
local o1 = newobj()
local function index_func(v)
if v == o1 then
local x = ffi.typeof(v).a
return x
else
return 2
end
end
ffi.metatype(test_t, {
__index = index_func
})
jit.flush()
jit.opt.start('hotloop=1')
local r
for _ = 1, 4 do
r = index_func(o1)
end
print(r)src/luajit /tmp/ffi_meta2.lua
LuaJIT ASSERT lj_record.c:165: rec_check_slots: slot 1 type mismatch: stack type 13 vs IR type 11
Aborted (core dumped) src/luajit /tmp/ffi_meta2.lua
src/luajit -joff /tmp/ffi_meta2.lua
2The JIT part doesn't invoke the metamethod for the CType. Instead it gets the field of the structure referenced by this CType.
The simplest patch for the JIT side is the following:
diff --git a/src/lj_crecord.c b/src/lj_crecord.c
index b016eaec..538847e6 100644
--- a/src/lj_crecord.c
+++ b/src/lj_crecord.c
@@ -886,7 +886,7 @@ again:
ptr = emitir(IRT(IR_ADD, IRT_PTR), ptr, lj_ir_kintp(J, ofs));
crec_index_bf(J, rd, ptr, fct->info);
return;
- } else {
+ } else if (cd && cd->ctypeid != CTID_CTYPEID) {
lj_assertJ(ctype_isfield(fct->info), "field expected");
sid = ctype_cid(fct->info);
}OTOH, maybe it is more clear to make logic in the VM match the JIT behaviour (the semantic provided by 6cee133 isn't obvious to me for that case).
Reactions are currently unavailable