Печать stacktrace из кода C со встроенным lua - программирование

Печать stacktrace из кода C со встроенным lua

Если я правильно понял, Lua по умолчанию вызовет библиотеку отладки "debug.traceback" при возникновении ошибки.

Однако при вложении Lua в C-код, как это сделано в примере здесь: Пример простого Lua API

У нас есть только сообщение об ошибке в верхней части стека.

то есть.

if (status) {
    /* If something went wrong, error message is at the top of */
    /* the stack */
    fprintf(stderr, "Couldn't load file: %s\n", lua_tostring(L, -1));

    /* I want to print a stacktrace here. How do I do that? */
    exit(1);
}

Как распечатать трассировку стека из C после начальной ошибки?

4b9b3361

Ответ 1

Lua по умолчанию вызовет библиотеку отладки "debug.traceback" при возникновении ошибки.

Нет, не будет. Lua runtime (lua.exe) сделает это, но библиотека Lua не сделает этого самостоятельно. Если вам нужен стек вызовов с вашими ошибками Lua, вам необходимо сгенерировать его.

Среда выполнения Lua делает это с помощью функции lua_pcall. Когда функция ошибки вызывается, стек не разматывается, поэтому вы можете получить там трассировку стека. Функция ошибки, используемая во время выполнения, такова:

static int traceback (lua_State *L) {
  if (!lua_isstring(L, 1))  /* 'message' not a string? */
    return 1;  /* keep it intact */
  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);  /* pass error message */
  lua_pushinteger(L, 2);  /* skip this function and traceback */
  lua_call(L, 2, 1);  /* call debug.traceback */
  return 1;
}

Ответ 2

Ответ от Nicols, приведенный выше, является рабочим примером:

static int traceback(lua_State *L) {
    lua_getfield(L, LUA_GLOBALSINDEX, "debug");
    lua_getfield(L, -1, "traceback");
    lua_pushvalue(L, 1);
    lua_pushinteger(L, 2);
    lua_call(L, 2, 1);
    fprintf(stderr, "%s\n", lua_tostring(L, -1));
    return 1;
}

int main(int argc, char **argv) {
    lua_State *L = lua_open();
    luaL_openlibs(L);    
    lua_pushcfunction(L, traceback);
    int rv = luaL_loadfile(L, "src/main.lua");
    if (rv) {
        fprintf(stderr, "%s\n", lua_tostring(L, -1));
        return rv;
    } else {
        return lua_pcall(L, 0, 0, lua_gettop(L) - 1);
    }
}

Ответ 3

Я встретил некоторый вопрос так же, как и вы, и я нашел, что этот способ работает:

luaL_traceback(L, L, NULL, 1);
printf("%s\n", lua_tostring(L, -1));

Так как luaL_traceback является ровно debug.traceback(), использующим для печати стека, поэтому я считаю, что это может быть правильным способом, и вы можете прочитать руководство по API luaL_traceback или просто прочитать исходный код Lua, чтобы выяснить что означает параметры.

Ответ 4

Код mxcl имеет некоторые проблемы:

static int traceback(lua_State *L) {
    lua_getfield(L, LUA_GLOBALSINDEX, "debug");
    lua_getfield(L, -1, "traceback");
    //---------------------------
    lua_pop(L,-2); //to popup the 'debug'
    //---------------------------
    lua_pushvalue(L, 1);
    lua_pushinteger(L, 2);
    lua_call(L, 2, 1);
    fprintf(stderr, "%s\n", lua_tostring(L, -1));
    return 1;
}