Make properties and callbacks of non-custom tools read-only

Non-custom here means any built-in tool but also the ElementTool associated with elements, including custom ones. So, describing the tools this commit affects as "built-in tools" wouldn't quite be correct. It was even possible to cause crashes by freeing such tools.

Also fix crashes when attempting to access non-custom tools as if they were custom tools. The incorrect assumption was that GameModel::GetToolIndex succeeding means that LuaScriptInterface::customTools has an entry for the tool, but this is only guaranteed for custom tools.
This commit is contained in:
Tamás Bálint Misius
2024-12-09 21:18:18 +01:00
parent 860ba13899
commit 5540517368
2 changed files with 25 additions and 8 deletions

View File

@@ -60,6 +60,7 @@ struct CustomElement
struct CustomTool struct CustomTool
{ {
bool valid = false;
LuaSmartRef perform; LuaSmartRef perform;
LuaSmartRef click; LuaSmartRef click;
LuaSmartRef drag; LuaSmartRef drag;

View File

@@ -32,13 +32,15 @@ static int allocate(lua_State *L)
lsi->gameModel->BuildMenus(); lsi->gameModel->BuildMenus();
auto index = *lsi->gameModel->GetToolIndex(lsi->gameModel->GetToolFromIdentifier(identifier)); auto index = *lsi->gameModel->GetToolIndex(lsi->gameModel->GetToolFromIdentifier(identifier));
lsi->customTools.resize(std::max(int(lsi->customTools.size()), index + 1)); lsi->customTools.resize(std::max(int(lsi->customTools.size()), index + 1));
lsi->customTools[index].valid = true;
lua_pushinteger(L, index); lua_pushinteger(L, index);
return 1; return 1;
} }
static bool IsDefault(Tool *tool) static bool IsCustom(int index)
{ {
return tool->Identifier.BeginsWith("DEFAULT_"); auto *lsi = GetLSI();
return index >= 0 && index < int(lsi->customTools.size()) && lsi->customTools[index].valid;
} }
static int ffree(lua_State *L) static int ffree(lua_State *L)
@@ -50,9 +52,9 @@ static int ffree(lua_State *L)
{ {
return luaL_error(L, "Invalid tool"); return luaL_error(L, "Invalid tool");
} }
if (IsDefault(tool)) if (!IsCustom(index))
{ {
return luaL_error(L, "Cannot free default tools"); return luaL_error(L, "Can only free custom tools");
} }
lsi->customTools[index] = {}; lsi->customTools[index] = {};
lsi->gameModel->FreeTool(tool); lsi->gameModel->FreeTool(tool);
@@ -285,6 +287,10 @@ static int property(lua_State *L)
{ {
return luaL_error(L, "Invalid tool"); return luaL_error(L, "Invalid tool");
} }
if (lua_gettop(L) > 2 && !IsCustom(index))
{
return luaL_error(L, "Can only change properties of custom tools");
}
ByteString propertyName = tpt_lua_checkByteString(L, 2); ByteString propertyName = tpt_lua_checkByteString(L, 2);
auto handleCallback = [lsi, L, index, tool, &propertyName]( auto handleCallback = [lsi, L, index, tool, &propertyName](
auto customToolMember, auto customToolMember,
@@ -296,10 +302,6 @@ static int property(lua_State *L)
{ {
if (lua_gettop(L) > 2) if (lua_gettop(L) > 2)
{ {
if (IsDefault(tool))
{
luaL_error(L, "Cannot change callbacks of default tools");
}
if (lua_type(L, 3) == LUA_TFUNCTION) if (lua_type(L, 3) == LUA_TFUNCTION)
{ {
(lsi->customTools[index].*customToolMember).Assign(L, 3); (lsi->customTools[index].*customToolMember).Assign(L, 3);
@@ -383,6 +385,19 @@ static int exists(lua_State *L)
return 1; return 1;
} }
static int isCustom(lua_State *L)
{
auto *lsi = GetLSI();
int index = luaL_checkinteger(L, 1);
auto *tool = lsi->gameModel->GetToolByIndex(index);
if (!tool)
{
return luaL_error(L, "Invalid tool");
}
lua_pushboolean(L, IsCustom(index));
return 1;
}
void LuaTools::Open(lua_State *L) void LuaTools::Open(lua_State *L)
{ {
auto *lsi = GetLSI(); auto *lsi = GetLSI();
@@ -391,6 +406,7 @@ void LuaTools::Open(lua_State *L)
LFUNC(allocate), LFUNC(allocate),
LFUNC(property), LFUNC(property),
LFUNC(exists), LFUNC(exists),
LFUNC(isCustom),
#undef LFUNC #undef LFUNC
{ "free", ffree }, { "free", ffree },
{ NULL, NULL } { NULL, NULL }