Skip to content

Commit 6906854

Browse files
committed
fix(Lua): improves Lua hook thread safety
Addresses potential issues with concurrent access to Lua hook threads by reusing the first created thread for subsequent calls. This anchors the hook thread to the parent registry only on its first use, preventing redundant registrations.
1 parent 3d4fbd0 commit 6906854

File tree

1 file changed

+56
-26
lines changed

1 file changed

+56
-26
lines changed

UE4SS/src/Mod/LuaMod.cpp

Lines changed: 56 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -740,11 +740,16 @@ namespace RC
740740
}
741741

742742
// auto static make_hook_state(Mod* mod, const LuaMadeSimple::Lua& lua)->std::shared_ptr<LuaMadeSimple::Lua>
743-
auto static make_hook_state(LuaMod* mod) -> LuaMadeSimple::Lua*
743+
auto static make_hook_state(LuaMod* mod, bool& is_first_use) -> LuaMadeSimple::Lua*
744744
{
745-
// if (!mod->m_hook_lua)
746-
//{
747-
return mod->m_hook_lua.emplace_back(&mod->lua().new_thread());
745+
if (mod->m_hook_lua.empty())
746+
{
747+
is_first_use = true;
748+
return mod->m_hook_lua.emplace_back(&mod->lua().new_thread());
749+
}
750+
751+
is_first_use = false;
752+
return mod->m_hook_lua[0];
748753

749754
// Make the hook thread (which is just a separate Lua stack) be a global in its parent.
750755
// This is needed because otherwise it will be GCd when we don't want it to.
@@ -2233,7 +2238,8 @@ No overload found for function 'NotifyOnNewObject'.
22332238
}
22342239

22352240
auto mod = get_mod_ref(lua);
2236-
auto hook_lua = make_hook_state(mod);
2241+
bool is_first_use = false;
2242+
auto hook_lua = make_hook_state(mod, is_first_use);
22372243

22382244
// Duplicate the Lua function to the top of the stack for lua_xmove and luaL_ref
22392245
lua_pushvalue(lua.get_lua_state(), 1);
@@ -2270,7 +2276,8 @@ No overload found for function 'RegisterCustomEvent'.
22702276
}
22712277

22722278
auto mod = get_mod_ref(lua);
2273-
auto hook_lua = make_hook_state(mod);
2279+
bool is_first_use = false;
2280+
auto hook_lua = make_hook_state(mod, is_first_use);
22742281

22752282
lua_xmove(lua.get_lua_state(), hook_lua->get_lua_state(), 1);
22762283

@@ -2320,7 +2327,8 @@ No overload found for function 'RegisterLoadMapPreHook'.
23202327
}
23212328

23222329
auto mod = get_mod_ref(lua);
2323-
auto hook_lua = make_hook_state(mod);
2330+
bool is_first_use = false;
2331+
auto hook_lua = make_hook_state(mod, is_first_use);
23242332

23252333
lua_xmove(lua.get_lua_state(), hook_lua->get_lua_state(), 1);
23262334

@@ -2347,7 +2355,8 @@ No overload found for function 'RegisterLoadMapPostHook'.
23472355
}
23482356

23492357
auto mod = get_mod_ref(lua);
2350-
auto hook_lua = make_hook_state(mod);
2358+
bool is_first_use = false;
2359+
auto hook_lua = make_hook_state(mod, is_first_use);
23512360

23522361
lua_xmove(lua.get_lua_state(), hook_lua->get_lua_state(), 1);
23532362

@@ -2374,7 +2383,8 @@ No overload found for function 'RegisterInitGameStatePreHook'.
23742383
}
23752384

23762385
auto mod = get_mod_ref(lua);
2377-
auto hook_lua = make_hook_state(mod);
2386+
bool is_first_use = false;
2387+
auto hook_lua = make_hook_state(mod, is_first_use);
23782388

23792389
lua_xmove(lua.get_lua_state(), hook_lua->get_lua_state(), 1);
23802390

@@ -2402,7 +2412,8 @@ No overload found for function 'RegisterInitGameStatePostHook'.
24022412
}
24032413

24042414
auto mod = get_mod_ref(lua);
2405-
auto hook_lua = make_hook_state(mod);
2415+
bool is_first_use = false;
2416+
auto hook_lua = make_hook_state(mod, is_first_use);
24062417

24072418
lua_xmove(lua.get_lua_state(), hook_lua->get_lua_state(), 1);
24082419

@@ -2430,7 +2441,8 @@ No overload found for function 'RegisterBeginPlayPreHook'.
24302441
}
24312442

24322443
auto mod = get_mod_ref(lua);
2433-
auto hook_lua = make_hook_state(mod);
2444+
bool is_first_use = false;
2445+
auto hook_lua = make_hook_state(mod, is_first_use);
24342446

24352447
lua_xmove(lua.get_lua_state(), hook_lua->get_lua_state(), 1);
24362448

@@ -2458,7 +2470,8 @@ No overload found for function 'RegisterBeginPlayPostHook'.
24582470
}
24592471

24602472
auto mod = get_mod_ref(lua);
2461-
auto hook_lua = make_hook_state(mod);
2473+
bool is_first_use = false;
2474+
auto hook_lua = make_hook_state(mod, is_first_use);
24622475

24632476
lua_xmove(lua.get_lua_state(), hook_lua->get_lua_state(), 1);
24642477

@@ -2486,7 +2499,8 @@ No overload found for function 'RegisterEndPlayPreHook'.
24862499
}
24872500

24882501
auto mod = get_mod_ref(lua);
2489-
auto hook_lua = make_hook_state(mod);
2502+
bool is_first_use = false;
2503+
auto hook_lua = make_hook_state(mod, is_first_use);
24902504

24912505
lua_xmove(lua.get_lua_state(), hook_lua->get_lua_state(), 1);
24922506

@@ -2514,7 +2528,8 @@ No overload found for function 'RegisterEndPlayPostHook'.
25142528
}
25152529

25162530
auto mod = get_mod_ref(lua);
2517-
auto hook_lua = make_hook_state(mod);
2531+
bool is_first_use = false;
2532+
auto hook_lua = make_hook_state(mod, is_first_use);
25182533

25192534
lua_xmove(lua.get_lua_state(), hook_lua->get_lua_state(), 1);
25202535

@@ -2958,7 +2973,8 @@ No overload found for function 'RegisterProcessConsoleExecPreHook'.
29582973

29592974
LuaMod::LuaCallbackData* callback = nullptr;
29602975
auto mod = get_mod_ref(lua);
2961-
auto hook_lua = make_hook_state(mod);
2976+
bool is_first_use = false;
2977+
auto hook_lua = make_hook_state(mod, is_first_use);
29622978
callback = &LuaMod::m_process_console_exec_pre_callbacks.emplace_back(LuaMod::LuaCallbackData{hook_lua, nullptr, {}});
29632979
lua_xmove(lua.get_lua_state(), callback->lua->get_lua_state(), 1);
29642980
const int32_t lua_function_ref = callback->lua->registry().make_ref();
@@ -2979,7 +2995,8 @@ No overload found for function 'RegisterProcessConsoleExecPostHook'.
29792995

29802996
LuaMod::LuaCallbackData* callback = nullptr;
29812997
auto mod = get_mod_ref(lua);
2982-
auto hook_lua = make_hook_state(mod);
2998+
bool is_first_use = false;
2999+
auto hook_lua = make_hook_state(mod, is_first_use);
29833000
callback = &LuaMod::m_process_console_exec_post_callbacks.emplace_back(LuaMod::LuaCallbackData{hook_lua, nullptr, {}});
29843001
lua_xmove(lua.get_lua_state(), callback->lua->get_lua_state(), 1);
29853002
const int32_t lua_function_ref = callback->lua->registry().make_ref();
@@ -3000,7 +3017,8 @@ No overload found for function 'RegisterCallFunctionByNameWithArgumentsPreHook'.
30003017

30013018
LuaMod::LuaCallbackData* callback = nullptr;
30023019
auto mod = get_mod_ref(lua);
3003-
auto hook_lua = make_hook_state(mod);
3020+
bool is_first_use = false;
3021+
auto hook_lua = make_hook_state(mod, is_first_use);
30043022
callback = &LuaMod::m_call_function_by_name_with_arguments_pre_callbacks.emplace_back(LuaMod::LuaCallbackData{hook_lua, nullptr, {}});
30053023
lua_xmove(lua.get_lua_state(), callback->lua->get_lua_state(), 1);
30063024
const int32_t lua_function_ref = callback->lua->registry().make_ref();
@@ -3021,7 +3039,8 @@ No overload found for function 'RegisterCallFunctionByNameWithArgumentsPostHook'
30213039

30223040
LuaMod::LuaCallbackData* callback = nullptr;
30233041
auto mod = get_mod_ref(lua);
3024-
auto hook_lua = make_hook_state(mod);
3042+
bool is_first_use = false;
3043+
auto hook_lua = make_hook_state(mod, is_first_use);
30253044
callback = &LuaMod::m_call_function_by_name_with_arguments_post_callbacks.emplace_back(LuaMod::LuaCallbackData{hook_lua, nullptr, {}});
30263045
lua_xmove(lua.get_lua_state(), callback->lua->get_lua_state(), 1);
30273046
const int32_t lua_function_ref = callback->lua->registry().make_ref();
@@ -3042,7 +3061,8 @@ No overload found for function 'RegisterULocalPlayerExecPreHook'.
30423061

30433062
LuaMod::LuaCallbackData* callback = nullptr;
30443063
auto mod = get_mod_ref(lua);
3045-
auto hook_lua = make_hook_state(mod);
3064+
bool is_first_use = false;
3065+
auto hook_lua = make_hook_state(mod, is_first_use);
30463066
callback = &LuaMod::m_local_player_exec_pre_callbacks.emplace_back(LuaMod::LuaCallbackData{hook_lua, nullptr, {}});
30473067
lua_xmove(lua.get_lua_state(), callback->lua->get_lua_state(), 1);
30483068
const int32_t lua_function_ref = callback->lua->registry().make_ref();
@@ -3063,7 +3083,8 @@ No overload found for function 'RegisterULocalPlayerExecPostHook'.
30633083

30643084
LuaMod::LuaCallbackData* callback = nullptr;
30653085
auto mod = get_mod_ref(lua);
3066-
auto hook_lua = make_hook_state(mod);
3086+
bool is_first_use = false;
3087+
auto hook_lua = make_hook_state(mod, is_first_use);
30673088
callback = &LuaMod::m_local_player_exec_post_callbacks.emplace_back(LuaMod::LuaCallbackData{hook_lua, nullptr, {}});
30683089
lua_xmove(lua.get_lua_state(), callback->lua->get_lua_state(), 1);
30693090
const int32_t lua_function_ref = callback->lua->registry().make_ref();
@@ -3093,7 +3114,8 @@ No overload found for function 'RegisterConsoleCommandGlobalHandler'.
30933114
if (iter == LuaMod::m_global_command_lua_callbacks.end())
30943115
{
30953116
auto mod = get_mod_ref(lua);
3096-
auto hook_lua = make_hook_state(mod);
3117+
bool is_first_use = false;
3118+
auto hook_lua = make_hook_state(mod, is_first_use);
30973119
callback = &LuaMod::m_global_command_lua_callbacks.emplace(command_name, LuaMod::LuaCallbackData{hook_lua, nullptr, {}}).first->second;
30983120
}
30993121
else
@@ -3128,7 +3150,8 @@ No overload found for function 'RegisterConsoleCommandHandler'.
31283150
if (iter == LuaMod::m_custom_command_lua_pre_callbacks.end())
31293151
{
31303152
auto mod = get_mod_ref(lua);
3131-
auto hook_lua = make_hook_state(mod);
3153+
bool is_first_use = false;
3154+
auto hook_lua = make_hook_state(mod, is_first_use);
31323155
callback = &LuaMod::m_custom_command_lua_pre_callbacks.emplace(command_name, LuaMod::LuaCallbackData{hook_lua, nullptr, {}}).first->second;
31333156
}
31343157
else
@@ -3576,15 +3599,19 @@ No overload found for function 'RegisterHook'.
35763599
}
35773600

35783601
auto mod = get_mod_ref(lua);
3579-
auto hook_lua = make_hook_state(mod); // operates on LuaMod::m_lua incrementing its stack via lua_newthread
3602+
bool is_first_use = false;
3603+
auto hook_lua = make_hook_state(mod, is_first_use); // operates on LuaMod::m_lua incrementing its stack via lua_newthread
35803604

35813605
// Duplicate the Lua function to the top of the stack for lua_xmove and luaL_ref
35823606
lua_pushvalue(lua.get_lua_state(), 1); // operates on LuaMadeSimple::Lua::m_lua_state
35833607
lua_xmove(lua.get_lua_state(), hook_lua->get_lua_state(), 1);
35843608

35853609
// Take a reference to the Lua function (it also pops it of the stack)
35863610
const auto lua_callback_registry_index = luaL_ref(hook_lua->get_lua_state(), LUA_REGISTRYINDEX);
3587-
const auto lua_thread_registry_index = luaL_ref(mod->lua().get_lua_state(), LUA_REGISTRYINDEX);
3611+
3612+
// Only anchor the thread to the parent registry on first use
3613+
// When reusing, the thread is already anchored from the first registration
3614+
const auto lua_thread_registry_index = is_first_use ? luaL_ref(mod->lua().get_lua_state(), LUA_REGISTRYINDEX) : LUA_REFNIL;
35883615

35893616
bool has_post_callback{};
35903617
int lua_post_callback_registry_index = -1;
@@ -3675,15 +3702,18 @@ No overload found for function 'ExecuteInGameThread'.
36753702
}
36763703

36773704
auto mod = get_mod_ref(lua);
3678-
auto hook_lua = make_hook_state(mod);
3705+
bool is_first_use = false;
3706+
auto hook_lua = make_hook_state(mod, is_first_use);
36793707

36803708
// Duplicate the Lua function to the top of the stack for lua_xmove and luaL_ref
36813709
lua_pushvalue(lua.get_lua_state(), 1);
36823710

36833711
lua_xmove(lua.get_lua_state(), hook_lua->get_lua_state(), 1);
36843712

36853713
const auto func_ref = luaL_ref(hook_lua->get_lua_state(), LUA_REGISTRYINDEX);
3686-
const auto thread_ref = luaL_ref(mod->lua().get_lua_state(), LUA_REGISTRYINDEX);
3714+
3715+
// Only anchor the thread to the parent registry on first use
3716+
const auto thread_ref = is_first_use ? luaL_ref(mod->lua().get_lua_state(), LUA_REGISTRYINDEX) : LUA_REFNIL;
36873717
SimpleLuaAction simpleAction{hook_lua, func_ref, thread_ref};
36883718
{
36893719
std::lock_guard<std::recursive_mutex> guard{LuaMod::m_thread_actions_mutex};

0 commit comments

Comments
 (0)