lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


I have stumbled across a situation that causes Lua to crash.  I am wondering if this is a bug.

 

If a coroutine is created and immediately yields, then using the coroutine’s lua_State for a ‘lua_pcall’ to debug.traceback() will work fine.

However, if a coroutine is created and is assigned a debug hook which causes it to yield, then doing the same thing will cause the program to crash.

 

If the main lua_State performs the call to ‘debug.traceback()’, passing the coroutine as a parameter, then the debug.traceback() will work fine.

If the coroutine’s lua_State is used to invoke the C API ‘lua_getstack’ and ‘lua_getinfo’ then no crash will occur, though occasionally the currentline of the lua_Debug structure will be incorrect.

 

I have include a test case to reproduce the bug.  Compiling and running this code as it is will reproduce the bug.

 

 

#include <lua.h>

#include <lualib.h>

#include <lauxlib.h>

#include <stdio.h>

 

#define TEST1

//#define TEST2

//#define TEST3

 

static void yield_me(lua_State* L, lua_Debug* ar)

{

                if (ar->event == LUA_HOOKCOUNT || ar->event == LUA_HOOKLINE) {

                                lua_yield(L, 0);

                }

}

 

void test() {

                lua_State* Lmain = luaL_newstate();

                luaL_openlibs(Lmain);

 

                //running arbitrary code and yielding from a hook causes this crash

                if (luaL_loadstring(Lmain, "for i=1,100 do end") != LUA_OK) {

                                printf("luaL_loadstring failed\n");

                                return;

                }

 

                lua_State* Lco = lua_newthread(Lmain);               //Lmain: main, Lco

                lua_insert(Lmain, lua_gettop(Lmain) - 1);              //Lmain: Lco, main

                lua_xmove(Lmain, Lco, 1);            //Lmain: Lco, Lco: main

                lua_sethook(Lco, yield_me, LUA_MASKCOUNT, 10);

 

                int status = lua_resume(Lco, Lmain, 0);

                if (status != LUA_YIELD) {

                                printf("expected us to be yielded, got status %d\n", status);

                                return;

                }

 

                lua_Hook func = lua_gethook(Lco);

                int mask = lua_gethookmask(Lco);

                int count = lua_gethookcount(Lco);

                lua_sethook(Lco, NULL, 0, 0);

 

 

#ifdef TEST1       //running a traceback using the coroutine ... crashes

                if (luaL_loadstring(Lco, "print(debug.traceback())") != LUA_OK) {

                                printf("error\n");

                                return;

                }

                if (lua_pcall(Lco, 0, 0, 0) != LUA_OK) {

                                printf("error\n");

                                return;

                }

#endif

#ifdef TEST2       //calling debug.traceback() from the main lua_State, but passing 'Lco' as a parameter to debug.traceback() ... works

                lua_getglobal(Lmain, "debug");

                lua_getfield(Lmain, -1, "traceback");

                lua_pushthread(Lco);

                lua_xmove(Lco, Lmain, 1);

                if (lua_pcall(Lmain, 1, 0, 0) != LUA_OK) {

                                printf("error\n");

                                return;

                }

                lua_pop(Lmain, 1);

#endif

#ifdef TEST3       //Performing the traceback using the C API from the coroutine ... works, albeit with a bad line value

                lua_Debug ar;

                if (!lua_getstack(Lco, 0, &ar))

                {

                                printf("lua_getstack failed\n");

                                return;

                }

                else

                {

                                int status = lua_getinfo(Lco, "Sln", &ar);

                                if (!status) {

                                                printf("lua_getinfo failed\n");

                                                return;

                                }

                                printf("line: %d file: %s func: %s\n",

                                                ar.currentline,

                                                ar.short_src,

                                                ar.name ? ar.name : "(null)"

                                );

                }

#endif

 

                printf("worked\n");

 

                lua_close(Lmain);

}

 

int main() {

                test();

}