Skip to content

Commit

Permalink
Stop fiddling around with jmp_buf.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
skullernet committed Dec 3, 2014
1 parent 7525450 commit 924ff39
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 30 deletions.
5 changes: 2 additions & 3 deletions inc/common/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <setjmp.h>

//
// common.h -- definitions common between client and server, but not game.dll
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down
19 changes: 18 additions & 1 deletion src/common/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 <setjmp.h>

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
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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)
{
Expand Down
22 changes: 10 additions & 12 deletions src/server/commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));

Expand All @@ -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;
Expand All @@ -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);

Expand Down
3 changes: 3 additions & 0 deletions src/server/mvd/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/

#include "../server.h"
#include <setjmp.h>

#define MVD_Malloc(size) Z_TagMalloc(size, TAG_MVD)
#define MVD_Mallocz(size) Z_TagMallocz(size, TAG_MVD)
Expand Down Expand Up @@ -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
Expand Down
2 changes: 0 additions & 2 deletions src/server/mvd/game.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
21 changes: 9 additions & 12 deletions src/server/save.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down

1 comment on commit 924ff39

@macolez
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi there Skuller. Im from a aq2 Brazil community. How can i contact you? My email: [email protected]

Please sign in to comment.