Skip to content

Commit b572fa8

Browse files
Buristanigormunkin
authored andcommitted
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. Resolves tarantool/tarantool#5820 Follows up tarantool/tarantool#5187 Reviewed-by: Igor Munkin <[email protected]> Reviewed-by: Sergey Ostanevich <[email protected]> Signed-off-by: Igor Munkin <[email protected]> (cherry picked from commit 82932be)
1 parent ca20270 commit b572fa8

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/tarantool-tests/misclib-getmetrics-capi.test.lua

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

1717
local test = tap.test("clib-misc-getmetrics")
18-
test:plan(10)
18+
test:plan(11)
1919

2020
local testgetmetrics = require("testgetmetrics")
2121

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

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

test/tarantool-tests/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/tarantool-tests/misclib-getmetrics-lapi.test.lua

+14-1
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ test:test("gc-steps", function(subtest)
177177
end)
178178

179179
test:test("objcount", function(subtest)
180-
subtest:plan(4)
180+
subtest:plan(5)
181181
local ffi = require("ffi")
182182

183183
jit.opt.start(0)
@@ -236,6 +236,19 @@ test:test("objcount", function(subtest)
236236
subtest:is(new_metrics.gc_cdatanum, old_metrics.gc_cdatanum,
237237
"cdatanum don't change")
238238

239+
-- gc_cdatanum decrement test.
240+
-- See https://github.com/tarantool/tarantool/issues/5820.
241+
local function nop() end
242+
local cdatanum_old = misc.getmetrics().gc_cdatanum
243+
ffi.gc(ffi.cast("void *", 0), nop)
244+
-- Does not collect the cdata, but resurrects the object and
245+
-- removes LJ_GC_CDATA_FIN flag.
246+
collectgarbage()
247+
-- Collects the cdata.
248+
collectgarbage()
249+
subtest:is(misc.getmetrics().gc_cdatanum, cdatanum_old,
250+
"cdatanum is decremented correctly")
251+
239252
-- Restore default jit settings.
240253
jit.opt.start(unpack(jit_opt_default))
241254
end)

0 commit comments

Comments
 (0)