Skip to content

Commit 8bc42e2

Browse files
authored
Merge pull request #820 from squeek502/ci-gc-lua-5.5
ci: Update aggressive GC settings for Lua 5.5, fix potential use-after-frees
2 parents f65fe9d + af434d1 commit 8bc42e2

File tree

3 files changed

+18
-21
lines changed

3 files changed

+18
-21
lines changed

.github/workflows/ci.yml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,9 @@ jobs:
4949
run: make test
5050
- name: Test with Aggressive GC
5151
# Run with extremely aggressive garbage collection to potentially find more problems
52-
run: ./build/lua -e "collectgarbage('incremental', 0, 10000000000000)" tests/run.lua
52+
# The 0 for stepmul is "a special case, [...] effectively producing a non-incremental, stop-the-world collector."
53+
# These calls assume Lua 5.5. Earlier versions had different APIs for setting the equivalent of these settings.
54+
run: ./build/lua -e "collectgarbage('incremental'); collectgarbage('param', 'pause', 0); collectgarbage('param', 'stepmul', 0);" tests/run.lua
5355

5456
clang-tsan:
5557
runs-on: ubuntu-latest
@@ -68,7 +70,9 @@ jobs:
6870
run: make test
6971
- name: Test with Aggressive GC
7072
# Run with extremely aggressive garbage collection to potentially find more problems
71-
run: ./build/lua -e "collectgarbage('incremental', 0, 10000000000000)" tests/run.lua
73+
# The 0 for stepmul is "a special case, [...] effectively producing a non-incremental, stop-the-world collector."
74+
# These calls assume Lua 5.5. Earlier versions had different APIs for setting the equivalent of these settings.
75+
run: ./build/lua -e "collectgarbage('incremental'); collectgarbage('param', 'pause', 0); collectgarbage('param', 'stepmul', 0);" tests/run.lua
7276

7377
valgrind:
7478
runs-on: ubuntu-latest
@@ -86,7 +90,7 @@ jobs:
8690
- name: Build
8791
run: make
8892
- name: Test
89-
run: valgrind --suppressions=.ci/valgrind_mem.supp --error-exitcode=1 --leak-check=full --child-silent-after-fork=yes --keep-debuginfo=yes --track-origins=yes ./build/lua -e "collectgarbage('incremental', 0, 10000000000000)" tests/run.lua
93+
run: valgrind --suppressions=.ci/valgrind_mem.supp --error-exitcode=1 --leak-check=full --child-silent-after-fork=yes --keep-debuginfo=yes --track-origins=yes ./build/lua -e "collectgarbage('incremental'); collectgarbage('param', 'pause', 0); collectgarbage('param', 'stepmul', 0);" tests/run.lua
9094

9195
process-cleanup-test:
9296
runs-on: ubuntu-latest

src/fs.c

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -260,13 +260,6 @@ static int push_fs_result(lua_State* L, uv_fs_t* req) {
260260
}
261261

262262
if (req->result < 0) {
263-
if (req->fs_type == UV_FS_SCANDIR) {
264-
// We need to unref the luv_fs_scandir_t userdata to allow it to be garbage collected.
265-
// The scandir callback can only be called once, so we now know that the
266-
// req can be safely garbage collected.
267-
luaL_unref(L, LUA_REGISTRYINDEX, data->data_ref);
268-
data->data_ref = LUA_NOREF;
269-
}
270263
lua_pushnil(L);
271264
if (fs_req_has_dest_path(req)) {
272265
lua_rawgeti(L, LUA_REGISTRYINDEX, data->data_ref);
@@ -356,11 +349,6 @@ static int push_fs_result(lua_State* L, uv_fs_t* req) {
356349
// We want to return this instead of the uv_req_t because the
357350
// luv_fs_scandir_t userdata has a gc method.
358351
lua_rawgeti(L, LUA_REGISTRYINDEX, data->data_ref);
359-
// We now want to unref the userdata to allow it to be garbage collected.
360-
// The scandir callback can only be called once, so we now know that the
361-
// req can be safely garbage collected.
362-
luaL_unref(L, LUA_REGISTRYINDEX, data->data_ref);
363-
data->data_ref = LUA_NOREF;
364352
return 1;
365353

366354
#if LUV_UV_VERSION_GEQ(1, 28, 0)
@@ -386,9 +374,6 @@ static int push_fs_result(lua_State* L, uv_fs_t* req) {
386374
return 1;
387375
}
388376
case UV_FS_READDIR: {
389-
luaL_unref(L, LUA_REGISTRYINDEX, data->data_ref);
390-
data->data_ref = LUA_NOREF;
391-
392377
if(req->result > 0) {
393378
size_t i;
394379
uv_dir_t *dir = (uv_dir_t*)req->ptr;
@@ -400,6 +385,8 @@ static int push_fs_result(lua_State* L, uv_fs_t* req) {
400385
} else
401386
lua_pushnil(L);
402387

388+
luaL_unref(L, LUA_REGISTRYINDEX, data->data_ref);
389+
data->data_ref = LUA_NOREF;
403390
return 1;
404391
}
405392
case UV_FS_CLOSEDIR:
@@ -438,6 +425,15 @@ static void luv_fs_cb(uv_fs_t* req) {
438425
}
439426
if (req->fs_type == UV_FS_SCANDIR) {
440427
luv_fulfill_req(L, data, nargs);
428+
// Regardless of whether or not we errored, we need to unref the
429+
// luv_fs_scandir_t userdata to allow it to be garbage collected.
430+
// The scandir callback can only be called once, so we now know that
431+
// the req can be safely garbage collected.
432+
//
433+
// Crucially, this needs to happen after the fulfill_req call to ensure
434+
// it doesn't get garbage collected beforehand.
435+
luaL_unref(L, LUA_REGISTRYINDEX, data->data_ref);
436+
data->data_ref = LUA_NOREF;
441437
}
442438
else {
443439
// cleanup the uv_fs_t before the callback is called to avoid

tests/test-fs.lua

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,6 @@ return require('lib/tap')(function (test)
8282
assert(uv.fs_unlink(path))
8383
end)
8484
end
85-
local count = collectgarbage("count")
86-
collectgarbage("collect")
87-
assert(count - collectgarbage("count") > 0)
8885
end)
8986

9087
test("fs.stat sync", function (print, p, expect, uv)

0 commit comments

Comments
 (0)