6

My C program probably has a silly bug. There is a certain point where the Lua stack doesn't contain the values that I think it should.

In order to debug it, I want to print the contents of the Lua stack at a certain point of my program. How can I do that without messing up the stack in the process?

hugomg
  • 68,213
  • 24
  • 160
  • 246
  • 2
    Does this answer your question: [Can we get stack trace for lua similar to core dump for C and C++ applications](https://stackoverflow.com/questions/5922337/can-we-get-stack-trace-for-lua-similar-to-core-dump-for-c-and-c-applications)? Or this: [Get true stack trace of an error in lua pcall](https://stackoverflow.com/q/45788739/69809)? – vgru Nov 28 '19 at 14:59
  • 2
    Unfortunately not. I already have a stack trace when my program crashes, and I already know what line it is crashing. What I want is to be able to print the Lua values that are being stored in the stack, for the current stack frame. That is, the contents of the slots from `1` to `get_top(L)` – hugomg Nov 28 '19 at 15:07
  • I don't see why this was closed as too broad (I voted dupe), so I voted to reopen. – vgru Nov 28 '19 at 16:36
  • 2
    This should not be closed as too broad. *The Lua stack* is a very specific thing, in the C API for Lua. It is not at all unclear. – user253751 Nov 28 '19 at 16:55
  • 1
    See http://lua-users.org/lists/lua-l/2017-12/msg00068.html – lhf Nov 29 '19 at 00:21

2 Answers2

11

This answer is a slightly edited version of the answer provided by @lhf in the comments.

It has the advantage that it does not modify any values in the stack, and does not require any additional space.

static void dumpstack (lua_State *L) {
  int top=lua_gettop(L);
  for (int i=1; i <= top; i++) {
    printf("%d\t%s\t", i, luaL_typename(L,i));
    switch (lua_type(L, i)) {
      case LUA_TNUMBER:
        printf("%g\n",lua_tonumber(L,i));
        break;
      case LUA_TSTRING:
        printf("%s\n",lua_tostring(L,i));
        break;
      case LUA_TBOOLEAN:
        printf("%s\n", (lua_toboolean(L, i) ? "true" : "false"));
        break;
      case LUA_TNIL:
        printf("%s\n", "nil");
        break;
      default:
        printf("%p\n",lua_topointer(L,i));
        break;
    }
  }
}

If you want, you can also use lua_isinteger(L, i) inside the LUA_TNUMBER case in order to distinguish between integers and floating-point numbers.

hugomg
  • 68,213
  • 24
  • 160
  • 246
1

This code traverses the stack from top to bottom and calls tostring on every value, printing the result (if no result is obtained, it prints the type name).

assert(lua_checkstack(L, 3));
int top = lua_gettop(L);
int bottom = 1;
lua_getglobal(L, "tostring");
for(int i = top; i >= bottom; i--)
{
    lua_pushvalue(L, -1);
    lua_pushvalue(L, i);
    lua_pcall(L, 1, 1, 0);
    const char *str = lua_tostring(L, -1);
    if (str) {
        printf("%s\n", str);
    }else{
        printf("%s\n", luaL_typename(L, i));
    }
    lua_pop(L, 1);
}
lua_pop(L, 1);
IS4
  • 11,945
  • 2
  • 47
  • 86
  • You have forgotten to check the space available in Lua C API stack – Egor Skriptunoff Nov 28 '19 at 17:22
  • Unfortunately, this solution does not preserve the value of `L->top` so it doesn't work for me. – hugomg Nov 28 '19 at 20:30
  • @hugomg It does not? When the code ends, it should have the initial value. – IS4 Nov 28 '19 at 23:39
  • A fixed version of this code would have to ensure that there is enough space available to push the extra elements, which might require reallocating the stack. You are right that most of the time this should not matter, but it does mean that if you are trying to debug a crash involving the Lua stack calling thid print function could change the behavior of the program you are trying to debug. – hugomg Nov 29 '19 at 00:05
  • 1
    This code changes the values in the stack: it converts numbers to strings. – lhf Nov 29 '19 at 00:22