aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBenoit Germain <benoit.germain@ubisoft.com>2024-06-17 18:16:46 +0200
committerBenoit Germain <benoit.germain@ubisoft.com>2024-06-17 18:16:46 +0200
commit54b47307ce4b2e21bc12c1602c77fecf55380452 (patch)
tree9e807499e9bde6ba7193e98d5f611b2d66173490 /src
parentca46cc7883b7b2749307a3e5a8196368fb52ba09 (diff)
downloadlanes-54b47307ce4b2e21bc12c1602c77fecf55380452.tar.gz
lanes-54b47307ce4b2e21bc12c1602c77fecf55380452.tar.bz2
lanes-54b47307ce4b2e21bc12c1602c77fecf55380452.zip
Foolproofed config.allocator when it is a function
Diffstat (limited to 'src')
-rw-r--r--src/lanes.lua8
-rw-r--r--src/state.cpp3
-rw-r--r--src/universe.cpp36
-rw-r--r--src/universe.h10
4 files changed, 37 insertions, 20 deletions
diff --git a/src/lanes.lua b/src/lanes.lua
index 6342ca9..7c1f8df 100644
--- a/src/lanes.lua
+++ b/src/lanes.lua
@@ -108,7 +108,7 @@ local default_params =
108-- ################################################################################################# 108-- #################################################################################################
109 109
110local boolean_param_checker = function(val_) 110local boolean_param_checker = function(val_)
111 -- non-'boolean-false' should be 'boolean-true' or nil 111 -- non-'boolean-false|nil' should be 'boolean-true'
112 return (not val_) or (val_ == true) 112 return (not val_) or (val_ == true)
113end 113end
114 114
@@ -116,7 +116,7 @@ local param_checkers =
116{ 116{
117 allocator = function(val_) 117 allocator = function(val_)
118 -- can be nil, "protected", or a function 118 -- can be nil, "protected", or a function
119 return val_ and (type(val_) == "function" or val_ == "protected") or true 119 return (val_ == nil) or (type(val_) == "function" or val_ == "protected")
120 end, 120 end,
121 internal_allocator = function(val_) 121 internal_allocator = function(val_)
122 -- can be "libc" or "allocator" 122 -- can be "libc" or "allocator"
@@ -128,11 +128,11 @@ local param_checkers =
128 end, 128 end,
129 nb_user_keepers = function(val_) 129 nb_user_keepers = function(val_)
130 -- nb_user_keepers should be a number in [0,100] (so that nobody tries to run OOM by specifying a huge amount) 130 -- nb_user_keepers should be a number in [0,100] (so that nobody tries to run OOM by specifying a huge amount)
131 return type(val_) == "number" and val_ >= 0 and val_ <= 100 131 return (type(val_) == "number") and (val_ >= 0) and (val_ <= 100)
132 end, 132 end,
133 on_state_create = function(val_) 133 on_state_create = function(val_)
134 -- on_state_create may be nil or a function 134 -- on_state_create may be nil or a function
135 return val_ and type(val_) == "function" or true 135 return (val_ == nil) or (type(val_) == "function")
136 end, 136 end,
137 shutdown_mode = function(val_) 137 shutdown_mode = function(val_)
138 local valid_hooks = { soft = true, hard = true, call = true, ret = true, line = true, count = true } 138 local valid_hooks = { soft = true, hard = true, call = true, ret = true, line = true, count = true }
diff --git a/src/state.cpp b/src/state.cpp
index 3f6b3d7..ee0b199 100644
--- a/src/state.cpp
+++ b/src/state.cpp
@@ -208,6 +208,9 @@ namespace state {
208 lua_pushcclosure(from, U->provideAllocator, 0); 208 lua_pushcclosure(from, U->provideAllocator, 0);
209 lua_call(from, 0, 1); 209 lua_call(from, 0, 1);
210 AllocatorDefinition* const _def{ luaG_tofulluserdata<AllocatorDefinition>(from, -1) }; 210 AllocatorDefinition* const _def{ luaG_tofulluserdata<AllocatorDefinition>(from, -1) };
211 if (!_def || _def->version != AllocatorDefinition::kAllocatorVersion) {
212 raise_luaL_error(from, "Bad config.allocator function, must provide a valid AllocatorDefinition");
213 }
211 lua_State* const _L{ lua_newstate(_def->allocF, _def->allocUD) }; 214 lua_State* const _L{ lua_newstate(_def->allocF, _def->allocUD) };
212 lua_pop(from, 1); 215 lua_pop(from, 1);
213 return _L; 216 return _L;
diff --git a/src/universe.cpp b/src/universe.cpp
index c98e2c8..d24a784 100644
--- a/src/universe.cpp
+++ b/src/universe.cpp
@@ -176,9 +176,23 @@ Universe::Universe()
176// Do I need to disable this when compiling for LuaJIT to prevent issues? 176// Do I need to disable this when compiling for LuaJIT to prevent issues?
177void Universe::initializeAllocatorFunction(lua_State* const L_) 177void Universe::initializeAllocatorFunction(lua_State* const L_)
178{ 178{
179 // start by just grabbing whatever allocator was provided to lua_newstate
180 protectedAllocator.initFrom(L_);
179 STACK_CHECK_START_REL(L_, 1); // L_: settings 181 STACK_CHECK_START_REL(L_, 1); // L_: settings
180 if (luaG_getfield(L_, -1, "allocator") != LuaType::NIL) { // L_: settings allocator|nil|"protected" 182 switch (luaG_getfield(L_, -1, "allocator")) { // L_: settings allocator|nil|"protected"
181 // store C function pointer in an internal variable 183 case LuaType::NIL:
184 // nothing else to do
185 break;
186
187 case LuaType::STRING:
188 LUA_ASSERT(L_, luaG_tostring(L_, -1) == "protected");
189 // set the original allocator to call from inside protection by the mutex
190 protectedAllocator.installIn(L_);
191 // before a state is created, this function will be called to obtain the allocator
192 provideAllocator = luaG_provide_protected_allocator;
193 break;
194
195 case LuaType::FUNCTION:
182 provideAllocator = lua_tocfunction(L_, -1); // L_: settings allocator 196 provideAllocator = lua_tocfunction(L_, -1); // L_: settings allocator
183 if (provideAllocator != nullptr) { 197 if (provideAllocator != nullptr) {
184 // make sure the function doesn't have upvalues 198 // make sure the function doesn't have upvalues
@@ -190,17 +204,13 @@ void Universe::initializeAllocatorFunction(lua_State* const L_)
190 // when we transfer the config table in newly created Lua states 204 // when we transfer the config table in newly created Lua states
191 lua_pushnil(L_); // L_: settings allocator nil 205 lua_pushnil(L_); // L_: settings allocator nil
192 lua_setfield(L_, -3, "allocator"); // L_: settings allocator 206 lua_setfield(L_, -3, "allocator"); // L_: settings allocator
193 } else if (luaG_type(L_, -1) == LuaType::STRING) { // should be "protected" 207 } else {
194 LUA_ASSERT(L_, strcmp(lua_tostring(L_, -1), "protected") == 0); 208 raise_luaL_error(L_, "Bad config.allocator, must be a C function");
195 // set the original allocator to call from inside protection by the mutex
196 protectedAllocator.initFrom(L_);
197 protectedAllocator.installIn(L_);
198 // before a state is created, this function will be called to obtain the allocator
199 provideAllocator = luaG_provide_protected_allocator;
200 } 209 }
201 } else { 210 break;
202 // just grab whatever allocator was provided to lua_newstate 211
203 protectedAllocator.initFrom(L_); 212 default: // should be filtered out in lanes.lua
213 raise_luaL_error(L_, "Bad config.allocator type %s", luaG_typename(L_, -1).data());
204 } 214 }
205 lua_pop(L_, 1); // L_: settings 215 lua_pop(L_, 1); // L_: settings
206 STACK_CHECK(L_, 1); 216 STACK_CHECK(L_, 1);
@@ -208,7 +218,7 @@ void Universe::initializeAllocatorFunction(lua_State* const L_)
208 std::ignore = luaG_getfield(L_, -1, "internal_allocator"); // L_: settings "libc"|"allocator" 218 std::ignore = luaG_getfield(L_, -1, "internal_allocator"); // L_: settings "libc"|"allocator"
209 std::string_view const _allocator{ luaG_tostring(L_, -1) }; 219 std::string_view const _allocator{ luaG_tostring(L_, -1) };
210 if (_allocator == "libc") { 220 if (_allocator == "libc") {
211 internalAllocator = AllocatorDefinition{ libc_lua_Alloc, nullptr }; 221 internalAllocator = AllocatorDefinition{ AllocatorDefinition::kAllocatorVersion, libc_lua_Alloc, nullptr };
212 } else if (provideAllocator == luaG_provide_protected_allocator) { 222 } else if (provideAllocator == luaG_provide_protected_allocator) {
213 // user wants mutex protection on the state's allocator. Use protection for our own allocations too, just in case. 223 // user wants mutex protection on the state's allocator. Use protection for our own allocations too, just in case.
214 internalAllocator = protectedAllocator.makeDefinition(); 224 internalAllocator = protectedAllocator.makeDefinition();
diff --git a/src/universe.h b/src/universe.h
index 47b86af..3742ddd 100644
--- a/src/universe.h
+++ b/src/universe.h
@@ -18,6 +18,9 @@ class Lane;
18class AllocatorDefinition 18class AllocatorDefinition
19{ 19{
20 public: 20 public:
21 // xxh64 of string "kAllocatorVersion_1" generated at https://www.pelock.com/products/hash-calculator
22 static constexpr uintptr_t kAllocatorVersion{ static_cast<uintptr_t>(0xCF9D321B0DFB5715ull) };
23 uintptr_t version{ kAllocatorVersion };
21 lua_Alloc allocF{ nullptr }; 24 lua_Alloc allocF{ nullptr };
22 void* allocUD{ nullptr }; 25 void* allocUD{ nullptr };
23 26
@@ -27,8 +30,9 @@ class AllocatorDefinition
27 // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception 30 // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception
28 static void operator delete([[maybe_unused]] void* p_, [[maybe_unused]] lua_State* L_) { LUA_ASSERT(L_, !"should never be called"); } 31 static void operator delete([[maybe_unused]] void* p_, [[maybe_unused]] lua_State* L_) { LUA_ASSERT(L_, !"should never be called"); }
29 32
30 AllocatorDefinition(lua_Alloc allocF_, void* allocUD_) noexcept 33 AllocatorDefinition(uintptr_t const version_, lua_Alloc const allocF_, void* const allocUD_) noexcept
31 : allocF{ allocF_ } 34 : version{ version_ }
35 , allocF{ allocF_ }
32 , allocUD{ allocUD_ } 36 , allocUD{ allocUD_ }
33 { 37 {
34 } 38 }
@@ -77,7 +81,7 @@ class ProtectedAllocator
77 81
78 AllocatorDefinition makeDefinition() 82 AllocatorDefinition makeDefinition()
79 { 83 {
80 return AllocatorDefinition{ protected_lua_Alloc, this }; 84 return AllocatorDefinition{ version, protected_lua_Alloc, this };
81 } 85 }
82 86
83 void installIn(lua_State* L_) 87 void installIn(lua_State* L_)