aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenoit Germain <benoit.germain@ubisoft.com>2024-06-19 11:17:15 +0200
committerBenoit Germain <benoit.germain@ubisoft.com>2024-06-19 11:17:15 +0200
commit1ca04d529a447341268cb92022e36abb09fe1315 (patch)
tree2095898d26db2ed6865bf60a28c78eadc937b920
parentad7a8a8a8f9f762ce9952e0e2cea98e73ac2b32e (diff)
downloadlanes-1ca04d529a447341268cb92022e36abb09fe1315.tar.gz
lanes-1ca04d529a447341268cb92022e36abb09fe1315.tar.bz2
lanes-1ca04d529a447341268cb92022e36abb09fe1315.zip
Fix on_state_create incorrectly rejecting Lua functions with only _ENV as upvalue
Diffstat (limited to '')
-rw-r--r--src/universe.cpp24
-rw-r--r--tests/manual_register.lua9
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
301void Universe::initializeOnStateCreate(lua_State* const L_) 301void 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
2local register_func = true
3
4local RequireAModuleThatExportsGlobalFunctions = function(type_) 1local 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))
15end 10end
16 11
17 12
18local lanes = require "lanes".configure{ with_timers = false, on_state_create = RequireAModuleThatExportsGlobalFunctions} 13local 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
21RequireAModuleThatExportsGlobalFunctions("main") 16RequireAModuleThatExportsGlobalFunctions("main")