From: bones_was_here <bones_was_here@xonotic.au>
Date: Tue, 6 Feb 2024 11:22:06 +0000 (+1000)
Subject: SVVM: fully shut down when stopping a server to avoid segfaulting later
X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=30c47b1aff3ac28359c469a40c44ee700c80e814;p=xonotic%2Fdarkplaces.git

SVVM: fully shut down when stopping a server to avoid segfaulting later

Fixes segfaults when functions that check if the progs is loaded (to
avoid crashing) are called after stopping a server.
Example repro: load a map, disconnect, `set sv_cheats 0`.

Fixes wrong SV_Shutdown order: SV_DropClient must be done before
shutting down SVQC because it calls SVQC functions.

Deduplicates SVQC shutdown.

Signed-off-by: bones_was_here <bones_was_here@xonotic.au>
---

diff --git a/sv_main.c b/sv_main.c
index 65ba374d..fed375eb 100644
--- a/sv_main.c
+++ b/sv_main.c
@@ -1816,16 +1816,7 @@ void SV_SpawnServer (const char *map)
 	}
 
 	if(sv.active)
-	{
-		World_End(&sv.world);
-		if(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");
-		}
-	}
+		PRVM_Prog_Reset(prog); // calls graceful SVQC shutdown in SVVM_reset_cmd
 
 	// free q3 shaders so that any newly downloaded shaders will be active
 	Mod_FreeQ3Shaders();
@@ -2125,22 +2116,13 @@ void SV_Shutdown(void)
 	NetConn_Heartbeat(2);
 	NetConn_Heartbeat(2);
 
-// make sure all the clients know we're disconnecting
-	World_End(&sv.world);
-	if(prog->loaded)
-	{
-		if(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");
-		}
-	}
+	// make sure all the clients know we're disconnecting
 	for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
 		if (host_client->active)
 			SV_DropClient(false, "Server shutting down"); // server shutdown
 
+	PRVM_Prog_Reset(prog); // calls graceful SVQC shutdown in SVVM_reset_cmd
+
 	NetConn_CloseServerPorts();
 
 	sv.active = false;