Skip to content

Commit 162a78e

Browse files
ligurioBuristan
andcommitted
luzer: fix argv building
Co-authored-by: Sergey Kaplun <skaplun@tarantool.org>
1 parent a6b9928 commit 162a78e

File tree

2 files changed

+56
-28
lines changed

2 files changed

+56
-28
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2626

2727
- Fix searching Clang RT.
2828
- Stack overflow due to recursive traceback calls.
29+
- Fix a crash due to incorrect `argv` building (#13).

luzer/luzer.c

Lines changed: 55 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ TestOneInput(const uint8_t* data, size_t size) {
230230
*/
231231
lua_sethook(L, debug_hook, LUA_MASKCALL | LUA_MASKLINE, 0);
232232

233-
char *buf = calloc(size + 1, sizeof(char));
233+
char *buf = malloc(size + 1 * sizeof(*buf));
234234
memcpy(buf, data, size);
235235
buf[size] = '\0';
236236
lua_pushlstring(L, buf, size);
@@ -316,49 +316,70 @@ load_custom_mutator_lib(void) {
316316
return 0;
317317
}
318318

319+
/* Find amount of fields in the table on the top of the stack. */
320+
NO_SANITIZE static int
321+
table_nkeys(lua_State *L)
322+
{
323+
int len = 0;
324+
/* Push starting `nil` for iterations. */
325+
lua_pushnil(L);
326+
while (lua_next(L, -2) != 0) {
327+
/*
328+
* Remove `value` from the stack. Keeps `key` for
329+
* the next iteration.
330+
*/
331+
lua_pop(L, 1);
332+
len++;
333+
}
334+
return len;
335+
}
336+
337+
NO_SANITIZE static void
338+
free_argv(int argc, char **argv)
339+
{
340+
/* Free allocated argv strings and the buffer. */
341+
for (int i = 1; i < argc; i++)
342+
free(argv[i]);
343+
free(argv);
344+
}
345+
319346
NO_SANITIZE static int
320347
luaL_fuzz(lua_State *L)
321348
{
322349
if (lua_istable(L, -1) == 0) {
323350
luaL_error(L, "opts is not a table");
324351
}
325-
lua_pushnil(L);
326-
327-
/* Processing a table with options. */
328-
int argc = 0;
329-
char **argv = malloc(1 * sizeof(char*));
352+
/* 0 element -- test name. Last -- ending NULL. */
353+
int argc = table_nkeys(L) + 1;
354+
char **argv = malloc((argc + 1) * sizeof(*argv));
330355
if (!argv)
331356
luaL_error(L, "not enough memory");
357+
358+
argv[0] = "<test name>";
332359
const char *corpus_path = NULL;
360+
361+
/* First key to start iteration. */
362+
lua_pushnil(L);
363+
int n_arg = 1;
333364
while (lua_next(L, -2) != 0) {
334-
char **argvp = realloc(argv, sizeof(char*) * (argc + 1));
335-
if (argvp == NULL) {
336-
free(argv);
337-
luaL_error(L, "not enough memory");
338-
}
339365
const char *key = lua_tostring(L, -2);
340366
const char *value = lua_tostring(L, -1);
341-
if (strcmp(key, "corpus") != 0) {
342-
size_t arg_len = strlen(key) + strlen(value) + 3;
343-
char *arg = calloc(arg_len, sizeof(char));
344-
if (!arg)
345-
luaL_error(L, "not enough memory");
346-
snprintf(arg, arg_len, "-%s=%s", key, value);
347-
argvp[argc] = arg;
348-
argc++;
349-
} else {
367+
if (strcmp(key, "corpus") == 0) {
350368
corpus_path = strdup(value);
369+
lua_pop(L, 1);
370+
continue;
351371
}
372+
size_t arg_len = strlen(key) + strlen(value) + 3;
373+
char *arg = malloc(arg_len * sizeof(*arg));
374+
if (!arg)
375+
luaL_error(L, "not enough memory");
376+
snprintf(arg, arg_len, "-%s=%s", key, value);
377+
argv[n_arg++] = arg;
352378
lua_pop(L, 1);
353-
argv = argvp;
354379
}
380+
355381
if (corpus_path) {
356-
argv[argc] = (char*)corpus_path;
357-
argc++;
358-
}
359-
if (argc == 0) {
360-
argv[argc] = "";
361-
argc++;
382+
argv[argc-1] = (char*)corpus_path;
362383
}
363384
argv[argc] = NULL;
364385
lua_pop(L, 1);
@@ -373,15 +394,18 @@ luaL_fuzz(lua_State *L)
373394

374395
/* Processing a function with custom mutator. */
375396
if (!lua_isnil(L, -1) && (lua_isfunction(L, -1) == 1)) {
376-
if (load_custom_mutator_lib())
397+
if (load_custom_mutator_lib()) {
398+
free_argv(argc, argv);
377399
luaL_error(L, "function LLVMFuzzerCustomMutator is not available");
400+
}
378401
luaL_set_custom_mutator(L);
379402
} else {
380403
lua_pop(L, 1);
381404
}
382405

383406
/* Processing a function LLVMFuzzerTestOneInput. */
384407
if (lua_isfunction(L, -1) != 1) {
408+
free_argv(argc, argv);
385409
luaL_error(L, "test_one_input is not a Lua function");
386410
}
387411
lua_setglobal(L, TEST_ONE_INPUT_FUNC);
@@ -395,12 +419,15 @@ luaL_fuzz(lua_State *L)
395419

396420
lua_getglobal(L, TEST_ONE_INPUT_FUNC);
397421
if (lua_isfunction(L, -1) != 1) {
422+
free_argv(argc, argv);
398423
luaL_error(L, "test_one_input is not defined");
399424
}
400425
lua_pop(L, -1);
401426

402427
set_global_lua_state(L);
403428
int rc = LLVMFuzzerRunDriver(&argc, &argv, &TestOneInput);
429+
430+
free_argv(argc, argv);
404431
luaL_cleanup(L);
405432

406433
lua_pushnumber(L, rc);

0 commit comments

Comments
 (0)