lua-users home
lua-l archive

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


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;
}