From 924ff39aa48df1d6cd985b42a2fe5a60ff154030 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Wed, 3 Dec 2014 13:28:16 +0300 Subject: [PATCH] Stop fiddling around with jmp_buf. Implement custom abort function handler for cleaning up CM after failed server startup. Less hacky and more portable than previous solution that involved swapping copies of jmp_buf around. Fixes a weird Win64 crash when loading savegames. --- inc/common/common.h | 5 ++--- src/common/common.c | 19 ++++++++++++++++++- src/server/commands.c | 22 ++++++++++------------ src/server/mvd/client.h | 3 +++ src/server/mvd/game.c | 2 -- src/server/save.c | 21 +++++++++------------ 6 files changed, 42 insertions(+), 30 deletions(-) diff --git a/inc/common/common.h b/inc/common/common.h index 643a9f179..1ed0a20d9 100644 --- a/inc/common/common.h +++ b/inc/common/common.h @@ -21,7 +21,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "common/cmd.h" #include "common/utils.h" -#include // // common.h -- definitions common between client and server, but not game.dll @@ -83,6 +82,8 @@ typedef void (*rdflush_t)(int target, char *buffer, size_t len); void Com_BeginRedirect(int target, char *buffer, size_t buffersize, rdflush_t flush); void Com_EndRedirect(void); +void Com_AbortFunc(void (*func)(void *), void *arg); + #ifdef _WIN32 void Com_AbortFrame(void); #endif @@ -175,8 +176,6 @@ extern unsigned time_before_ref; extern unsigned time_after_ref; #endif -extern jmp_buf com_abortframe; - extern const char com_version_string[]; extern unsigned com_framenum; diff --git a/src/common/common.c b/src/common/common.c index 48a82ea67..a136c43fb 100644 --- a/src/common/common.c +++ b/src/common/common.c @@ -49,7 +49,12 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "server/server.h" #include "system/system.h" -jmp_buf com_abortframe; // an ERR_DROP occured, exit the entire frame +#include + +static jmp_buf com_abortframe; // an ERR_DROP occured, exit the entire frame + +static void (*com_abort_func)(void *); +static void *com_abort_arg; static qboolean com_errorEntered; static char com_errorMsg[MAXERRORMSG]; // from Com_Printf/Com_Error @@ -509,6 +514,12 @@ void Com_Error(error_type_t code, const char *fmt, ...) // abort any console redirects Com_AbortRedirect(); + // call custom cleanup function if set + if (com_abort_func) { + com_abort_func(com_abort_arg); + com_abort_func = NULL; + } + // reset Com_Printf recursion level com_printEntered = 0; @@ -562,6 +573,12 @@ void Com_Error(error_type_t code, const char *fmt, ...) longjmp(com_abortframe, -1); } +void Com_AbortFunc(void (*func)(void *), void *arg) +{ + com_abort_func = func; + com_abort_arg = arg; +} + #ifdef _WIN32 void Com_AbortFrame(void) { diff --git a/src/server/commands.c b/src/server/commands.c index 09a799027..b5c09fe12 100644 --- a/src/server/commands.c +++ b/src/server/commands.c @@ -257,11 +257,16 @@ another level: map tram.cin+jail_e3 ====================== */ + +static void abort_func(void *arg) +{ + CM_FreeMap(arg); +} + static void SV_Map(qboolean restart) { mapcmd_t cmd; size_t len; - jmp_buf tmp; memset(&cmd, 0, sizeof(cmd)); @@ -275,15 +280,8 @@ static void SV_Map(qboolean restart) if (!SV_ParseMapCmd(&cmd)) return; - // save error frame - memcpy(tmp, com_abortframe, sizeof(jmp_buf)); - - // catch ERR_DROP and free the map - if (setjmp(com_abortframe)) { - memcpy(com_abortframe, tmp, sizeof(jmp_buf)); - CM_FreeMap(&cmd.cm); - return; - } + // save pending CM to be freed later if ERR_DROP is thrown + Com_AbortFunc(abort_func, &cmd.cm); // wipe savegames cmd.endofunit |= restart; @@ -294,8 +292,8 @@ static void SV_Map(qboolean restart) if ((sv.state != ss_game && sv.state != ss_pic) || restart) SV_InitGame(MVD_SPAWN_DISABLED); // the game is just starting - // restore error frame - memcpy(com_abortframe, tmp, sizeof(jmp_buf)); + // clear pending CM + Com_AbortFunc(NULL, NULL); SV_SpawnServer(&cmd); diff --git a/src/server/mvd/client.h b/src/server/mvd/client.h index f2ec522e7..278fb3f3b 100644 --- a/src/server/mvd/client.h +++ b/src/server/mvd/client.h @@ -17,6 +17,7 @@ with this program; if not, write to the Free Software Foundation, Inc., */ #include "../server.h" +#include #define MVD_Malloc(size) Z_TagMalloc(size, TAG_MVD) #define MVD_Mallocz(size) Z_TagMallocz(size, TAG_MVD) @@ -187,6 +188,8 @@ extern qboolean mvd_dirty; extern qboolean mvd_active; extern unsigned mvd_last_activity; +extern jmp_buf mvd_jmpbuf; + #ifdef _DEBUG extern cvar_t *mvd_shownet; #endif diff --git a/src/server/mvd/game.c b/src/server/mvd/game.c index 41eb7e199..db18ef474 100644 --- a/src/server/mvd/game.c +++ b/src/server/mvd/game.c @@ -38,8 +38,6 @@ mvd_client_t *mvd_clients; mvd_player_t mvd_dummy; -extern jmp_buf mvd_jmpbuf; - static int mvd_numplayers; static void MVD_UpdateClient(mvd_client_t *client); diff --git a/src/server/save.c b/src/server/save.c index a5d8eafc4..4413ceee4 100644 --- a/src/server/save.c +++ b/src/server/save.c @@ -304,12 +304,16 @@ char *SV_GetSaveInfo(const char *dir) return Z_CopyString(va("%s %s", date, name)); } +static void abort_func(void *arg) +{ + CM_FreeMap(arg); +} + static int read_server_file(void) { char name[MAX_OSPATH], string[MAX_STRING_CHARS]; mapcmd_t cmd; size_t len; - jmp_buf tmp; // errors like missing file, bad version, etc are // non-fatal and just return to the command handler @@ -342,15 +346,8 @@ static int read_server_file(void) if (!SV_ParseMapCmd(&cmd)) return -1; - // save error frame - memcpy(tmp, com_abortframe, sizeof(jmp_buf)); - - // catch ERR_DROP and free the map - if (setjmp(com_abortframe)) { - memcpy(com_abortframe, tmp, sizeof(jmp_buf)); - CM_FreeMap(&cmd.cm); - return -1; - } + // save pending CM to be freed later if ERR_DROP is thrown + Com_AbortFunc(abort_func, &cmd.cm); // any error will drop from this point SV_Shutdown("Server restarted\n", ERR_RECONNECT); @@ -389,8 +386,8 @@ static int read_server_file(void) ge->ReadGame(name); - // restore error frame - memcpy(com_abortframe, tmp, sizeof(jmp_buf)); + // clear pending CM + Com_AbortFunc(NULL, NULL); // go to the map SV_SpawnServer(&cmd);