]> git.xonotic.org Git - xonotic/darkplaces.git/commitdiff
SVVM: Fix segfault during shutdown, improve previous commit
authorbones_was_here <bones_was_here@xonotic.au>
Wed, 7 Feb 2024 14:19:05 +0000 (00:19 +1000)
committerbones_was_here <bones_was_here@xonotic.au>
Wed, 7 Feb 2024 14:37:13 +0000 (00:37 +1000)
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 <bones_was_here@xonotic.au>
sv_main.c
svvm_cmds.c

index fed375eb8bfd2e4da21d116c6757d0c1a1970613..2f2077a75abe544d523ab521cdae1f48e89db699 100644 (file)
--- 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();
 
index 278786ea481c47a3f10c82fb388896ca444f0635..ce0a4bf90dd071346e4cafec1bcb9d40c641be26 100644 (file)
@@ -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);
 }