aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBenoit Germain <benoit.germain@ubisoft.com>2025-07-31 09:24:22 +0200
committerBenoit Germain <benoit.germain@ubisoft.com>2025-07-31 09:24:22 +0200
commit818f94b863d8307b41afbfc9ad43868d6e9097eb (patch)
tree603156f57621f98b7f109543a89ae0c677d4fcde /src
parentdc2b7577b6663ff65a76fa3790578215d2136a48 (diff)
downloadlanes-818f94b863d8307b41afbfc9ad43868d6e9097eb.tar.gz
lanes-818f94b863d8307b41afbfc9ad43868d6e9097eb.tar.bz2
lanes-818f94b863d8307b41afbfc9ad43868d6e9097eb.zip
RAII + setjmp = UB
Diffstat (limited to 'src')
-rw-r--r--src/linda.cpp29
-rw-r--r--src/linda.hpp24
2 files changed, 13 insertions, 40 deletions
diff --git a/src/linda.cpp b/src/linda.cpp
index 56285f7..1f4b19d 100644
--- a/src/linda.cpp
+++ b/src/linda.cpp
@@ -338,6 +338,7 @@ Keeper* Linda::acquireKeeper() const
338 Keeper* const _keeper{ whichKeeper() }; 338 Keeper* const _keeper{ whichKeeper() };
339 if (_keeper) { 339 if (_keeper) {
340 _keeper->mutex.lock(); 340 _keeper->mutex.lock();
341 keeperOperationCount.fetch_add(1, std::memory_order_seq_cst);
341 } 342 }
342 return _keeper; 343 return _keeper;
343} 344}
@@ -422,23 +423,16 @@ int Linda::ProtectedCall(lua_State* const L_, lua_CFunction const f_)
422 // doing LindaFactory::deleteDeepObjectInternal -> keeper_call(clear) 423 // doing LindaFactory::deleteDeepObjectInternal -> keeper_call(clear)
423 lua_gc(L_, LUA_GCSTOP, 0); 424 lua_gc(L_, LUA_GCSTOP, 0);
424 425
425 LuaError _rc{}; 426 // if we didn't do anything wrong, the keeper stack should be clean
426 { 427 LUA_ASSERT(L_, lua_gettop(_K) == 0);
427 // there is something really strange here: in Release builds, MSVC will invoke _koip destructor on stack unwinding when we raise_lua_error() below 428
428 // even though the variable does not exist in the stack frame because it went out of scope -> comment until we understand why, because it causes a crash 429 // push the function to be called and move it before the arguments
429 //LUA_ASSERT_CODE(auto const _koip{ _linda->startKeeperOperation(L_) }); 430 lua_pushcfunction(L_, f_);
430 431 lua_insert(L_, 1);
431 // if we didn't do anything wrong, the keeper stack should be clean 432 // do a protected call
432 LUA_ASSERT(L_, lua_gettop(_K) == 0); 433 LuaError const _rc{ ToLuaError(lua_pcall(L_, lua_gettop(L_) - 1, LUA_MULTRET, 0)) };
433 434 // whatever happens, the keeper state stack must be empty when we are done
434 // push the function to be called and move it before the arguments 435 lua_settop(_K, 0);
435 lua_pushcfunction(L_, f_);
436 lua_insert(L_, 1);
437 // do a protected call
438 _rc = ToLuaError(lua_pcall(L_, lua_gettop(L_) - 1, LUA_MULTRET, 0));
439 // whatever happens, the keeper state stack must be empty when we are done
440 lua_settop(_K, 0);
441 }
442 436
443 // restore normal GC operations 437 // restore normal GC operations
444 lua_gc(L_, LUA_GCRESTART, 0); 438 lua_gc(L_, LUA_GCRESTART, 0);
@@ -467,6 +461,7 @@ void Linda::releaseKeeper(Keeper* const keeper_) const
467{ 461{
468 if (keeper_) { // can be nullptr if we tried to acquire during shutdown 462 if (keeper_) { // can be nullptr if we tried to acquire during shutdown
469 assert(keeper_ == whichKeeper()); 463 assert(keeper_ == whichKeeper());
464 keeperOperationCount.fetch_sub(1, std::memory_order_seq_cst);
470 keeper_->mutex.unlock(); 465 keeper_->mutex.unlock();
471 } 466 }
472} 467}
diff --git a/src/linda.hpp b/src/linda.hpp
index 9288b38..f02c46e 100644
--- a/src/linda.hpp
+++ b/src/linda.hpp
@@ -14,26 +14,6 @@ class Linda final
14: public DeepPrelude // Deep userdata MUST start with this header 14: public DeepPrelude // Deep userdata MUST start with this header
15{ 15{
16 public: 16 public:
17 class [[nodiscard]] KeeperOperationInProgress final
18 {
19 private:
20 Linda& linda;
21 lua_State* const L{}; // just here for inspection while debugging
22
23 public:
24 KeeperOperationInProgress(Linda& linda_, lua_State* const L_) noexcept
25 : linda{ linda_ }
26 , L{ L_ }
27 {
28 [[maybe_unused]] UnusedInt const _prev{ linda.keeperOperationCount.fetch_add(1, std::memory_order_seq_cst) };
29 }
30
31 public:
32 ~KeeperOperationInProgress() noexcept
33 {
34 [[maybe_unused]] UnusedInt const _prev{ linda.keeperOperationCount.fetch_sub(1, std::memory_order_seq_cst) };
35 }
36 };
37 17
38 enum class [[nodiscard]] Status 18 enum class [[nodiscard]] Status
39 { 19 {
@@ -51,7 +31,7 @@ class Linda final
51 // depending on the name length, it is either embedded inside the Linda, or allocated separately 31 // depending on the name length, it is either embedded inside the Linda, or allocated separately
52 std::variant<std::string_view, EmbeddedName> nameVariant{}; 32 std::variant<std::string_view, EmbeddedName> nameVariant{};
53 // counts the keeper operations in progress 33 // counts the keeper operations in progress
54 std::atomic<int> keeperOperationCount{}; 34 mutable std::atomic<int> keeperOperationCount{};
55 lua_Duration wakePeriod{}; 35 lua_Duration wakePeriod{};
56 36
57 public: 37 public:
@@ -110,7 +90,5 @@ class Linda final
110 static int ProtectedCall(lua_State* L_, lua_CFunction f_); 90 static int ProtectedCall(lua_State* L_, lua_CFunction f_);
111 void pushCancelString(lua_State* L_) const; 91 void pushCancelString(lua_State* L_) const;
112 [[nodiscard]] 92 [[nodiscard]]
113 KeeperOperationInProgress startKeeperOperation(lua_State* const L_) { return KeeperOperationInProgress{ *this, L_ }; };
114 [[nodiscard]]
115 Keeper* whichKeeper() const { return U->keepers.getKeeper(keeperIndex); } 93 Keeper* whichKeeper() const { return U->keepers.getKeeper(keeperIndex); }
116}; 94};