commit - 442f7ad87d59fba01c2e517a75032dfb69ccbd4b
commit + 069045d59af704cf8f0bf27432436e27b5712ede
blob - 39e35003aeb751ee86d026778836562e89c82661
blob + dc5c92c1a8050487908134d6172d991753dc5081
--- CHANGELOG.md
+++ CHANGELOG.md
### Fixed
- Fix searching Clang RT.
+- Stack overflow due to recursive traceback calls.
blob - 4f76421a49c64be403566d3f75ae3e1a88932534
blob + ac026f1d081536b6d23d317b6584b7a304a66405
--- luzer/CMakeLists.txt
+++ luzer/CMakeLists.txt
)
set(LUZER_SOURCES luzer.c
+ compat.c
fuzzed_data_provider.cc
tracer.c
counters.c
blob - /dev/null
blob + 2bc398c993cfe44c971913beff31b3c6ba368a9b (mode 644)
--- /dev/null
+++ luzer/compat.c
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
+
+#if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM == 501
+
+static int
+countlevels(lua_State *L) {
+ lua_Debug ar;
+ int li = 1, le = 1;
+ /* Find an upper bound. */
+ while (lua_getstack(L, le, &ar))
+ { li = le; le *= 2; }
+ /* Do a binary search. */
+ while (li < le) {
+ int m = (li + le) / 2;
+ if (lua_getstack(L, m, &ar))
+ li = m + 1;
+ else
+ le = m;
+ }
+ return le - 1;
+}
+
+static int
+findfield(lua_State *L, int objidx, int level) {
+ if (level == 0 || !lua_istable(L, -1))
+ /* Not found. */
+ return 0;
+
+ /* Start 'next' loop. */
+ lua_pushnil(L);
+ /* For each pair in table. */
+ while (lua_next(L, -2)) {
+ /* Ignore non-string keys. */
+ if (lua_type(L, -2) == LUA_TSTRING) {
+ /* Found an object? */
+ if (lua_rawequal(L, objidx, -1)) {
+ /* Remove value (but keep name). */
+ lua_pop(L, 1);
+ return 1;
+ }
+ /* Try recursively. */
+ else if (findfield(L, objidx, level - 1)) {
+ /* Remove table (but keep name). */
+ lua_remove(L, -2);
+ lua_pushliteral(L, ".");
+ /* Place '.' between the two names. */
+ lua_insert(L, -2);
+ lua_concat(L, 3);
+ return 1;
+ }
+ }
+ /* Remove value. */
+ lua_pop(L, 1);
+ }
+ /* Not found. */
+ return 0;
+}
+
+int
+lua_absindex(lua_State *L, int i) {
+ if (i < 0 && i > LUA_REGISTRYINDEX)
+ i += lua_gettop(L) + 1;
+ return i;
+}
+
+void
+lua_copy(lua_State *L, int from, int to) {
+ int abs_to = lua_absindex(L, to);
+ luaL_checkstack(L, 1, "not enough stack slots");
+ lua_pushvalue(L, from);
+ lua_replace(L, abs_to);
+}
+
+static int
+pushglobalfuncname(lua_State *L, lua_Debug *ar) {
+ int top = lua_gettop(L);
+ /* Push function. */
+ lua_getinfo(L, "f", ar);
+ lua_pushvalue(L, LUA_GLOBALSINDEX);
+ if (findfield(L, top + 1, 2)) {
+ /* Move name to proper place. */
+ lua_copy(L, -1, top + 1);
+ /* Remove pushed values. */
+ lua_pop(L, 2);
+ return 1;
+ }
+ else {
+ /* Remove function and global table. */
+ lua_settop(L, top);
+ return 0;
+ }
+}
+
+static void
+pushfuncname(lua_State *L, lua_Debug *ar) {
+ /* Is there a name? */
+ if (*ar->namewhat != '\0')
+ lua_pushfstring(L, "function " LUA_QS, ar->name);
+ else if (*ar->what == 'm') /* Main? */
+ lua_pushliteral(L, "main chunk");
+ else if (*ar->what == 'C') {
+ if (pushglobalfuncname(L, ar)) {
+ lua_pushfstring(L, "function " LUA_QS, lua_tostring(L, -1));
+ /* Remove name. */
+ lua_remove(L, -2);
+ }
+ else
+ lua_pushliteral(L, "?");
+ }
+ else
+ lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined);
+}
+
+/* Size of the first part of the stack. */
+#define LEVELS1 12
+/* Size of the second part of the stack. */
+#define LEVELS2 10
+
+void
+luaL_traceback(lua_State *L, lua_State *L1,
+ const char *msg, int level) {
+ lua_Debug ar;
+ int top = lua_gettop(L);
+ int numlevels = countlevels(L1);
+ int mark = (numlevels > LEVELS1 + LEVELS2) ? LEVELS1 : 0;
+ if (msg) lua_pushfstring(L, "%s\n", msg);
+ lua_pushliteral(L, "stack traceback:");
+ while (lua_getstack(L1, level++, &ar)) {
+ /* Too many levels? */
+ if (level == mark) {
+ /* Add a '...'. */
+ lua_pushliteral(L, "\n\t...");
+ /* And skip to last ones. */
+ level = numlevels - LEVELS2;
+ }
+ else {
+ lua_getinfo(L1, "Slnt", &ar);
+ lua_pushfstring(L, "\n\t%s:", ar.short_src);
+ if (ar.currentline > 0)
+ lua_pushfstring(L, "%d:", ar.currentline);
+ lua_pushliteral(L, " in ");
+ pushfuncname(L, &ar);
+ lua_concat(L, lua_gettop(L) - top);
+ }
+ }
+ lua_concat(L, lua_gettop(L) - top);
+}
+
+#endif
blob - /dev/null
blob + 7859dbb4055b9153a40bf7f544d0a3b8a50a0285 (mode 644)
--- /dev/null
+++ luzer/compat.h
+#ifndef LUZER_COMPAT_H_
+#define LUZER_COMPAT_H_
+
+void luaL_traceback(lua_State *L, lua_State *L1,
+ const char *msg, int level);
+
+#endif // LUZER_COMPAT_H_
blob - 4943749b01ea81ef9a32314750447497e724f0a8
blob + e740944321eb16fa400d8e86fb3e6cba3688772d
--- luzer/luzer.c
+++ luzer/luzer.c
#include "fuzzed_data_provider.h"
#include "counters.h"
+#include "compat.h"
#include "macros.h"
#include "tracer.h"
#include "version.h"
return LL;
}
-#if LUA_VERSION_NUM < 502
-static int
-luaL_traceback(lua_State *L) {
- lua_getfield(L, LUA_GLOBALSINDEX, "debug");
- if (!lua_istable(L, -1)) {
- lua_pop(L, 1);
- return 1;
- }
- lua_getfield(L, -1, "traceback");
- if (!lua_isfunction(L, -1)) {
- lua_pop(L, 2);
- return 1;
- }
- lua_pushvalue(L, 1);
- lua_pushinteger(L, 2);
- lua_call(L, 2, 1);
- fprintf(stderr, "%s\n", lua_tostring(L, -1));
- return 1;
-}
-#endif
-
#ifdef __cplusplus
extern "C" {
#endif
}
/**
- * Print the stack trace leading to this call. Useful for debugging user code.
- * See:
- * - https://github.com/keplerproject/lua-compat-5.2/blob/master/c-api/compat-5.2.c#L229
- * - http://www.lua.org/manual/5.2/manual.html#luaL_traceback
+ * Print a Lua stack trace leading to this call.
+ * Useful for debugging user code.
+ * See http://www.lua.org/manual/5.2/manual.html#luaL_traceback
*/
NO_SANITIZE void
__sanitizer_print_stack_trace(void)
{
lua_State *L = get_global_lua_state();
-#if LUA_VERSION_NUM < 502
- luaL_traceback(L);
-#else
- luaL_traceback(L, L, "traceback", 3);
-#endif
+ lua_State *L1 = luaL_newstate();
+ luaL_traceback(L, L1, "traceback", 3);
+ lua_close(L1);
}
#ifdef __cplusplus
} /* extern "C" */