From 174de2caed52d2b83b6ff2f702d5b9c27edb1f5e Mon Sep 17 00:00:00 2001 From: GinjaNinja32 Date: Thu, 16 May 2024 20:39:04 +0100 Subject: [PATCH 1/5] Improve sandboxing setup; re-allow get/setmetatable - Give each script its own proxy for global tables; this allows scripts to set e.g. `string.foo = ...` without affecting other scripts' view of the library. - Protect all important metatables for values provided by C++ - Remove getmetatable and setmetatable from the list of disallowed functions --- CMakeLists.txt | 2 + src/scriptInterface.cpp | 82 ++++++++++++++++++++++++++-------- src/scriptInterfaceMagic.h | 9 ++++ src/scriptInterfaceSandbox.cpp | 65 +++++++++++++++++++++++++++ src/scriptInterfaceSandbox.h | 23 ++++++++++ 5 files changed, 163 insertions(+), 18 deletions(-) create mode 100644 src/scriptInterfaceSandbox.cpp create mode 100644 src/scriptInterfaceSandbox.h diff --git a/CMakeLists.txt b/CMakeLists.txt index f83f0cb..259342a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -173,6 +173,7 @@ set(source_files #All SeriousProton's objects to compile src/resources.cpp src/scriptInterface.cpp src/scriptInterfaceMagic.cpp + src/scriptInterfaceSandbox.cpp src/shaderManager.cpp src/soundManager.cpp src/stringImproved.cpp @@ -252,6 +253,7 @@ set(source_files #All SeriousProton's objects to compile src/resources.h src/scriptInterface.h src/scriptInterfaceMagic.h + src/scriptInterfaceSandbox.h src/shaderManager.h src/soundManager.h src/stringImproved.h diff --git a/src/scriptInterface.cpp b/src/scriptInterface.cpp index 2a086c3..3f01c61 100644 --- a/src/scriptInterface.cpp +++ b/src/scriptInterface.cpp @@ -3,6 +3,7 @@ #include "random.h" #include "resources.h" #include "scriptInterface.h" +#include "scriptInterfaceSandbox.h" static int random(lua_State* L) { @@ -118,35 +119,80 @@ void ScriptObject::createLuaState() { luaL_requiref(L, lib->name, lib->func, 1); lua_pop(L, 1); /* remove lib */ + + // for any library that isn't the global base, it will have registered a table we need to make read-only + if (strcmp(lib->name, "_G")) { + lua_getglobal(L, lib->name); + makeReadonlyLuaProxy(L); + lua_setglobal(L, lib->name); + } } - } - //Remove unsafe base functions. - lua_pushnil(L); - lua_setglobal(L, "collectgarbage"); - lua_pushnil(L); - lua_setglobal(L, "dofile"); - lua_pushnil(L); - lua_setglobal(L, "getmetatable"); - lua_pushnil(L); - lua_setglobal(L, "loadfile"); - lua_pushnil(L); - lua_setglobal(L, "load"); - lua_pushnil(L); - lua_setglobal(L, "rawequal"); - lua_pushnil(L); - lua_setglobal(L, "setmetatable"); + //Remove unsafe base functions. + lua_pushnil(L); + lua_setglobal(L, "collectgarbage"); + lua_pushnil(L); + lua_setglobal(L, "dofile"); + lua_pushnil(L); + lua_setglobal(L, "loadfile"); + lua_pushnil(L); + lua_setglobal(L, "load"); + lua_pushnil(L); + lua_setglobal(L, "rawequal"); + + // Protect the metatable the string library sets on strings. + // This metatable points to the global `string` library, rather than the environment's proxy. + // This global string library table can't be accessed directly, but it means a function defining + // `function string.foo(...)` can't call that function as `"some_string":foo()` since the metatable + // points to the global version rather than its own editable proxy. + // TODO see if this can be fixed without breaking the sandbox. probably not. + lua_pushstring(L, ""); + protectLuaMetatable(L); + lua_pop(L, 1); + + // Replace the standard _G with a read-only proxy. + // We'll set _G in the script's environment to be that environment to act more like Lua's _G, but if the script sets `_G = nil` it'll clear that and get whatever _G exists in the global table. + // This is also a useful place to store the protected version of the real global table so we can use that as __index for the script environment metatable. + lua_pushglobaltable(L); + makeReadonlyLuaProxy(L); + lua_setglobal(L, "_G"); + } //Setup a new table as the first upvalue. This will be used as "global" environment for the script. And thus will prevent global namespace polution. lua_newtable(L); /* environment for loaded function */ + // set a _G in the script's environment pointing to its own global environment + lua_pushstring(L, "_G"); + lua_pushvalue(L, -2); + lua_rawset(L, -3); + + // Register proxies for the global libraries + // We've made the global libraries' tables read-only, but some scripts will want to do `table.foo = function(...) ... end` to add to the standard set. + // Give each script its own editable proxy with a metatable pointing at the global library (which itself is a readonly proxy, since setting this local proxy to nil would reveal the global one) + for (const luaL_Reg *lib = loadedlibs; lib->func; lib++) + { + if (!strcmp(lib->name, "_G")) { + continue; + } + + lua_pushstring(L, lib->name); + lua_getglobal(L, lib->name); + makeEditableLuaProxy(L); + lua_rawset(L, -3); + } + //Register all global functions for our game. for(ScriptClassInfo* item = scriptClassInfoList; item != NULL; item = item->next) item->register_function(L); - lua_newtable(L); /* meta table for the environment, with an __index pointing to the general global table so we can access every global function */ + // Create a metatable for the script environment. + // Note that unlike all other metatables we set up, this metatable is _not_ protected. + // This is to allow the sandboxed code to set metatable bits on its own environment, since we don't let it wrap the actual table. + // This isn't a security issue since the only things it allows the script to do are 1) mess with its own environment, and 2) see the read-only global table proxy in __index + // TODO: probably all non-script access to the environment table should be rawget/rawset so we don't have to worry about the sandboxed code doing something funky in __index/__newindex? + lua_newtable(L); lua_pushstring(L, "__index"); - lua_pushglobaltable(L); + lua_getglobal(L, "_G"); lua_rawset(L, -3); lua_setmetatable(L, -2); diff --git a/src/scriptInterfaceMagic.h b/src/scriptInterfaceMagic.h index 696fdaa..ba8709d 100644 --- a/src/scriptInterfaceMagic.h +++ b/src/scriptInterfaceMagic.h @@ -10,6 +10,7 @@ #include "P.h" #include "stringImproved.h" #include "lua/lua.hpp" +#include "scriptInterfaceSandbox.h" #include "glm/gtc/type_precision.hpp" #include #include @@ -196,6 +197,10 @@ struct convert> P** p = static_cast< P** >(lua_newuserdata(L, sizeof(P*))); *p = new P(); (**p) = ptr; + + // protect the new userdata's metatable + protectLuaMetatable(L); + lua_settable(L, -3); lua_pushlightuserdata(L, ptr); @@ -598,6 +603,10 @@ template class scriptBindObject lua_pop(L, 1); luaL_newmetatable(L, objectTypeName); } + + lua_pushstring(L, "__metatable"); // protect the metatable + lua_pushstring(L, "sandbox"); + lua_settable(L, metatable); lua_pushstring(L, "__gc"); lua_pushcfunction(L, gc_collect); diff --git a/src/scriptInterfaceSandbox.cpp b/src/scriptInterfaceSandbox.cpp new file mode 100644 index 0000000..3a56dfb --- /dev/null +++ b/src/scriptInterfaceSandbox.cpp @@ -0,0 +1,65 @@ +#include "lua/lua.hpp" +#include "scriptInterfaceSandbox.h" + +int reject_write(lua_State* L) { + lua_pop(L, lua_gettop(L)); + lua_pushstring(L, "cannot write to sandbox-external library"); + lua_error(L); + return 0; +} + +// Add or protect a metatable, and add that metatable to the stack. +// Input Lua stack: [object] +// Output Lua stack: [object] [mt] +void protectGetLuaMetatable(lua_State* L) +{ + if (!lua_getmetatable(L, -1)) { + lua_newtable(L); // [object] [mt] + lua_pushvalue(L, -1); // [object] [mt] [mt] + lua_setmetatable(L, -3); // [object] [mt] + } + + lua_pushstring(L, "__metatable"); // [object] [mt] "__metatable" + lua_pushstring(L, "sandbox"); // [object] [mt] "__metatable" "sandbox" + lua_settable(L, -3); // [object] [mt] +} + +void protectLuaMetatable(lua_State* L) +{ + protectGetLuaMetatable(L); // [object] [mt] + lua_pop(L, 1); // [object] +} + +// Make the base proxy for a table, and return the proxy and its metatable. +// Input Lua stack: [table] +// Output Lua stack: [proxy] [mt] +void makeLuaProxy(lua_State* L) +{ + lua_newtable(L); // [table] [proxy] + + // Add a protected metatable + protectGetLuaMetatable(L); // [table] [proxy] [mt] + + // Set the metatable's __index to the original table + lua_pushstring(L, "__index"); // [table] [proxy] [mt] "__index" + lua_rotate(L, -4, -1); // [proxy] [mt] "__index" [table] + lua_rawset(L, -3); // [proxy] [mt] +} + +void makeEditableLuaProxy(lua_State* L) +{ + makeLuaProxy(L); // [proxy] [mt] + lua_pop(L, 1); // [proxy] +} + +void makeReadonlyLuaProxy(lua_State* L) +{ + makeLuaProxy(L); // [proxy] [mt] + + // Set the metatable's __newindex to reject writes + lua_pushstring(L, "__newindex"); // [proxy] [mt] "__newindex" + lua_pushcclosure(L, reject_write, 0); // [proxy] [mt] "__newindex" [reject_write] + lua_rawset(L, -3); // [proxy] [mt] + + lua_pop(L, 1); // [proxy] +} diff --git a/src/scriptInterfaceSandbox.h b/src/scriptInterfaceSandbox.h new file mode 100644 index 0000000..74f3994 --- /dev/null +++ b/src/scriptInterfaceSandbox.h @@ -0,0 +1,23 @@ +#ifndef SCRIPT_INTERFACE_SANDBOX_H +#define SCRIPT_INTERFACE_SANDBOX_H + +#include "lua/lua.hpp" + +// Add or protect a metatable for the provided object such that the metatable can't be read or changed from inside the sandbox. +// Input Lua stack: [object] +// Output Lua stack: [object] +void protectLuaMetatable(lua_State* L); + +// Create an editable proxy for the provided table. +// The proxy table itself will be editable, but its metatable will be protected and the input table will not be directly accessible. +// Input Lua stack: [table] +// Output Lua stack: [proxy] +void makeEditableLuaProxy(lua_State* L); + +// Create a read-only proxy for the provided table. +// The proxy table will be empty and uneditable, its metatable will be protected, and the input table will not be directly accessible. +// Input Lua stack: [table] +// Output Lua stack: [proxy] +void makeReadonlyLuaProxy(lua_State* L); + +#endif // SCRIPT_INTERFACE_SANDBOX_H From c98aa5607ae78419fc3d798ef3c4298bed9e0e3a Mon Sep 17 00:00:00 2001 From: GinjaNinja32 Date: Fri, 17 May 2024 06:30:06 +0100 Subject: [PATCH 2/5] Clone library tables into script environment rather than using metatable proxies --- src/scriptInterface.cpp | 96 ++++++++++++++++++---------------- src/scriptInterfaceSandbox.cpp | 54 ++----------------- src/scriptInterfaceSandbox.h | 12 ----- 3 files changed, 56 insertions(+), 106 deletions(-) diff --git a/src/scriptInterface.cpp b/src/scriptInterface.cpp index 3f01c61..e456a5d 100644 --- a/src/scriptInterface.cpp +++ b/src/scriptInterface.cpp @@ -108,6 +108,13 @@ static const luaL_Reg loadedlibs[] = { {NULL, NULL} }; +static const char* safe_functions[] = { + "assert", "error", "getmetatable", "ipairs", "next", "pairs", "pcall", + "print", "rawequal", "rawget", "rawlen", "rawset", "require", "select", + "setmetatable", "tonumber", "tostring", "type", "xpcall", + NULL, +}; + void ScriptObject::createLuaState() { if (L == NULL) @@ -119,43 +126,17 @@ void ScriptObject::createLuaState() { luaL_requiref(L, lib->name, lib->func, 1); lua_pop(L, 1); /* remove lib */ - - // for any library that isn't the global base, it will have registered a table we need to make read-only - if (strcmp(lib->name, "_G")) { - lua_getglobal(L, lib->name); - makeReadonlyLuaProxy(L); - lua_setglobal(L, lib->name); - } } - //Remove unsafe base functions. - lua_pushnil(L); - lua_setglobal(L, "collectgarbage"); - lua_pushnil(L); - lua_setglobal(L, "dofile"); - lua_pushnil(L); - lua_setglobal(L, "loadfile"); - lua_pushnil(L); - lua_setglobal(L, "load"); - lua_pushnil(L); - lua_setglobal(L, "rawequal"); - // Protect the metatable the string library sets on strings. - // This metatable points to the global `string` library, rather than the environment's proxy. + // This metatable points to the global `string` library, rather than the environment's copy. // This global string library table can't be accessed directly, but it means a function defining // `function string.foo(...)` can't call that function as `"some_string":foo()` since the metatable - // points to the global version rather than its own editable proxy. + // points to the global version rather than its own copy. // TODO see if this can be fixed without breaking the sandbox. probably not. lua_pushstring(L, ""); protectLuaMetatable(L); lua_pop(L, 1); - - // Replace the standard _G with a read-only proxy. - // We'll set _G in the script's environment to be that environment to act more like Lua's _G, but if the script sets `_G = nil` it'll clear that and get whatever _G exists in the global table. - // This is also a useful place to store the protected version of the real global table so we can use that as __index for the script environment metatable. - lua_pushglobaltable(L); - makeReadonlyLuaProxy(L); - lua_setglobal(L, "_G"); } //Setup a new table as the first upvalue. This will be used as "global" environment for the script. And thus will prevent global namespace polution. @@ -166,35 +147,62 @@ void ScriptObject::createLuaState() lua_pushvalue(L, -2); lua_rawset(L, -3); - // Register proxies for the global libraries - // We've made the global libraries' tables read-only, but some scripts will want to do `table.foo = function(...) ... end` to add to the standard set. - // Give each script its own editable proxy with a metatable pointing at the global library (which itself is a readonly proxy, since setting this local proxy to nil would reveal the global one) + // Copy in the safe global functions. + for (const char **fn = safe_functions; *fn; fn++) + { + lua_pushstring(L, *fn); + lua_getglobal(L, *fn); + lua_settable(L, -3); + } + + // Copy in the global libraries. for (const luaL_Reg *lib = loadedlibs; lib->func; lib++) { if (!strcmp(lib->name, "_G")) { continue; } - lua_pushstring(L, lib->name); - lua_getglobal(L, lib->name); - makeEditableLuaProxy(L); - lua_rawset(L, -3); + // Make a table for the library. + lua_newtable(L); // [env] [local] + + // Set it into the script environment. + lua_pushstring(L, lib->name); // [env] [local] [libname] + lua_pushvalue(L, -2); // [env] [local] [libname] [local] + lua_settable(L, -4); // [env] [local] + + // Iterate the global library. + lua_getglobal(L, lib->name); // [env] [local] [global] + lua_pushnil(L); // [env] [local] [global] nil + while (lua_next(L, -2)) + { // [env] [local] [global] [key] [value] + if (!lua_isfunction(L, -1) && !lua_isnumber(L, -1)) + { + // This doesn't trigger on anything right now; it's here in case anything gets added to any of the libraries that would potentially break the sandbox. + LOG(WARNING) << "ignoring non-{function,number} in " << lib->name; + lua_pop(L, 1); + continue; + } + + // Functions and numbers are safe to share - copy the value into the script's library table + lua_pushvalue(L, -2); // [env] [local] [global] [key] [value] [key] + lua_rotate(L, -2, 1); // [env] [local] [global] [key] [key] [value] + lua_settable(L, -5); // [env] [local] [global] [key] + } + // [env] [local] [global] + lua_pop(L, 2); // [env] } //Register all global functions for our game. for(ScriptClassInfo* item = scriptClassInfoList; item != NULL; item = item->next) + { item->register_function(L); - // Create a metatable for the script environment. - // Note that unlike all other metatables we set up, this metatable is _not_ protected. - // This is to allow the sandboxed code to set metatable bits on its own environment, since we don't let it wrap the actual table. - // This isn't a security issue since the only things it allows the script to do are 1) mess with its own environment, and 2) see the read-only global table proxy in __index + lua_pushstring(L, item->class_name.c_str()); + lua_getglobal(L, item->class_name.c_str()); + lua_settable(L, -3); + } + // TODO: probably all non-script access to the environment table should be rawget/rawset so we don't have to worry about the sandboxed code doing something funky in __index/__newindex? - lua_newtable(L); - lua_pushstring(L, "__index"); - lua_getglobal(L, "_G"); - lua_rawset(L, -3); - lua_setmetatable(L, -2); //Register the destroyScript function. This needs a reference back to the script object, we pass this as an upvalue. lua_pushstring(L, "destroyScript"); diff --git a/src/scriptInterfaceSandbox.cpp b/src/scriptInterfaceSandbox.cpp index 3a56dfb..9c7933a 100644 --- a/src/scriptInterfaceSandbox.cpp +++ b/src/scriptInterfaceSandbox.cpp @@ -1,17 +1,10 @@ #include "lua/lua.hpp" #include "scriptInterfaceSandbox.h" -int reject_write(lua_State* L) { - lua_pop(L, lua_gettop(L)); - lua_pushstring(L, "cannot write to sandbox-external library"); - lua_error(L); - return 0; -} - -// Add or protect a metatable, and add that metatable to the stack. +// Add or protect a metatable for the provided object // Input Lua stack: [object] -// Output Lua stack: [object] [mt] -void protectGetLuaMetatable(lua_State* L) +// Output Lua stack: [object] +void protectLuaMetatable(lua_State* L) { if (!lua_getmetatable(L, -1)) { lua_newtable(L); // [object] [mt] @@ -22,44 +15,5 @@ void protectGetLuaMetatable(lua_State* L) lua_pushstring(L, "__metatable"); // [object] [mt] "__metatable" lua_pushstring(L, "sandbox"); // [object] [mt] "__metatable" "sandbox" lua_settable(L, -3); // [object] [mt] -} - -void protectLuaMetatable(lua_State* L) -{ - protectGetLuaMetatable(L); // [object] [mt] - lua_pop(L, 1); // [object] -} - -// Make the base proxy for a table, and return the proxy and its metatable. -// Input Lua stack: [table] -// Output Lua stack: [proxy] [mt] -void makeLuaProxy(lua_State* L) -{ - lua_newtable(L); // [table] [proxy] - - // Add a protected metatable - protectGetLuaMetatable(L); // [table] [proxy] [mt] - - // Set the metatable's __index to the original table - lua_pushstring(L, "__index"); // [table] [proxy] [mt] "__index" - lua_rotate(L, -4, -1); // [proxy] [mt] "__index" [table] - lua_rawset(L, -3); // [proxy] [mt] -} - -void makeEditableLuaProxy(lua_State* L) -{ - makeLuaProxy(L); // [proxy] [mt] - lua_pop(L, 1); // [proxy] -} - -void makeReadonlyLuaProxy(lua_State* L) -{ - makeLuaProxy(L); // [proxy] [mt] - - // Set the metatable's __newindex to reject writes - lua_pushstring(L, "__newindex"); // [proxy] [mt] "__newindex" - lua_pushcclosure(L, reject_write, 0); // [proxy] [mt] "__newindex" [reject_write] - lua_rawset(L, -3); // [proxy] [mt] - - lua_pop(L, 1); // [proxy] + lua_pop(L, 1); // [object] } diff --git a/src/scriptInterfaceSandbox.h b/src/scriptInterfaceSandbox.h index 74f3994..b1e680c 100644 --- a/src/scriptInterfaceSandbox.h +++ b/src/scriptInterfaceSandbox.h @@ -8,16 +8,4 @@ // Output Lua stack: [object] void protectLuaMetatable(lua_State* L); -// Create an editable proxy for the provided table. -// The proxy table itself will be editable, but its metatable will be protected and the input table will not be directly accessible. -// Input Lua stack: [table] -// Output Lua stack: [proxy] -void makeEditableLuaProxy(lua_State* L); - -// Create a read-only proxy for the provided table. -// The proxy table will be empty and uneditable, its metatable will be protected, and the input table will not be directly accessible. -// Input Lua stack: [table] -// Output Lua stack: [proxy] -void makeReadonlyLuaProxy(lua_State* L); - #endif // SCRIPT_INTERFACE_SANDBOX_H From fb40e54c53144ea424aa71582b7c94a5ff50c437 Mon Sep 17 00:00:00 2001 From: GinjaNinja32 Date: Fri, 17 May 2024 11:55:15 +0100 Subject: [PATCH 3/5] Add required include --- src/scriptInterface.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/scriptInterface.cpp b/src/scriptInterface.cpp index e456a5d..400bb46 100644 --- a/src/scriptInterface.cpp +++ b/src/scriptInterface.cpp @@ -1,4 +1,5 @@ #include +#include #include "random.h" #include "resources.h" From aa6216725b2431e25848060b9a5652578ad36dbc Mon Sep 17 00:00:00 2001 From: GinjaNinja32 Date: Mon, 20 May 2024 21:06:36 +0100 Subject: [PATCH 4/5] Always use rawset/rawget on tables the script might have set a metatable on --- src/scriptInterface.cpp | 24 +++++++++++------------- src/scriptInterfaceMagic.h | 10 +++++----- src/scriptInterfaceSandbox.cpp | 2 +- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/src/scriptInterface.cpp b/src/scriptInterface.cpp index 400bb46..1f37d0b 100644 --- a/src/scriptInterface.cpp +++ b/src/scriptInterface.cpp @@ -153,7 +153,7 @@ void ScriptObject::createLuaState() { lua_pushstring(L, *fn); lua_getglobal(L, *fn); - lua_settable(L, -3); + lua_rawset(L, -3); } // Copy in the global libraries. @@ -169,7 +169,7 @@ void ScriptObject::createLuaState() // Set it into the script environment. lua_pushstring(L, lib->name); // [env] [local] [libname] lua_pushvalue(L, -2); // [env] [local] [libname] [local] - lua_settable(L, -4); // [env] [local] + lua_rawset(L, -4); // [env] [local] // Iterate the global library. lua_getglobal(L, lib->name); // [env] [local] [global] @@ -187,7 +187,7 @@ void ScriptObject::createLuaState() // Functions and numbers are safe to share - copy the value into the script's library table lua_pushvalue(L, -2); // [env] [local] [global] [key] [value] [key] lua_rotate(L, -2, 1); // [env] [local] [global] [key] [key] [value] - lua_settable(L, -5); // [env] [local] [global] [key] + lua_rawset(L, -5); // [env] [local] [global] [key] } // [env] [local] [global] lua_pop(L, 2); // [env] @@ -200,11 +200,9 @@ void ScriptObject::createLuaState() lua_pushstring(L, item->class_name.c_str()); lua_getglobal(L, item->class_name.c_str()); - lua_settable(L, -3); + lua_rawset(L, -3); } - // TODO: probably all non-script access to the environment table should be rawget/rawset so we don't have to worry about the sandboxed code doing something funky in __index/__newindex? - //Register the destroyScript function. This needs a reference back to the script object, we pass this as an upvalue. lua_pushstring(L, "destroyScript"); lua_pushlightuserdata(L, this); @@ -296,7 +294,7 @@ void ScriptObject::setVariable(string variable_name, string value) //Set our variable in this environment table lua_pushstring(L, variable_name.c_str()); lua_pushstring(L, value.c_str()); - lua_settable(L, -3); + lua_rawset(L, -3); //Pop the table lua_pop(L, 1); @@ -313,7 +311,7 @@ void ScriptObject::registerObject(P object, string variable_name) if (convert< P >::returnType(L, object)) { - lua_settable(L, -3); + lua_rawset(L, -3); //Pop the environment table lua_pop(L, 1); }else{ @@ -437,7 +435,7 @@ bool ScriptObject::callFunction(string name) lua_gettable(L, LUA_REGISTRYINDEX); //Get the function from the environment lua_pushstring(L, name.c_str()); - lua_gettable(L, -2); + lua_rawget(L, -2); //Call the function if (lua_pcall(L, 0, 0, 0)) { @@ -491,7 +489,7 @@ void ScriptObject::update(float delta) lua_gettable(L, LUA_REGISTRYINDEX); // Get the update function from the script environment lua_pushstring(L, "update"); - lua_gettable(L, -2); + lua_rawget(L, -2); // If it's a function, call it, if not, pop the environment and the function from the stack. if (!lua_isfunction(L, -1)) @@ -582,7 +580,7 @@ void ScriptCallback::operator() () lua_pop(L, 1); return; } - + lua_pushnil(L); while (lua_next(L, -2) != 0) { @@ -597,7 +595,7 @@ void ScriptCallback::operator() () //Stack is [callback_table] [callback_key] [callback_entry_table] [script_pointer] lua_pushvalue(L, -3); lua_pushnil(L); - lua_settable(L, -6); + lua_rawset(L, -6); lua_pop(L, 1); }else{ lua_pop(L, 1); @@ -768,7 +766,7 @@ template<> void convert::param(lua_State* L, int& idx, Scr //Stack is now: [function_environment] [callback object pointer] [table] "script_pointer" lua_pushstring(L, "__script_pointer"); - lua_gettable(L, -5); + lua_rawget(L, -5); if (lua_isnil(L, -1)) { //Simple functions that do not access globals do not inherit their environment from their creator, so they have nil here. diff --git a/src/scriptInterfaceMagic.h b/src/scriptInterfaceMagic.h index ba8709d..65e0c32 100644 --- a/src/scriptInterfaceMagic.h +++ b/src/scriptInterfaceMagic.h @@ -125,7 +125,7 @@ struct convert return; } lua_pushstring(L, "__ptr"); - lua_gettable(L, idx++); + lua_rawget(L, idx++); P** p = static_cast< P** >(lua_touserdata(L, -1)); lua_pop(L, 1); @@ -154,7 +154,7 @@ struct convert> return; } lua_pushstring(L, "__ptr"); - lua_gettable(L, idx++); + lua_rawget(L, idx++); P** p = static_cast< P** >(lua_touserdata(L, -1)); lua_pop(L, 1); @@ -201,7 +201,7 @@ struct convert> // protect the new userdata's metatable protectLuaMetatable(L); - lua_settable(L, -3); + lua_rawset(L, -3); lua_pushlightuserdata(L, ptr); lua_pushvalue(L, -2); @@ -372,7 +372,7 @@ template struct call if (!lua_istable(L, -1)) luaL_error(L, "??[setcallbackFunction] Upvalue 1 of function is not a table..."); lua_pushstring(L, "__script_pointer"); - lua_gettable(L, -2); + lua_rawget(L, -2); if (!lua_islightuserdata(L, -1)) luaL_error(L, "??[setcallbackFunction] Cannot find reference back to script..."); //Stack is now: [function_environment] [pointer] @@ -528,7 +528,7 @@ template class scriptBindObject if (!lua_istable(L, -1)) return 0; lua_pushstring(L, "__ptr"); - lua_gettable(L, -2); + lua_rawget(L, -2); if (lua_isuserdata(L, -1)) //When a subclass is destroyed, it's metatable might call the __gc function on it's sub-metatable. So we can get nil values here, ignore that. { PT* p = static_cast< PT* >(lua_touserdata(L, -1)); diff --git a/src/scriptInterfaceSandbox.cpp b/src/scriptInterfaceSandbox.cpp index 9c7933a..248abea 100644 --- a/src/scriptInterfaceSandbox.cpp +++ b/src/scriptInterfaceSandbox.cpp @@ -14,6 +14,6 @@ void protectLuaMetatable(lua_State* L) lua_pushstring(L, "__metatable"); // [object] [mt] "__metatable" lua_pushstring(L, "sandbox"); // [object] [mt] "__metatable" "sandbox" - lua_settable(L, -3); // [object] [mt] + lua_rawset(L, -3); // [object] [mt] lua_pop(L, 1); // [object] } From 0806816bad43f63034ec287a28f43e8e745f71e3 Mon Sep 17 00:00:00 2001 From: GinjaNinja32 Date: Wed, 22 May 2024 20:42:58 +0100 Subject: [PATCH 5/5] Remove redundant metatable protection call --- src/scriptInterfaceMagic.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/scriptInterfaceMagic.h b/src/scriptInterfaceMagic.h index 65e0c32..34a22bb 100644 --- a/src/scriptInterfaceMagic.h +++ b/src/scriptInterfaceMagic.h @@ -198,9 +198,6 @@ struct convert> *p = new P(); (**p) = ptr; - // protect the new userdata's metatable - protectLuaMetatable(L); - lua_rawset(L, -3); lua_pushlightuserdata(L, ptr);