Skip to content

Commit aa29ec7

Browse files
committed
core: fix cdata decrementing
When cdata has custom finalizer (and so LJ_GC_CDATA_FIN flag) it is not collected immediately, when lj_cdata_free() is called. Instead, it is resurrected and marked finalized, so it is collected at the next GC cycle. The reason of the bug is that gc_cdatanum is decremented when cdata is resurrected too (i.e. twice). This patch excludes cdata decrementing from resurrection branch and adds corresponding tests. Follows up tarantool/tarantool#5187 Closes tarantool/tarantool#5820
1 parent c0c2e62 commit aa29ec7

File tree

4 files changed

+58
-3
lines changed

4 files changed

+58
-3
lines changed

src/lj_cdata.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,11 @@ void LJ_FASTCALL lj_cdata_free(global_State *g, GCcdata *cd)
8080
lua_assert(ctype_hassize(ct->info) || ctype_isfunc(ct->info) ||
8181
ctype_isextern(ct->info));
8282
lj_mem_free(g, cd, sizeof(GCcdata) + sz);
83+
g->gc.cdatanum--;
8384
} else {
8485
lj_mem_free(g, memcdatav(cd), sizecdatav(cd));
86+
g->gc.cdatanum--;
8587
}
86-
g->gc.cdatanum--;
8788
}
8889

8990
void lj_cdata_setfin(lua_State *L, GCcdata *cd, GCobj *obj, uint32_t it)

test/misclib-getmetrics-capi.test.lua

+14-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ local jit_opt_default = {
1414
local tap = require('tap')
1515

1616
local test = tap.test("clib-misc-getmetrics")
17-
test:plan(10)
17+
test:plan(11)
1818

1919
local testgetmetrics = require("testgetmetrics")
2020

@@ -62,6 +62,19 @@ test:ok(testgetmetrics.objcount(function(iterations)
6262
jit.opt.start(unpack(jit_opt_default))
6363
end))
6464

65+
test:ok(testgetmetrics.objcount_cdata_decrement(function()
66+
-- cdata decrement test.
67+
-- See https://github.com/tarantool/tarantool/issues/5820.
68+
local ffi = require("ffi")
69+
local function nop() end
70+
ffi.gc(ffi.cast("void *", 0), nop)
71+
-- Does not collect cdata, but removes LJ_GC_CDATA_FIN flag
72+
-- and resurrects object.
73+
collectgarbage()
74+
-- Collects cdata.
75+
collectgarbage()
76+
end))
77+
6578
-- Compiled loop with a direct exit to the interpreter.
6679
test:ok(testgetmetrics.snap_restores(function()
6780
jit.opt.start(0, "hotloop=1")

test/misclib-getmetrics-capi/testgetmetrics.c

+28
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,33 @@ static int objcount(lua_State *L)
155155
return 1;
156156
}
157157

158+
static int objcount_cdata_decrement(lua_State *L)
159+
{
160+
/*
161+
* cdata decrement test.
162+
* See https://github.com/tarantool/tarantool/issues/5820.
163+
*/
164+
struct luam_Metrics oldm, newm;
165+
int n = lua_gettop(L);
166+
if (n != 1 || !lua_isfunction(L, 1))
167+
luaL_error(L, "incorrect argument: 1 function is required");
168+
169+
/* Force up garbage collect all dead objects. */
170+
lua_gc(L, LUA_GCCOLLECT, 0);
171+
172+
luaM_metrics(L, &oldm);
173+
/*
174+
* The function generates and collects cdata with
175+
* LJ_GC_CDATA_FIN flag.
176+
*/
177+
lua_call(L, 0, 0);
178+
luaM_metrics(L, &newm);
179+
assert(newm.gc_cdatanum - oldm.gc_cdatanum == 0);
180+
181+
lua_pushboolean(L, 1);
182+
return 1;
183+
}
184+
158185
static int snap_restores(lua_State *L)
159186
{
160187
struct luam_Metrics oldm, newm;
@@ -229,6 +256,7 @@ static const struct luaL_Reg testgetmetrics[] = {
229256
{"gc_allocated_freed", gc_allocated_freed},
230257
{"gc_steps", gc_steps},
231258
{"objcount", objcount},
259+
{"objcount_cdata_decrement", objcount_cdata_decrement},
232260
{"snap_restores", snap_restores},
233261
{"strhash", strhash},
234262
{"tracenum_base", tracenum_base},

test/misclib-getmetrics-lapi.test.lua

+14-1
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ test:test("gc-steps", function(subtest)
172172
end)
173173

174174
test:test("objcount", function(subtest)
175-
subtest:plan(4)
175+
subtest:plan(5)
176176
local ffi = require("ffi")
177177

178178
jit.opt.start(0)
@@ -231,6 +231,19 @@ test:test("objcount", function(subtest)
231231
subtest:is(new_metrics.gc_cdatanum, old_metrics.gc_cdatanum,
232232
"cdatanum don't change")
233233

234+
-- cdata decrement test.
235+
-- See https://github.com/tarantool/tarantool/issues/5820.
236+
local function nop() end
237+
local cdatanum_old = misc.getmetrics().gc_cdatanum
238+
ffi.gc(ffi.cast("void *", 0), nop)
239+
-- Does not collect cdata, but removes LJ_GC_CDATA_FIN flag
240+
-- and resurrects object.
241+
collectgarbage()
242+
-- Collects cdata.
243+
collectgarbage()
244+
subtest:is(misc.getmetrics().gc_cdatanum, cdatanum_old,
245+
"cdatanum is decremented correctly")
246+
234247
-- Restore default jit settings.
235248
jit.opt.start(unpack(jit_opt_default))
236249
end)

0 commit comments

Comments
 (0)