[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: coroutine.resume() crash
- From: John Dunn <John.Dunn@...>
- Date: Thu, 8 Sep 2022 18:22:18 +0000
I am using Lua 5.3.2 and have some Lua modules that implement asynchronous callbacks. I was trying to wrap them in coroutines to make them act a little more like async/await and when I do that I get a crash
ldo:636
Exception thrown: read access violation
ci->u.l.base was 0xFFFFFFFFFFFFFFFF
Here's example code that shows the problem - it crashes when running 'bad_lua'. Am I just misunderstanding how coroutines can operate?
#include <lua/lua.hpp>
#include <string>
#include <iostream>
struct timer_t
{
lua_State* L;
int handler_index{ LUA_REFNIL };
void trigger()
{
std::cout << __FUNCTION__ << std::endl;
lua_rawgeti(L, LUA_REGISTRYINDEX, handler_index);
lua_pcall(L, 0, 0, 0);
}
};
timer_t* the_timer = nullptr;
static int timer_call_after(lua_State* L)
{
std::cout << __FUNCTION__ << std::endl;
timer_t** timer = (timer_t**)lua_newuserdata(L, sizeof(timer_t*));
*timer = new timer_t();
(*timer)->L = L;
// store function
lua_pushvalue(L, 1);
(*timer)->handler_index = luaL_ref(L, LUA_REGISTRYINDEX);;
// stash timer
the_timer = *timer;
return 0;
}
static const struct luaL_Reg timer_lib_methods[] =
{
{ "CallAfter", timer_call_after },
{NULL,NULL}
};
void timer_init(lua_State* L)
{
luaL_register(L, "Timer", timer_lib_methods);
}
const char* good_lua = R"XXX(
print("init good")
Timer.CallAfter(function() print("tick") end, time)
print("init good")
)XXX";
const char* bad_lua = R"XXX(
function wait(time)
co = coroutine.running()
Timer.CallAfter(function() coroutine.resume(co) end, time)
return coroutine.yield()
end
function get_some_times()
c = wait(2)
end
func = coroutine.wrap(get_some_times)
func()
print("init good")
)XXX";
void run(const char* code)
{
lua_State* L = luaL_newstate();
luaL_openlibs(L);
timer_init(L);
luaL_loadbuffer(L, code, strlen(code), "=");
lua_pcall(L, 0, LUA_MULTRET, 0);
// synthesize timer trigger
the_timer->trigger();
}
int main(int argc, char** argv)
{
std::cout << "running good code" << std::endl;
run(good_lua);
std::cout << "running bad code" << std::endl;
run(bad_lua);
return 0;
}