diff options
| author | Benoit Germain <benoit.germain@ubisoft.com> | 2024-06-19 11:17:15 +0200 |
|---|---|---|
| committer | Benoit Germain <benoit.germain@ubisoft.com> | 2024-06-19 11:17:15 +0200 |
| commit | 1ca04d529a447341268cb92022e36abb09fe1315 (patch) | |
| tree | 2095898d26db2ed6865bf60a28c78eadc937b920 | |
| parent | ad7a8a8a8f9f762ce9952e0e2cea98e73ac2b32e (diff) | |
| download | lanes-1ca04d529a447341268cb92022e36abb09fe1315.tar.gz lanes-1ca04d529a447341268cb92022e36abb09fe1315.tar.bz2 lanes-1ca04d529a447341268cb92022e36abb09fe1315.zip | |
Fix on_state_create incorrectly rejecting Lua functions with only _ENV as upvalue
| -rw-r--r-- | src/universe.cpp | 24 | ||||
| -rw-r--r-- | tests/manual_register.lua | 9 |
2 files changed, 19 insertions, 14 deletions
diff --git a/src/universe.cpp b/src/universe.cpp index b63008a..08fdf40 100644 --- a/src/universe.cpp +++ b/src/universe.cpp | |||
| @@ -300,14 +300,24 @@ int Universe::InitializeFinalizer(lua_State* const L_) | |||
| 300 | 300 | ||
| 301 | void Universe::initializeOnStateCreate(lua_State* const L_) | 301 | void Universe::initializeOnStateCreate(lua_State* const L_) |
| 302 | { | 302 | { |
| 303 | STACK_CHECK_START_REL(L_, 1); // L_: settings | 303 | STACK_CHECK_START_REL(L_, 0); // L_: settings |
| 304 | if (luaG_getfield(L_, -1, kOnStateCreate) != LuaType::NIL) { // L_: settings on_state_create|nil | 304 | if (luaG_getfield(L_, -1, kOnStateCreate) != LuaType::NIL) { // L_: settings on_state_create|nil |
| 305 | LUA_ASSERT(L_, luaG_type(L_, -1) == LuaType::FUNCTION); // ensured by lanes.lua parameter validation | 305 | LUA_ASSERT(L_, luaG_type(L_, -1) == LuaType::FUNCTION); // ensured by lanes.lua parameter validation |
| 306 | // make sure the function doesn't have upvalues | 306 | // make sure the function doesn't have upvalues other than _G |
| 307 | char const* _upname{ lua_getupvalue(L_, -1, 1) }; // L_: settings on_state_create upval? | 307 | int _uvi{ 1 }; |
| 308 | if (_upname != nullptr) { // should be "" for C functions with upvalues if any | 308 | for ( |
| 309 | raise_luaL_error(L_, "%s with upvalues are forbidden", kOnStateCreate.data()); | 309 | char const* _upname{ lua_getupvalue(L_, -1, _uvi) }; |
| 310 | _upname; | ||
| 311 | _upname = lua_getupvalue(L_, -1, ++_uvi) // L_: settings on_state_create upvalue | ||
| 312 | ) { | ||
| 313 | // starting with Lua 5.2, functions have _ENV as their first upvalue. This is ok, it is mapped correctly | ||
| 314 | luaG_pushglobaltable(L_); // L_: settings on_state_create upvalue _G | ||
| 315 | if (!lua_rawequal(L_, -1, -2)) { | ||
| 316 | raise_luaL_error(L_, "%s with upvalues are forbidden", kOnStateCreate.data()); | ||
| 317 | } | ||
| 318 | lua_pop(L_, 2); // L_: settings on_state_create | ||
| 310 | } | 319 | } |
| 320 | STACK_CHECK(L_, 1); // make sure no garbage remains on the stack after upvalue check // L_: settings on_state_create | ||
| 311 | // store C function pointer in an internal variable | 321 | // store C function pointer in an internal variable |
| 312 | lua_CFunction const _func{ lua_tocfunction(L_, -1) }; // L_: settings on_state_create | 322 | lua_CFunction const _func{ lua_tocfunction(L_, -1) }; // L_: settings on_state_create |
| 313 | if (_func) { | 323 | if (_func) { |
| @@ -317,14 +327,14 @@ void Universe::initializeOnStateCreate(lua_State* const L_) | |||
| 317 | lua_pushnil(L_); // L_: settings on_state_create nil | 327 | lua_pushnil(L_); // L_: settings on_state_create nil |
| 318 | luaG_setfield(L_, -3, kOnStateCreate); // L_: settings on_state_create | 328 | luaG_setfield(L_, -3, kOnStateCreate); // L_: settings on_state_create |
| 319 | } else { | 329 | } else { |
| 320 | // the function is still in the config table | 330 | // the function is still in the config table. we indicate this with the uintptr_t alternative (actual value is irrelevant) |
| 321 | onStateCreateFunc.emplace<uintptr_t>(std::bit_cast<uintptr_t>(kOnStateCreate.data())); | 331 | onStateCreateFunc.emplace<uintptr_t>(std::bit_cast<uintptr_t>(kOnStateCreate.data())); |
| 322 | } | 332 | } |
| 323 | } else { | 333 | } else { |
| 324 | LUA_ASSERT(L_, std::holds_alternative<std::nullptr_t>(onStateCreateFunc)); | 334 | LUA_ASSERT(L_, std::holds_alternative<std::nullptr_t>(onStateCreateFunc)); |
| 325 | }; | 335 | }; |
| 326 | lua_pop(L_, 1); // L_: settings | 336 | lua_pop(L_, 1); // L_: settings |
| 327 | STACK_CHECK(L_, 1); | 337 | STACK_CHECK(L_, 0); |
| 328 | } | 338 | } |
| 329 | 339 | ||
| 330 | // ################################################################################################# | 340 | // ################################################################################################# |
diff --git a/tests/manual_register.lua b/tests/manual_register.lua index a8f2098..5220cf8 100644 --- a/tests/manual_register.lua +++ b/tests/manual_register.lua | |||
| @@ -1,6 +1,3 @@ | |||
| 1 | |||
| 2 | local register_func = true | ||
| 3 | |||
| 4 | local RequireAModuleThatExportsGlobalFunctions = function(type_) | 1 | local RequireAModuleThatExportsGlobalFunctions = function(type_) |
| 5 | -- grab some module that exports C functions, this is good enough for our purpose | 2 | -- grab some module that exports C functions, this is good enough for our purpose |
| 6 | local lfs = require "lfs" | 3 | local lfs = require "lfs" |
| @@ -8,14 +5,12 @@ local RequireAModuleThatExportsGlobalFunctions = function(type_) | |||
| 8 | GlobalFunc = lfs.attributes | 5 | GlobalFunc = lfs.attributes |
| 9 | -- we need to register it so that it is transferable | 6 | -- we need to register it so that it is transferable |
| 10 | local lanes = require "lanes" | 7 | local lanes = require "lanes" |
| 11 | if register_func then | 8 | lanes.register( "GlobalFunc", GlobalFunc) |
| 12 | lanes.register( "GlobalFunc", GlobalFunc) | ||
| 13 | end | ||
| 14 | print(type_, "RequireAModuleThatExportsGlobalFunctions done:", lanes.nameof(GlobalFunc)) | 9 | print(type_, "RequireAModuleThatExportsGlobalFunctions done:", lanes.nameof(GlobalFunc)) |
| 15 | end | 10 | end |
| 16 | 11 | ||
| 17 | 12 | ||
| 18 | local lanes = require "lanes".configure{ with_timers = false, on_state_create = RequireAModuleThatExportsGlobalFunctions} | 13 | local lanes = require "lanes".configure{on_state_create = RequireAModuleThatExportsGlobalFunctions} |
| 19 | 14 | ||
| 20 | -- load some module that adds C functions to the global space | 15 | -- load some module that adds C functions to the global space |
| 21 | RequireAModuleThatExportsGlobalFunctions("main") | 16 | RequireAModuleThatExportsGlobalFunctions("main") |
