1
\$\begingroup\$

I'm trying to hook lua-scripts to my entities, where several entities of the same type want to use a separate instance of the same script. Problem is, when I run two or more scripts and use any C-api functionality, I get an access violation after some time. I'm guessing some kind of stack corruption occurs but I'm not sure. The application is single-threaded but uses lua_newthread for each entity, and I then use lua_resume on each new thread for when I want the scripts to run. The code looks like this.

Script 1

function Update(dt, owner)
   print("Script 1")
   pos = GetPosition(owner)
end

Script 2

function Update(dt, owner)
   print("Script 2")
end

GetPosition()

static int GetPosition(lua_State* L)
    {
        Core::Entity entity = lua_tonumber(L, 1);
        Core::TransformationComponent* tc = WGETC<Core::TransformationComponent>(entity);

        lua_newtable(L);

        for (int i = 0; i < 2; i++)
        {
            lua_pushnumber(L, tc->position[i]);
            lua_rawseti(L, -2, i);
        }

        return 1;
    }

How I create new lua threads (m_luaState is the global parent state to which I bind all my functions):

lua_State* LuaCore::CreateThread(std::string file)
    {
        lua_State* newState = lua_newthread(m_luaState);

        lua_newtable(newState); //new globals table
        lua_newtable(newState); //metatable

        lua_pushliteral(newState, "__index");
        lua_pushvalue(newState, LUA_GLOBALSINDEX); //original globals 
        lua_settable(newState, -3);
        lua_setmetatable(newState, -2);
        lua_replace(newState, LUA_GLOBALSINDEX); //replace newState's globals

        luaL_dofile(newState, file.c_str());

        return newState;
    }

How each script is called:

            lua_State* ls = GetChildState(stateIndex)
            lua_pushstring(ls, functionName.c_str());
            lua_gettable(ls, LUA_GLOBALSINDEX);

            SimpleLuaCallData* slcd = (SimpleLuaCallData*)inData;

            lua_pushnumber(ls, slcd->dt);
            lua_pushnumber(ls, slcd->ownerID);

            lua_pcall(ls, 2, 0, 0);

            return nullptr;

If I remove the call to GetPosition from Script 1, the application runs without issue. Am I missing some kind of required clean-up or garbage collection problems? I'd like to try and avoid creating a new state for each entity, as that seems excessive and sharing globals via the core state is nice. lua_pcall doesn't produce any results. The application eventually stops running Script 1 and after a few more cycles it gets the access violation on

lua_gettable(ls, LUA_GLOBALSINDEX); 

in the calling function.

\$\endgroup\$
1
\$\begingroup\$

So turns out the solution was quite simple. When creating my threads I needed to get the reference to that thread, or it would get destroyed by the garbage collector. Why this didn't manifest when running only one script is beyond me, maybe someone can provide a good answer for that? New CreateThread method, for reference.

lua_State* LuaCore::CreateThread(std::string file, int& refKey)
    {
        lua_State* newState = lua_newthread(m_luaState);
        refKey = luaL_ref(m_luaState, LUA_REGISTRYINDEX);

        lua_newtable(newState); //new globals table
        lua_newtable(newState); //metatable

        lua_pushliteral(newState, "__index");
        lua_pushvalue(newState, LUA_GLOBALSINDEX); //original globals 
        lua_settable(newState, -3);
        lua_setmetatable(newState, -2);
        lua_replace(newState, LUA_GLOBALSINDEX); //replace newState's globals

        luaL_dofile(newState, file.c_str());

        return newState;
    }
\$\endgroup\$
  • \$\begingroup\$ FYI: You don't need to "get a reference" to that thread. You simply need to permanently store it somewhere in the Lua system. After calling that function, it's pushed on top of the stack, which will be emptied eventually. The registry is one place to store it, but there are other places too. It didn't manifest in the other case because garbage collection happens whenever and however Lua wants it to. \$\endgroup\$ – Nicol Bolas Dec 8 '15 at 19:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.