Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Arguments checking in `Fuzz()` (#41).
- A memory leak in a Lua-based implementation of `TestOneInput()`.
- An initial buffer size in FuzzedDataProvider.
- Memory leak in FuzzedDataProvider (#52).
- Segfault on parsing a broken dictionary (#65).
71 changes: 64 additions & 7 deletions luzer/luzer.c
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,8 @@ TestOneInput(const uint8_t* data, size_t size) {
/* Disable debug hook. */
LUA_SETHOOK(L, debug_hook, 0, 0);

lua_gc(L, LUA_GCCOLLECT, 0);

return rc;
}

Expand Down Expand Up @@ -437,6 +439,66 @@ free_argv(int argc, char **argv)
free(argv);
}

NO_SANITIZE static int
os_exit(int exit_code) {
lua_State *L = luaL_newstate();
luaL_openlibs(L);
lua_getglobal(L, "os");
if (!lua_istable(L, -1)) {
fprintf(stderr, "Error: 'os' table not found.\n");
lua_close(L);
return 1;
}

lua_getfield(L, -1, "exit");
if (!lua_isfunction(L, -1)) {
fprintf(stderr, "Error: 'os.exit' function not found.\n");
lua_close(L);
return 1;
}

// Remove the 'os' table from the stack, leaving only 'os.exit'
lua_remove(L, -2);
// Optional: Push an exit code argument (e.g., 1 for error)
lua_pushinteger(L, exit_code);
lua_pushboolean(L, 1);
lua_call(L, 1, 0);

// This part will only be reached if os.exit somehow fails
// or doesn't exit the process.
lua_close(L);
return 0;
}

NO_SANITIZE static void
shutdown_lua(void)
{
lua_State *L = get_global_lua_state();
lua_gc(L, LUA_GCCOLLECT, 0);
luaL_cleanup(L);
lua_close(L);
set_global_lua_state(NULL);
}

int atexit_retcode;

NO_SANITIZE void
xxx(void) {
_exit(atexit_retcode);
}

NO_SANITIZE static void
graceful_exit(int retcode, bool prevent_crash_report) {
prevent_crash_report = true;
if (prevent_crash_report) {
// Disable libfuzzer's atexit.
atexit_retcode = retcode;
atexit(&xxx);
}
shutdown_lua();
os_exit(retcode);
}

NO_SANITIZE static int
luaL_fuzz(lua_State *L)
{
Expand Down Expand Up @@ -534,14 +596,9 @@ luaL_fuzz(lua_State *L)

jit_status = luajit_has_enabled_jit(L);
set_global_lua_state(L);
int rc = LLVMFuzzerRunDriver(&argc, &argv, &TestOneInput);

free_argv(argc, argv);
luaL_cleanup(L);
graceful_exit(LLVMFuzzerRunDriver(&argc, &argv, &TestOneInput), true);

lua_pushnumber(L, rc);

return 1;
return 0;
}

static const struct luaL_Reg Module[] = {
Expand Down
26 changes: 19 additions & 7 deletions luzer/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
include(MakeLuaPath)

set(ASAN_DSO_PATH ${PROJECT_BINARY_DIR}/luzer/${ASAN_DSO})
set(UBSAN_DSO_PATH ${PROJECT_BINARY_DIR}/luzer/${UBSAN_DSO})

make_lua_path(LUA_CPATH
PATHS
${PROJECT_BINARY_DIR}/luzer/?.so
Expand Down Expand Up @@ -137,6 +140,21 @@ set_tests_properties(luzer_hook_test PROPERTIES
PASS_REGULAR_EXPRESSION "test_hook.lua:19"
)

list(APPEND TEST_ENV
"LUA_CPATH=${LUA_CPATH}"
"LUA_PATH=${LUA_PATH}"
"LD_PRELOAD=${ASAN_DSO_PATH}"
)
add_test(
NAME luzer_bad_dict_test
COMMAND ${LUA_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_options_3.lua
-dict=${CMAKE_CURRENT_SOURCE_DIR}/bad.dict
)
set_tests_properties(luzer_bad_dict_test PROPERTIES
ENVIRONMENT "${TEST_ENV}"
PASS_REGULAR_EXPRESSION "ParseDictionaryFile"
)

macro(generate_luac_lib name cflags)
add_library(${name} SHARED luac.c test_lib.c)
target_include_directories(${name} PRIVATE ${LUA_INCLUDE_DIR})
Expand Down Expand Up @@ -174,10 +192,6 @@ list(APPEND TEST_ENV
"LUA_PATH=${LUA_PATH};"
)

set(ASAN_DSO_PATH ${PROJECT_BINARY_DIR}/luzer/${ASAN_DSO})
set(UBSAN_DSO_PATH ${PROJECT_BINARY_DIR}/luzer/${UBSAN_DSO})
set(UBSAN_CXX_DSO_PATH ${PROJECT_BINARY_DIR}/luzer/${UBSAN_CXX_DSO})

generate_luac_test(luzer_luac
"${TEST_ENV};LIB_NAME=luac"
"Hello, Lua!"
Expand Down Expand Up @@ -237,11 +251,9 @@ if (LUA_HAS_JIT)
"${TEST_ENV};FFI_LIB_NAME=testlib.so"
"Done 10 runs in 0 second"
)
# XXX: Memory leak in FDP is expected, should be fixed in [1].
# 1. https://github.com/ligurio/luzer/issues/52
generate_ffi_test(luzer_ffi_asan
"${TEST_ENV};LD_PRELOAD=${ASAN_DSO_PATH};FFI_LIB_NAME=testlib_asan.so"
"LeakSanitizer: detected memory leaks"
"Done 10 runs in 0 second"
)
generate_ffi_test(luzer_ffi_ubsan
"${TEST_ENV};LD_PRELOAD=${UBSAN_DSO_PATH};FFI_LIB_NAME=testlib_ubsan.so"
Expand Down
Loading