Fix LuaSmartRefs acting on dead Lua states

This fixes problems with degenerate cases such as:

	local button
	assert(coroutine.resume(coroutine.create(function()
		button = Button(10, 10, 20, 20)
	end)))
	button:action(function()
		print("hi")
	end)
This commit is contained in:
Tamás Bálint Misius 2020-08-21 11:02:51 +02:00
parent f9c6633c62
commit fd032eff36
No known key found for this signature in database
GPG Key ID: 5B472A12F6ECA9F2
13 changed files with 91 additions and 58 deletions

View File

@ -348,7 +348,7 @@ int luatpt_element_func(lua_State *l)
int replace = luaL_optint(l, 3, 0);
if (luacon_sim->IsValidElement(element))
{
lua_el_func[element].Assign(1);
lua_el_func[element].Assign(l, 1);
if (replace == 2)
lua_el_mode[element] = 3; //update before
else if (replace)
@ -428,7 +428,7 @@ int luatpt_graphics_func(lua_State *l)
int element = luaL_optint(l, 2, 0);
if (luacon_sim->IsValidElement(element))
{
lua_gr_func[element].Assign(1);
lua_gr_func[element].Assign(l, 1);
luacon_ren->graphicscache[element].isready = 0;
return 0;
}

View File

@ -53,7 +53,7 @@ int LuaButton::enabled(lua_State * l)
int LuaButton::action(lua_State * l)
{
return actionFunction.CheckAndAssignArg1();
return actionFunction.CheckAndAssignArg1(l);
}
int LuaButton::text(lua_State * l)

View File

@ -51,7 +51,7 @@ int LuaCheckbox::checked(lua_State * l)
int LuaCheckbox::action(lua_State * l)
{
return actionFunction.CheckAndAssignArg1();
return actionFunction.CheckAndAssignArg1(l);
}
int LuaCheckbox::text(lua_State * l)

View File

@ -8,6 +8,15 @@ int luaL_typerror (lua_State *L, int narg, const char *tname)
return luaL_argerror(L, narg, msg);
}
void tpt_lua_setmainthread(lua_State *L)
{
}
void tpt_lua_getmainthread(lua_State *L)
{
lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD);
}
#else
// Implement function added in lua 5.2 that we now use
@ -16,6 +25,17 @@ void lua_pushglobaltable(lua_State *L)
lua_pushvalue(L, LUA_GLOBALSINDEX);
}
void tpt_lua_setmainthread(lua_State *L)
{
lua_pushthread(L);
lua_setfield(L, LUA_REGISTRYINDEX, "tpt_lua_mainthread");
}
void tpt_lua_getmainthread(lua_State *L)
{
lua_getfield(L, LUA_REGISTRYINDEX, "tpt_lua_mainthread");
}
#endif
// Useful helper function, mainly used for logging

View File

@ -24,6 +24,9 @@ extern "C"
#include "lua5.1/lualib.h"
#endif
LUALIB_API void tpt_lua_setmainthread(lua_State *L);
LUALIB_API void tpt_lua_getmainthread(lua_State *L);
#if LUA_VERSION_NUM >= 502
LUALIB_API int (luaL_typerror) (lua_State *L, int narg, const char *tname);
#else

View File

@ -7,20 +7,20 @@
#include "gui/interface/Component.h"
#include "gui/interface/Window.h"
int LuaComponentCallback::CheckAndAssignArg1()
int LuaComponentCallback::CheckAndAssignArg1(lua_State *l)
{
if (lua_type(l, 1) != LUA_TNIL)
{
luaL_checktype(l, 1, LUA_TFUNCTION);
}
LuaSmartRef::Assign(1);
LuaSmartRef::Assign(l, 1);
return 0;
}
LuaComponent::LuaComponent(lua_State * l) : owner_ref(LUA_REFNIL)
{
this->l = l;
this->l = l; // I don't get how this doesn't cause crashes later on
lua_pushstring(l, "Luacon_ci");
lua_gettable(l, LUA_REGISTRYINDEX);
ci = (LuaScriptInterface*)lua_touserdata(l, -1);

View File

@ -14,7 +14,7 @@ class LuaComponentCallback : public LuaSmartRef
{
public:
using LuaSmartRef::LuaSmartRef;
int CheckAndAssignArg1();
int CheckAndAssignArg1(lua_State *l);
};
class LuaComponent

View File

@ -125,6 +125,7 @@ LuaScriptInterface::LuaScriptInterface(GameController * c, GameModel * m):
//New TPT API
l = luaL_newstate();
tpt_lua_setmainthread(l);
lua_atpanic(l, atPanic);
luaL_openlibs(l);
luaopen_bit(l);
@ -291,7 +292,7 @@ tpt.partsdata = nil");
}
tptPart = new LuaSmartRef(l);
tptPart->Assign(-1);
tptPart->Assign(l, -1);
lua_pop(l, 1);
#endif
@ -522,7 +523,7 @@ int LuaScriptInterface::interface_addComponent(lua_State * l)
if (ok.second)
{
auto it = ok.first;
it->second.Assign(1);
it->second.Assign(l, 1);
it->first->owner_ref = it->second;
}
luacon_ci->Window->AddComponent(luaComponent->GetComponent());
@ -2818,7 +2819,7 @@ int LuaScriptInterface::elements_element(lua_State * l)
lua_getfield(l, -1, "Update");
if (lua_type(l, -1) == LUA_TFUNCTION)
{
lua_el_func[id].Assign(-1);
lua_el_func[id].Assign(l, -1);
lua_el_mode[id] = 1;
}
else if (lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1))
@ -2832,7 +2833,7 @@ int LuaScriptInterface::elements_element(lua_State * l)
lua_getfield(l, -1, "Graphics");
if (lua_type(l, -1) == LUA_TFUNCTION)
{
lua_gr_func[id].Assign(-1);
lua_gr_func[id].Assign(l, -1);
}
else if (lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1))
{
@ -2844,7 +2845,7 @@ int LuaScriptInterface::elements_element(lua_State * l)
lua_getfield(l, -1, "Create");
if (lua_type(l, -1) == LUA_TFUNCTION)
{
luaCreateHandlers[id].Assign(-1);
luaCreateHandlers[id].Assign(l, -1);
luacon_sim->elements[id].Create = luaCreateWrapper;
}
else if (lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1))
@ -2857,7 +2858,7 @@ int LuaScriptInterface::elements_element(lua_State * l)
lua_getfield(l, -1, "CreateAllowed");
if (lua_type(l, -1) == LUA_TFUNCTION)
{
luaCreateAllowedHandlers[id].Assign(-1);
luaCreateAllowedHandlers[id].Assign(l, -1);
luacon_sim->elements[id].CreateAllowed = luaCreateAllowedWrapper;
}
else if (lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1))
@ -2870,7 +2871,7 @@ int LuaScriptInterface::elements_element(lua_State * l)
lua_getfield(l, -1, "ChangeType");
if (lua_type(l, -1) == LUA_TFUNCTION)
{
luaChangeTypeHandlers[id].Assign(-1);
luaChangeTypeHandlers[id].Assign(l, -1);
luacon_sim->elements[id].ChangeType = luaChangeTypeWrapper;
}
else if (lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1))
@ -2883,7 +2884,7 @@ int LuaScriptInterface::elements_element(lua_State * l)
lua_getfield(l, -1, "CtypeDraw");
if (lua_type(l, -1) == LUA_TFUNCTION)
{
luaCtypeDrawHandlers[id].Assign(-1);
luaCtypeDrawHandlers[id].Assign(l, -1);
luacon_sim->elements[id].CtypeDraw = luaCtypeDrawWrapper;
}
else if (lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1))
@ -2998,7 +2999,7 @@ int LuaScriptInterface::elements_property(lua_State * l)
lua_el_mode[id] = 1; //update after
break;
}
lua_el_func[id].Assign(3);
lua_el_func[id].Assign(l, 3);
}
else if (lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, 3))
{
@ -3011,7 +3012,7 @@ int LuaScriptInterface::elements_property(lua_State * l)
{
if (lua_type(l, 3) == LUA_TFUNCTION)
{
lua_gr_func[id].Assign(3);
lua_gr_func[id].Assign(l, 3);
}
else if (lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, 3))
{
@ -3024,7 +3025,7 @@ int LuaScriptInterface::elements_property(lua_State * l)
{
if (lua_type(l, 3) == LUA_TFUNCTION)
{
luaCreateHandlers[id].Assign(3);
luaCreateHandlers[id].Assign(l, 3);
luacon_sim->elements[id].Create = luaCreateWrapper;
}
else if (lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, 3))
@ -3037,7 +3038,7 @@ int LuaScriptInterface::elements_property(lua_State * l)
{
if (lua_type(l, 3) == LUA_TFUNCTION)
{
luaCreateAllowedHandlers[id].Assign(3);
luaCreateAllowedHandlers[id].Assign(l, 3);
luacon_sim->elements[id].CreateAllowed = luaCreateAllowedWrapper;
}
else if (lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, 3))
@ -3050,7 +3051,7 @@ int LuaScriptInterface::elements_property(lua_State * l)
{
if (lua_type(l, 3) == LUA_TFUNCTION)
{
luaChangeTypeHandlers[id].Assign(3);
luaChangeTypeHandlers[id].Assign(l, 3);
luacon_sim->elements[id].ChangeType = luaChangeTypeWrapper;
}
else if (lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, 3))
@ -3063,7 +3064,7 @@ int LuaScriptInterface::elements_property(lua_State * l)
{
if (lua_type(l, 3) == LUA_TFUNCTION)
{
luaCtypeDrawHandlers[id].Assign(3);
luaCtypeDrawHandlers[id].Assign(l, 3);
luacon_sim->elements[id].CtypeDraw = luaCtypeDrawWrapper;
}
else if (lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, 3))

View File

@ -51,7 +51,7 @@ int LuaSlider::steps(lua_State * l)
int LuaSlider::onValueChanged(lua_State * l)
{
return onValueChangedFunction.CheckAndAssignArg1();
return onValueChangedFunction.CheckAndAssignArg1(l);
}
int LuaSlider::value(lua_State * l)

View File

@ -3,14 +3,16 @@
void LuaSmartRef::Clear()
{
luaL_unref(l, LUA_REGISTRYINDEX, ref);
luaL_unref(rootl, LUA_REGISTRYINDEX, ref);
ref = LUA_REFNIL;
}
LuaSmartRef::LuaSmartRef(lua_State *state) :
ref(LUA_REFNIL),
l(state)
LuaSmartRef::LuaSmartRef(lua_State *l) :
ref(LUA_REFNIL)
{
tpt_lua_getmainthread(l);
rootl = lua_tothread(l, -1);
lua_pop(l, 1);
}
LuaSmartRef::~LuaSmartRef()
@ -18,20 +20,21 @@ LuaSmartRef::~LuaSmartRef()
Clear();
}
void LuaSmartRef::Assign(int index)
void LuaSmartRef::Assign(lua_State *l, int index)
{
if (index < 0)
{
index = lua_gettop(l) + index + 1;
}
Clear();
lua_pushvalue(l, index);
ref = luaL_ref(l, LUA_REGISTRYINDEX);
}
LuaSmartRef::operator int() const
int LuaSmartRef::Push(lua_State *l)
{
return ref;
lua_rawgeti(l, LUA_REGISTRYINDEX, ref);
return lua_type(l, -1);
}
LuaSmartRef::operator bool() const
{
return ref != LUA_REFNIL;
}
#endif

View File

@ -5,16 +5,22 @@
class LuaSmartRef
{
int ref;
protected:
lua_State *l;
lua_State *rootl;
public:
LuaSmartRef(lua_State *l);
~LuaSmartRef();
void Assign(int index); // Copies the value before getting reference, stack unchanged.
void Assign(lua_State *l, int index); // Copies the value before getting reference, stack unchanged.
void Clear();
operator int() const;
operator bool() const;
};
int Push(lua_State *l); // Always pushes exactly one value, possibly nil.
inline operator int() const
{
return ref;
}
inline operator bool() const
{
return ref != LUA_REFNIL;
}
};

View File

@ -55,7 +55,7 @@ int LuaTextbox::readonly(lua_State * l)
int LuaTextbox::onTextChanged(lua_State * l)
{
return onTextChangedFunction.CheckAndAssignArg1();
return onTextChangedFunction.CheckAndAssignArg1(l);
}
void LuaTextbox::triggerOnTextChanged()

View File

@ -131,7 +131,7 @@ int LuaWindow::addComponent(lua_State * l)
if (ok.second)
{
auto it = ok.first;
it->second.Assign(1);
it->second.Assign(l, 1);
it->first->owner_ref = it->second;
}
window->AddComponent(luaComponent->GetComponent());
@ -416,72 +416,72 @@ void LuaWindow::triggerOnKeyRelease(int key, int scan, bool repeat, bool shift,
int LuaWindow::onInitialized(lua_State * l)
{
return onInitializedFunction.CheckAndAssignArg1();
return onInitializedFunction.CheckAndAssignArg1(l);
}
int LuaWindow::onExit(lua_State * l)
{
return onExitFunction.CheckAndAssignArg1();
return onExitFunction.CheckAndAssignArg1(l);
}
int LuaWindow::onTick(lua_State * l)
{
return onTickFunction.CheckAndAssignArg1();
return onTickFunction.CheckAndAssignArg1(l);
}
int LuaWindow::onDraw(lua_State * l)
{
return onDrawFunction.CheckAndAssignArg1();
return onDrawFunction.CheckAndAssignArg1(l);
}
int LuaWindow::onFocus(lua_State * l)
{
return onFocusFunction.CheckAndAssignArg1();
return onFocusFunction.CheckAndAssignArg1(l);
}
int LuaWindow::onBlur(lua_State * l)
{
return onBlurFunction.CheckAndAssignArg1();
return onBlurFunction.CheckAndAssignArg1(l);
}
int LuaWindow::onTryExit(lua_State * l)
{
return onTryExitFunction.CheckAndAssignArg1();
return onTryExitFunction.CheckAndAssignArg1(l);
}
int LuaWindow::onTryOkay(lua_State * l)
{
return onTryOkayFunction.CheckAndAssignArg1();
return onTryOkayFunction.CheckAndAssignArg1(l);
}
int LuaWindow::onMouseMove(lua_State * l)
{
return onMouseMoveFunction.CheckAndAssignArg1();
return onMouseMoveFunction.CheckAndAssignArg1(l);
}
int LuaWindow::onMouseDown(lua_State * l)
{
return onMouseDownFunction.CheckAndAssignArg1();
return onMouseDownFunction.CheckAndAssignArg1(l);
}
int LuaWindow::onMouseUp(lua_State * l)
{
return onMouseUpFunction.CheckAndAssignArg1();
return onMouseUpFunction.CheckAndAssignArg1(l);
}
int LuaWindow::onMouseWheel(lua_State * l)
{
return onMouseWheelFunction.CheckAndAssignArg1();
return onMouseWheelFunction.CheckAndAssignArg1(l);
}
int LuaWindow::onKeyPress(lua_State * l)
{
return onKeyPressFunction.CheckAndAssignArg1();
return onKeyPressFunction.CheckAndAssignArg1(l);
}
int LuaWindow::onKeyRelease(lua_State * l)
{
return onKeyReleaseFunction.CheckAndAssignArg1();
return onKeyReleaseFunction.CheckAndAssignArg1(l);
}