From f126a74a91735cca8765bda2a6e7c68a9ad203fa Mon Sep 17 00:00:00 2001 From: bones_was_here Date: Thu, 8 Feb 2024 00:19:05 +1000 Subject: [PATCH] SVVM: Fix segfault during shutdown, improve previous commit In 30c47b1aff3ac28359c469a40c44ee700c80e814 a bug in SVVM_reset_cmd was revealed because that code never ran before that commit: sometimes the server segfaulted at end of match because SVVM_reset_cmd called QC code even though SVVM_reset_cmd would only be called by PRVM_Prog_Reset after it had freed the tempstring memory... so if QC created a tempstring, crash. This commit refactors the SV VM shutdown to be consistent with the CL and MENU shutdown by moving the QC SV_Shutdown() call into a separate func that (optionally) resets the VM afterwards. As per 30c47b1aff3ac28359c469a40c44ee700c80e814 we MUST reset when stopping a server to avoid crashes later, but we can still skip it when changing map (like in previous versions). Signed-off-by: bones_was_here --- sv_main.c | 20 +++++++++++++++++--- svvm_cmds.c | 9 --------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/sv_main.c b/sv_main.c index fed375eb..2f2077a7 100644 --- a/sv_main.c +++ b/sv_main.c @@ -1773,6 +1773,21 @@ int SV_IsLocalServer(void) return (host_isclient.integer && sv.active ? svs.maxclients : 0); } +static void SV_VM_Shutdown(qbool prog_reset) +{ + prvm_prog_t *prog = SVVM_prog; + + if(prog->loaded && PRVM_serverfunction(SV_Shutdown)) + { + func_t s = PRVM_serverfunction(SV_Shutdown); + PRVM_serverglobalfloat(time) = sv.time; + PRVM_serverfunction(SV_Shutdown) = 0; // prevent it from getting called again + prog->ExecuteProgram(prog, s,"SV_Shutdown() required"); + } + if (prog_reset) + PRVM_Prog_Reset(prog); +} + /* ================ SV_SpawnServer @@ -1816,7 +1831,7 @@ void SV_SpawnServer (const char *map) } if(sv.active) - PRVM_Prog_Reset(prog); // calls graceful SVQC shutdown in SVVM_reset_cmd + SV_VM_Shutdown(false); // free q3 shaders so that any newly downloaded shaders will be active Mod_FreeQ3Shaders(); @@ -2103,7 +2118,6 @@ This only happens at the end of a game, not between levels */ void SV_Shutdown(void) { - prvm_prog_t *prog = SVVM_prog; int i; SV_LockThreadMutex(); @@ -2121,7 +2135,7 @@ void SV_Shutdown(void) if (host_client->active) SV_DropClient(false, "Server shutting down"); // server shutdown - PRVM_Prog_Reset(prog); // calls graceful SVQC shutdown in SVVM_reset_cmd + SV_VM_Shutdown(true); NetConn_CloseServerPorts(); diff --git a/svvm_cmds.c b/svvm_cmds.c index 278786ea..ce0a4bf9 100644 --- a/svvm_cmds.c +++ b/svvm_cmds.c @@ -3924,14 +3924,5 @@ void SVVM_init_cmd(prvm_prog_t *prog) void SVVM_reset_cmd(prvm_prog_t *prog) { World_End(&sv.world); - - if(prog->loaded && PRVM_serverfunction(SV_Shutdown)) - { - func_t s = PRVM_serverfunction(SV_Shutdown); - PRVM_serverglobalfloat(time) = sv.time; - PRVM_serverfunction(SV_Shutdown) = 0; // prevent it from getting called again - prog->ExecuteProgram(prog, s,"SV_Shutdown() required"); - } - VM_Cmd_Reset(prog); } -- 2.39.2