From 591877ee0c64958303dcbb4f2af3d343a420cf6a Mon Sep 17 00:00:00 2001 From: bones_was_here Date: Mon, 22 Jan 2024 07:52:26 +1000 Subject: [PATCH] sys: improve error and crash handling Renames Sys_Error to Sys_Abort (now using the Engine Abort message) for clarity (as distinct from the non-fatal Host_Error). Includes the engine version in the Crash and Abort SDL dialogs. Linux: includes the glibc backtrace in the Engine Crash SDL dialog. Fixes CTRL+C not working while the SDL dialog is open. Fixes a double Sys_Error/Sys_Abort when memory corruption was detected. Windows: omits colours when printing a Crash to stderr (not supported). Makes signal handling (mostly) POSIX async-signal-safe. Fixes a slight bug in PRVM_ShortStackTrace(). Signed-off-by: bones_was_here --- cap_avi.c | 10 ++-- cap_ogg.c | 12 ++-- cl_demo.c | 2 +- cl_main.c | 2 +- cl_particles.c | 2 +- common.h | 2 +- gl_backend.c | 8 +-- gl_rmain.c | 4 +- gl_textures.c | 14 ++--- host.c | 15 ++--- host.h | 3 +- menu.c | 4 +- model_shared.c | 2 +- phys.c | 2 +- prvm_cmds.c | 2 +- prvm_exec.c | 7 ++- r_modules.c | 2 +- snd_oss.c | 2 +- snd_sdl.c | 2 +- sv_send.c | 2 +- sys.h | 6 +- sys_null.c | 4 +- sys_sdl.c | 4 +- sys_shared.c | 148 +++++++++++++++++++++++++++++++++++-------------- vid_sdl.c | 8 +-- vid_shared.c | 8 +-- world.c | 4 +- zone.c | 60 ++++++++++---------- 28 files changed, 204 insertions(+), 137 deletions(-) diff --git a/cap_avi.c b/cap_avi.c index ea0e3544..136a9ec2 100644 --- a/cap_avi.c +++ b/cap_avi.c @@ -188,10 +188,10 @@ static void SCR_CaptureVideo_RIFF_IndexEntry(const char *chunkfourcc, int chunks { LOAD_FORMATSPECIFIC_AVI(); if(!format->canseek) - Sys_Error("SCR_CaptureVideo_RIFF_IndexEntry called on non-seekable AVI"); + Sys_Abort("SCR_CaptureVideo_RIFF_IndexEntry called on non-seekable AVI"); if (format->riffstacklevel != 2) - Sys_Error("SCR_Capturevideo_RIFF_IndexEntry: RIFF stack level is %i (should be 2)\n", format->riffstacklevel); + Sys_Abort("SCR_Capturevideo_RIFF_IndexEntry: RIFF stack level is %i (should be 2)\n", format->riffstacklevel); GrowBuf(&format->riffindexbuffer, 16); SCR_CaptureVideo_RIFF_Flush(); MSG_WriteUnterminatedString(&format->riffindexbuffer, chunkfourcc); @@ -209,7 +209,7 @@ static void SCR_CaptureVideo_RIFF_MakeIxChunk(const char *fcc, const char *dwChu fs_offset_t pos, sz; if(!format->canseek) - Sys_Error("SCR_CaptureVideo_RIFF_MakeIxChunk called on non-seekable AVI"); + Sys_Abort("SCR_CaptureVideo_RIFF_MakeIxChunk called on non-seekable AVI"); if(*masteridx_count >= AVI_MASTER_INDEX_SIZE) return; @@ -312,7 +312,7 @@ static void SCR_CaptureVideo_RIFF_OverflowCheck(int framesize) fs_offset_t cursize; //fs_offset_t curfilesize; if (format->riffstacklevel != 2) - Sys_Error("SCR_CaptureVideo_RIFF_OverflowCheck: chunk stack leakage!\n"); + Sys_Abort("SCR_CaptureVideo_RIFF_OverflowCheck: chunk stack leakage!\n"); if(!format->canseek) return; @@ -707,7 +707,7 @@ void SCR_CaptureVideo_Avi_BeginVideo(void) // we're done with the headers now... SCR_CaptureVideo_RIFF_Flush(); if (format->riffstacklevel != 2) - Sys_Error("SCR_CaptureVideo_BeginVideo: broken AVI writing code (stack level is %i (should be 2) at end of headers)\n", format->riffstacklevel); + Sys_Abort("SCR_CaptureVideo_BeginVideo: broken AVI writing code (stack level is %i (should be 2) at end of headers)\n", format->riffstacklevel); if(!format->canseek) { diff --git a/cap_ogg.c b/cap_ogg.c index e0f85994..d6f4e6db 100644 --- a/cap_ogg.c +++ b/cap_ogg.c @@ -660,7 +660,7 @@ static void SCR_CaptureVideo_Ogg_Interleave(void) format->videopage.len = pg.header_len + pg.body_len; format->videopage.time = qtheora_granule_time(&format->ts, qogg_page_granulepos(&pg)); if(format->videopage.len > sizeof(format->videopage.data)) - Sys_Error("video page too long"); + Sys_Abort("video page too long"); memcpy(format->videopage.data, pg.header, pg.header_len); memcpy(format->videopage.data + pg.header_len, pg.body, pg.body_len); } @@ -670,7 +670,7 @@ static void SCR_CaptureVideo_Ogg_Interleave(void) format->audiopage.len = pg.header_len + pg.body_len; format->audiopage.time = qvorbis_granule_time(&format->vd, qogg_page_granulepos(&pg)); if(format->audiopage.len > sizeof(format->audiopage.data)) - Sys_Error("audio page too long"); + Sys_Abort("audio page too long"); memcpy(format->audiopage.data, pg.header, pg.header_len); memcpy(format->audiopage.data + pg.header_len, pg.body, pg.body_len); } @@ -765,7 +765,7 @@ static void SCR_CaptureVideo_Ogg_EndVideo(void) while (1) { int result = qogg_stream_flush (&format->to, &pg); if (result < 0) - fprintf (stderr, "Internal Ogg library error.\n"); // TODO Sys_Error + fprintf (stderr, "Internal Ogg library error.\n"); // TODO Sys_Abort if (result <= 0) break; FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len); @@ -777,7 +777,7 @@ static void SCR_CaptureVideo_Ogg_EndVideo(void) while (1) { int result = qogg_stream_flush (&format->vo, &pg); if (result < 0) - fprintf (stderr, "Internal Ogg library error.\n"); // TODO Sys_Error + fprintf (stderr, "Internal Ogg library error.\n"); // TODO Sys_Abort if (result <= 0) break; FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len); @@ -1082,7 +1082,7 @@ void SCR_CaptureVideo_Ogg_BeginVideo(void) { int result = qogg_stream_flush (&format->to, &pg); if (result < 0) - fprintf (stderr, "Internal Ogg library error.\n"); // TODO Sys_Error + fprintf (stderr, "Internal Ogg library error.\n"); // TODO Sys_Abort if (result <= 0) break; FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len); @@ -1094,7 +1094,7 @@ void SCR_CaptureVideo_Ogg_BeginVideo(void) { int result = qogg_stream_flush (&format->vo, &pg); if (result < 0) - fprintf (stderr, "Internal Ogg library error.\n"); // TODO Sys_Error + fprintf (stderr, "Internal Ogg library error.\n"); // TODO Sys_Abort if (result <= 0) break; FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len); diff --git a/cl_demo.c b/cl_demo.c index a11d63b5..cd884e5a 100644 --- a/cl_demo.c +++ b/cl_demo.c @@ -145,7 +145,7 @@ void CL_CutDemo (unsigned char **buf, fs_offset_t *filesize) // restart the demo recording cls.demofile = FS_OpenRealFile(cls.demoname, "wb", false); if(!cls.demofile) - Sys_Error("failed to reopen the demo file"); + Sys_Abort("failed to reopen the demo file"); FS_Printf(cls.demofile, "%i\n", cls.forcetrack); } diff --git a/cl_main.c b/cl_main.c index 6a69648e..cba1b756 100644 --- a/cl_main.c +++ b/cl_main.c @@ -302,7 +302,7 @@ void CL_ExpandEntities(int num) if (num >= cl.max_entities) { if (!cl.entities) - Sys_Error("CL_ExpandEntities: cl.entities not initialized"); + Sys_Abort("CL_ExpandEntities: cl.entities not initialized"); if (num >= MAX_EDICTS) Host_Error("CL_ExpandEntities: num %i >= %i", num, MAX_EDICTS); oldmaxentities = cl.max_entities; diff --git a/cl_particles.c b/cl_particles.c index 31abace8..1757b80e 100644 --- a/cl_particles.c +++ b/cl_particles.c @@ -2025,7 +2025,7 @@ static void setuptex(int texnum, unsigned char *data, unsigned char *particletex int basex, basey, w, h, y; CL_Particle_PixelCoordsForTexnum(texnum, &basex, &basey, &w, &h); if(w != PARTICLETEXTURESIZE || h != PARTICLETEXTURESIZE) - Sys_Error("invalid particle texture size for autogenerating"); + Sys_Abort("invalid particle texture size for autogenerating"); for (y = 0;y < PARTICLETEXTURESIZE;y++) memcpy(particletexturedata + ((basey + y) * PARTICLEFONTSIZE + basex) * 4, data + y * PARTICLETEXTURESIZE * 4, PARTICLETEXTURESIZE * 4); } diff --git a/common.h b/common.h index 200e432b..1414e633 100644 --- a/common.h +++ b/common.h @@ -47,7 +47,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. typedef struct sizebuf_s { - qbool allowoverflow; ///< if false, do a Sys_Error + qbool allowoverflow; ///< if false, do a Sys_Abort qbool overflowed; ///< set to true if the buffer size failed unsigned char *data; int maxsize; diff --git a/gl_backend.c b/gl_backend.c index b5336a22..09614742 100644 --- a/gl_backend.c +++ b/gl_backend.c @@ -108,7 +108,7 @@ static void GLAPIENTRY GL_DebugOutputCallback(GLenum source, GLenum type, GLuint } #endif -#define BACKENDACTIVECHECK if (!gl_state.active) Sys_Error("GL backend function called when backend is not active"); +#define BACKENDACTIVECHECK if (!gl_state.active) Sys_Abort("GL backend function called when backend is not active"); void SCR_ScreenShot_f(cmd_state_t *cmd); @@ -1978,7 +1978,7 @@ void R_Mesh_TexCoordPointer(unsigned int unitnum, int components, int gltype, si { gltextureunit_t *unit = gl_state.units + unitnum; if (unitnum >= MAX_TEXTUREUNITS) - Sys_Error("R_Mesh_TexCoordPointer: unitnum %i > max units %i\n", unitnum, MAX_TEXTUREUNITS); + Sys_Abort("R_Mesh_TexCoordPointer: unitnum %i > max units %i\n", unitnum, MAX_TEXTUREUNITS); // update array settings // note: there is no need to check bufferobject here because all cases // that involve a valid bufferobject also supply a texcoord array @@ -2027,7 +2027,7 @@ int R_Mesh_TexBound(unsigned int unitnum, int id) { gltextureunit_t *unit = gl_state.units + unitnum; if (unitnum >= MAX_TEXTUREUNITS) - Sys_Error("R_Mesh_TexCoordPointer: unitnum %i > max units %i\n", unitnum, MAX_TEXTUREUNITS); + Sys_Abort("R_Mesh_TexCoordPointer: unitnum %i > max units %i\n", unitnum, MAX_TEXTUREUNITS); if (id == GL_TEXTURE_2D) return unit->t2d; if (id == GL_TEXTURE_3D) @@ -2068,7 +2068,7 @@ void R_Mesh_TexBind(unsigned int unitnum, rtexture_t *tex) gltextureunit_t *unit = gl_state.units + unitnum; int texnum; if (unitnum >= MAX_TEXTUREUNITS) - Sys_Error("R_Mesh_TexBind: unitnum %i > max units %i\n", unitnum, MAX_TEXTUREUNITS); + Sys_Abort("R_Mesh_TexBind: unitnum %i > max units %i\n", unitnum, MAX_TEXTUREUNITS); switch(vid.renderpath) { case RENDERPATH_GL32: diff --git a/gl_rmain.c b/gl_rmain.c index ec88c187..cb77104b 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -3733,7 +3733,7 @@ r_meshbuffer_t *R_BufferData_Store(size_t datasize, const void *data, r_bufferda // if the resize did not give us enough memory, fail if (!r_bufferdata_buffer[r_bufferdata_cycle][type] || r_bufferdata_buffer[r_bufferdata_cycle][type]->current + padsize > r_bufferdata_buffer[r_bufferdata_cycle][type]->size) - Sys_Error("R_BufferData_Store: failed to create a new buffer of sufficient size\n"); + Sys_Abort("R_BufferData_Store: failed to create a new buffer of sufficient size\n"); mem = r_bufferdata_buffer[r_bufferdata_cycle][type]; offset = (int)mem->current; @@ -8549,7 +8549,7 @@ void RSurf_DrawBatch(void) if (c >= rsurface.modelsurfaces[j].num_firstvertex && c < (rsurface.modelsurfaces[j].num_firstvertex + rsurface.modelsurfaces[j].num_vertices)) { if (rsurface.modelsurfaces[j].texture != rsurface.texture) - Sys_Error("RSurf_DrawBatch: index %i uses different texture (%s) than surface %i which it belongs to (which uses %s)\n", c, rsurface.texture->name, j, rsurface.modelsurfaces[j].texture->name); + Sys_Abort("RSurf_DrawBatch: index %i uses different texture (%s) than surface %i which it belongs to (which uses %s)\n", c, rsurface.texture->name, j, rsurface.modelsurfaces[j].texture->name); break; } } diff --git a/gl_textures.c b/gl_textures.c index 7065432e..b1cc74a1 100644 --- a/gl_textures.c +++ b/gl_textures.c @@ -928,19 +928,19 @@ static void GL_SetupTextureParameters(int flags, textype_t textype, int texturet static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth) { if (data == NULL) - Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier); + Sys_Abort("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier); if (glt->texturetype != GLTEXTURETYPE_2D) - Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier); + Sys_Abort("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier); if (glt->textype->textype == TEXTYPE_PALETTE) - Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier); + Sys_Abort("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier); if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP)) - Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier); + Sys_Abort("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier); if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1) - Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier); + Sys_Abort("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier); // update a portion of the image @@ -971,7 +971,7 @@ static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data) // error out if a stretch is needed on special texture types if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth)) - Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier); + Sys_Abort("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier); // when picmip or maxsize is applied, we scale up to a power of 2 multiple // of the target size and then use the mipmap reduction function to get @@ -1280,7 +1280,7 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden flags |= TEXF_ALPHA; break; default: - Sys_Error("R_LoadTexture: unknown texture type"); + Sys_Abort("R_LoadTexture: unknown texture type"); } texinfo2 = R_GetTexTypeInfo(textype, flags); diff --git a/host.c b/host.c index d291799c..bb1b83fc 100644 --- a/host.c +++ b/host.c @@ -105,12 +105,12 @@ void Host_Error (const char *error, ...) Con_Printf(CON_ERROR "Host_Error: %s\n", hosterrorstring1); // LadyHavoc: if crashing very early, or currently shutting down, do - // Sys_Error instead + // Sys_Abort instead if (host.framecount < 3 || host.state == host_shutdown) - Sys_Error ("Host_Error: %s", hosterrorstring1); + Sys_Abort ("Host_Error during %s: %s", host.framecount < 3 ? "startup" : "shutdown", hosterrorstring1); if (hosterror) - Sys_Error ("Host_Error: recursively entered (original error was: %s new error is: %s)", hosterrorstring2, hosterrorstring1); + Sys_Abort ("Host_Error: recursively entered (original error was: %s new error is: %s)", hosterrorstring2, hosterrorstring1); hosterror = true; dp_strlcpy(hosterrorstring2, hosterrorstring1, sizeof(hosterrorstring2)); @@ -135,11 +135,12 @@ void Host_Error (const char *error, ...) host.hook.SV_Shutdown(); if (cls.state == ca_dedicated) - Sys_Error ("Host_Error: %s",hosterrorstring2); // dedicated servers exit + Sys_Abort ("Host_Error: %s",hosterrorstring2); // dedicated servers exit // prevent an endless loop if the error was triggered by a command Cbuf_Clear(cmd_local->cbuf); + // DP8 TODO: send a disconnect message indicating we errored out, see Sys_Abort() and Sys_HandleCrash() CL_Disconnect(); cls.demonum = -1; @@ -344,7 +345,7 @@ void Host_LockSession(void) } else { - Sys_Error("session lock %s could not be acquired. Please run with -sessionid and an unique session name.\n", p); + Sys_Abort("session lock %s could not be acquired. Please run with -sessionid and an unique session name.\n", p); } } } @@ -389,7 +390,7 @@ static void Host_Init (void) host.state = host_init; if (setjmp(host.abortframe)) // Huh?! - Sys_Error("Engine initialization failed. Check the console (if available) for additional information.\n"); + Sys_Abort("Engine initialization failed. Check the console (if available) for additional information.\n"); if (Sys_CheckParm("-profilegameonly")) Sys_AllowProfiling(false); @@ -573,7 +574,7 @@ static void Host_Init (void) =============== Host_Shutdown -FIXME: this is a callback from Sys_Quit and Sys_Error. It would be better +FIXME: this is a callback from Sys_Quit(). It would be better to run quit through here before the final handoff to the sys code. =============== */ diff --git a/host.h b/host.h index 61182b52..78bd8083 100644 --- a/host.h +++ b/host.h @@ -23,7 +23,8 @@ typedef enum host_state_e host_shutdown, host_init, host_loading, - host_active + host_active, + host_failed ///< crashed or aborted, SDL dialog open } host_state_t; typedef struct host_static_s diff --git a/menu.c b/menu.c index f2d35983..e26e74d7 100644 --- a/menu.c +++ b/menu.c @@ -2573,7 +2573,7 @@ void M_Menu_Keys_f(cmd_state_t *cmd) // Only sections? There may be a problem somewhere... if (keys_cursor >= numcommands) - Sys_Error ("M_Init: The key binding list only contains sections"); + Sys_Abort ("M_Init: The key binding list only contains sections"); } } @@ -5221,7 +5221,7 @@ void MVM_error_cmd(const char *format, ...) va_end (argptr); if (host.framecount < 3) - Sys_Error("Menu_Error: %s\n", errorstring); + Sys_Abort("Menu_Error: %s\n", errorstring); Con_Printf( "Menu_Error: %s\n", errorstring ); diff --git a/model_shared.c b/model_shared.c index 11b0d61c..fd181f35 100644 --- a/model_shared.c +++ b/model_shared.c @@ -550,7 +550,7 @@ model_t *Mod_LoadModel(model_t *mod, qbool crash, qbool checkdisk) Con_Printf(CON_ERROR "Mod_LoadModel: model \"%s\" is of unknown/unsupported type\n", mod->name); } else if (crash) - // LadyHavoc: Sys_Error was *ANNOYING* + // LadyHavoc: Sys_Abort was *ANNOYING* Con_Printf (CON_ERROR "Mod_LoadModel: %s not found\n", mod->name); // no fatal errors occurred, so this model is ready to use. diff --git a/phys.c b/phys.c index 7128ea3d..04c5449d 100644 --- a/phys.c +++ b/phys.c @@ -26,7 +26,7 @@ int PHYS_NudgeOutOfSolid(prvm_prog_t *prog, prvm_edict_t *ent) separation = cl_gameplayfix_nudgeoutofsolid_separation.value; } else - Sys_Error("PHYS_NudgeOutOfSolid: cannot be called from %s VM\n", prog->name); + Sys_Abort("PHYS_NudgeOutOfSolid: cannot be called from %s VM\n", prog->name); VectorCopy(PRVM_serveredictvector(ent, mins), stuckmins); VectorCopy(PRVM_serveredictvector(ent, maxs), stuckmaxs); diff --git a/prvm_cmds.c b/prvm_cmds.c index aefac672..6bc211c6 100644 --- a/prvm_cmds.c +++ b/prvm_cmds.c @@ -5687,7 +5687,7 @@ void VM_nudgeoutofsolid(prvm_prog_t *prog) else if (prog == CLVM_prog) CL_LinkEdict(ent); else - Sys_Error("PHYS_NudgeOutOfSolid: cannot be called from %s VM\n", prog->name); + Sys_Abort("PHYS_NudgeOutOfSolid: cannot be called from %s VM\n", prog->name); } } diff --git a/prvm_exec.c b/prvm_exec.c index ee738b9c..4c50ff6e 100644 --- a/prvm_exec.c +++ b/prvm_exec.c @@ -431,14 +431,15 @@ void PRVM_StackTrace (prvm_prog_t *prog) void PRVM_ShortStackTrace(prvm_prog_t *prog, char *buf, size_t bufsize) { - mfunction_t *f; - int i; + mfunction_t *f; + int i; char vabuf[1024]; char *p; if(prog) { - p = buf + max(0, dpsnprintf(buf, bufsize, "(%s) ", prog->name)); + i = dpsnprintf(buf, bufsize, "(%s) ", prog->name); + p = buf + max(0, i); } else { diff --git a/r_modules.c b/r_modules.c index dd76b6ca..c6c04191 100644 --- a/r_modules.c +++ b/r_modules.c @@ -36,7 +36,7 @@ void R_RegisterModule(const char *name, void(*start)(void), void(*shutdown)(void } } if (i >= MAXRENDERMODULES) - Sys_Error("R_RegisterModule: ran out of renderer module slots (%i)", MAXRENDERMODULES); + Sys_Abort("R_RegisterModule: ran out of renderer module slots (%i)", MAXRENDERMODULES); rendermodule[i].active = 0; rendermodule[i].name = name; rendermodule[i].start = start; diff --git a/snd_oss.c b/snd_oss.c index 05f91c92..ecf18333 100644 --- a/snd_oss.c +++ b/snd_oss.c @@ -222,7 +222,7 @@ static int SndSys_Write (const unsigned char* buffer, unsigned int nb_bytes) factor = snd_renderbuffer->format.width * snd_renderbuffer->format.channels; if (written % factor != 0) - Sys_Error ("SndSys_Write: nb of bytes written (%d) isn't aligned to a frame sample!\n", + Sys_Abort ("SndSys_Write: nb of bytes written (%d) isn't aligned to a frame sample!\n", written); snd_renderbuffer->startframe += written / factor; diff --git a/snd_sdl.c b/snd_sdl.c index e93d3021..f3479ba9 100644 --- a/snd_sdl.c +++ b/snd_sdl.c @@ -37,7 +37,7 @@ static void Buffer_Callback (void *userdata, Uint8 *stream, int len) factor = snd_renderbuffer->format.channels * snd_renderbuffer->format.width; if ((unsigned int)len % factor != 0) - Sys_Error("SDL sound: invalid buffer length passed to Buffer_Callback (%d bytes)\n", len); + Sys_Abort("SDL sound: invalid buffer length passed to Buffer_Callback (%d bytes)\n", len); RequestedFrames = (unsigned int)len / factor; diff --git a/sv_send.c b/sv_send.c index a8a44347..68856c1a 100644 --- a/sv_send.c +++ b/sv_send.c @@ -1697,7 +1697,7 @@ void SV_SendClientMessages(void) int i, prepared = false; if (sv.protocol == PROTOCOL_QUAKEWORLD) - Sys_Error("SV_SendClientMessages: no quakeworld support\n"); + Sys_Abort("SV_SendClientMessages: no quakeworld support\n"); SV_FlushBroadcastMessages(); diff --git a/sys.h b/sys.h index 2255a6a3..baa7146b 100644 --- a/sys.h +++ b/sys.h @@ -204,10 +204,12 @@ char *Sys_TimeString(const char *timeformat); // system IO interface (these are the sys functions that need to be implemented in a new driver atm) // -/// an error will cause the entire program to exit -void Sys_Error (const char *error, ...) DP_FUNC_PRINTF(1) DP_FUNC_NORETURN; +/// Causes the entire program to exit ASAP. +/// Trailing \n should be omitted. +void Sys_Abort (const char *error, ...) DP_FUNC_PRINTF(1) DP_FUNC_NORETURN; /// (may) output text to terminal which launched program +/// is POSIX async-signal-safe /// textlen excludes any (optional) \0 terminator void Sys_Print(const char *text, size_t textlen); /// used to report failures inside Con_Printf() diff --git a/sys_null.c b/sys_null.c index e2b9b0a0..3b1f356d 100644 --- a/sys_null.c +++ b/sys_null.c @@ -26,10 +26,10 @@ void Sys_SDL_Init(void) qbool sys_supportsdlgetticks = false; unsigned int Sys_SDL_GetTicks (void) { - Sys_Error("Called Sys_SDL_GetTicks on non-SDL target"); + Sys_Abort("Called Sys_SDL_GetTicks on non-SDL target"); return 0; } void Sys_SDL_Delay (unsigned int milliseconds) { - Sys_Error("Called Sys_SDL_Delay on non-SDL target"); + Sys_Abort("Called Sys_SDL_Delay on non-SDL target"); } diff --git a/sys_sdl.c b/sys_sdl.c index f96bc87e..c811cdd9 100644 --- a/sys_sdl.c +++ b/sys_sdl.c @@ -23,7 +23,7 @@ void Sys_SDL_Shutdown(void) SDL_Quit(); } -// Sys_Error early in startup might screw with automated +// Sys_Abort early in startup might screw with automated // workflows or something if we show the dialog by default. static qbool nocrashdialog = true; void Sys_SDL_Dialog(const char *title, const char *string) @@ -53,7 +53,7 @@ void Sys_SDL_Init(void) { // we don't know which systems we'll want to init, yet... if (SDL_Init(0) < 0) - Sys_Error("SDL_Init failed: %s\n", SDL_GetError()); + Sys_Abort("SDL_Init failed: %s\n", SDL_GetError()); // COMMANDLINEOPTION: sdl: -nocrashdialog disables "Engine Error" crash dialog boxes if(!Sys_CheckParm("-nocrashdialog")) diff --git a/sys_shared.c b/sys_shared.c index 26bd27c2..6b5eef43 100644 --- a/sys_shared.c +++ b/sys_shared.c @@ -413,7 +413,7 @@ double Sys_DirtyTime(void) double old_benchmark_time = benchmark_time; benchmark_time += 1; if(benchmark_time == old_benchmark_time) - Sys_Error("sys_usenoclockbutbenchmark cannot run any longer, sorry"); + Sys_Abort("sys_usenoclockbutbenchmark cannot run any longer, sorry"); return benchmark_time * 0.000001; } #if HAVE_QUERYPERFORMANCECOUNTER @@ -494,7 +494,7 @@ double Sys_DirtyTime(void) } #else // fallback for using the SDL timer if no other timer is available - // this calls Sys_Error() if not linking against SDL + // this calls Sys_Abort() if not linking against SDL return (double) Sys_SDL_GetTicks() / 1000.0; #endif } @@ -523,7 +523,7 @@ double Sys_Sleep(double time) double old_benchmark_time = benchmark_time; benchmark_time += microseconds; if(benchmark_time == old_benchmark_time) - Sys_Error("sys_usenoclockbutbenchmark cannot run any longer, sorry"); + Sys_Abort("sys_usenoclockbutbenchmark cannot run any longer, sorry"); return 0; } @@ -596,6 +596,7 @@ STDIO =============================================================================== */ +// NOTE: use only POSIX async-signal-safe library functions here (see: man signal-safety) void Sys_Print(const char *text, size_t textlen) { #ifdef __ANDROID__ @@ -704,10 +705,11 @@ Startup and Shutdown =============================================================================== */ -void Sys_Error (const char *error, ...) +void Sys_Abort (const char *error, ...) { va_list argptr; char string[MAX_INPUTLINE]; + int i; // set output to blocking stderr sys.outfd = fileno(stderr); @@ -719,12 +721,30 @@ void Sys_Error (const char *error, ...) dpvsnprintf (string, sizeof (string), error, argptr); va_end (argptr); - Con_Printf(CON_ERROR "Engine Error: %s\n", string); + Con_Printf(CON_ERROR "Engine Abort: %s\n^9%s\n", string, engineversion); - // don't want a dead window left blocking the OS UI or the crash dialog - Host_Shutdown(); + dp_strlcat(string, "\n\n", sizeof(string)); + dp_strlcat(string, engineversion, sizeof(string)); - Sys_SDL_Dialog("Engine Error", string); + // Most shutdown funcs can't be called here as they could error while we error. + + // DP8 TODO: send a disconnect message indicating we aborted, see Host_Error() and Sys_HandleCrash() + + if (cls.demorecording) + CL_Stop_f(cmd_local); + if (sv.active) + { + sv.active = false; // make SV_DropClient() skip the QC stuff to avoid recursive errors + for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++) + if (host_client->active) + SV_DropClient(false, "Server abort!"); // closes demo file + } + // don't want a dead window left blocking the OS UI or the abort dialog + VID_Shutdown(); + S_StopAllSounds(); + + host.state = host_failed; // make Sys_HandleSignal() call exit() + Sys_SDL_Dialog("Engine Abort", string); fflush(stderr); @@ -925,10 +945,33 @@ void Sys_MakeProcessMean (void) } #endif + +static const char *Sys_SigDesc(int sig) +{ + switch (sig) + { + // Windows only supports the C99 signals + case SIGINT: return "Interrupt"; + case SIGILL: return "Illegal instruction"; + case SIGABRT: return "Aborted"; + case SIGFPE: return "Floating point exception"; + case SIGSEGV: return "Segmentation fault"; + case SIGTERM: return "Termination"; +#ifndef WIN32 + // POSIX has several others worth catching + case SIGHUP: return "Hangup"; + case SIGQUIT: return "Quit"; + case SIGBUS: return "Bus error (bad memory access)"; + case SIGPIPE: return "Broken pipe"; +#endif + default: return "Yo dawg, we bugged out while bugging out"; + } +} + /** Halt and try not to catch fire. * Writing to any file could corrupt it, * any uneccessary code could crash while we crash. - * No malloc() (libgcc should be loaded already) or Con_Printf() allowed here. + * Try to use only POSIX async-signal-safe library functions here (see: man signal-safety). */ static void Sys_HandleCrash(int sig) { @@ -937,70 +980,89 @@ static void Sys_HandleCrash(int sig) #include void *stackframes[32]; int framecount = backtrace(stackframes, 32); + char **btstrings; #endif + char dialogtext[3072]; + const char *sigdesc = Sys_SigDesc(sig); - // Windows doesn't have strsignal() - const char *sigdesc; - switch (sig) - { -#ifndef WIN32 // or SIGBUS - case SIGBUS: sigdesc = "Bus error"; break; -#endif - case SIGILL: sigdesc = "Illegal instruction"; break; - case SIGABRT: sigdesc = "Aborted"; break; - case SIGFPE: sigdesc = "Floating point exception"; break; - case SIGSEGV: sigdesc = "Segmentation fault"; break; - default: sigdesc = "Yo dawg, we hit a bug while hitting a bug"; - } - - // set output to blocking stderr - sys.outfd = fileno(stderr); + // set output to blocking stderr and print header, backtrace, version + sys.outfd = fileno(stderr); // not async-signal-safe :( #ifndef WIN32 fcntl(sys.outfd, F_SETFL, fcntl(sys.outfd, F_GETFL, 0) & ~O_NONBLOCK); -#endif - - fprintf(stderr, "\n\n\e[1;37;41m Engine Crash: %s (%d) \e[m\n", sigdesc, sig); -#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1 + Sys_Print("\n\n\e[1;37;41m Engine Crash: ", 30); + Sys_Print(sigdesc, strlen(sigdesc)); + Sys_Print(" \e[m\n", 8); + #if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1 // the first two addresses will be in this function and in signal() in libc backtrace_symbols_fd(stackframes + 2, framecount - 2, sys.outfd); + #endif + Sys_Print("\e[1m", 4); + Sys_Print(engineversion, strlen(engineversion)); + Sys_Print("\e[m\n", 4); +#else // Windows console doesn't support colours + Sys_Print("\n\nEngine Crash: ", 16); + Sys_Print(sigdesc, strlen(sigdesc)); + Sys_Print("\n", 1); + Sys_Print(engineversion, strlen(engineversion)); + Sys_Print("\n", 1); #endif - fprintf(stderr, "\e[1m%s\e[m\n", engineversion); - // DP8 TODO: send a disconnect message indicating we crashed, see CL_DisconnectEx() + // DP8 TODO: send a disconnect message indicating we crashed, see Sys_Abort() and Host_Error() // don't want a dead window left blocking the OS UI or the crash dialog VID_Shutdown(); S_StopAllSounds(); - Sys_SDL_Dialog("Engine Crash", sigdesc); + // prepare the dialogtext: signal, backtrace, version + // the dp_st* funcs are POSIX async-signal-safe IF we don't trigger their warnings + dp_strlcpy(dialogtext, sigdesc, sizeof(dialogtext)); + dp_strlcat(dialogtext, "\n\n", sizeof(dialogtext)); +#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1 + btstrings = backtrace_symbols(stackframes + 2, framecount - 2); // calls malloc :( + if (btstrings) + for (int i = 0; i < framecount - 2; ++i) + { + dp_strlcat(dialogtext, btstrings[i], sizeof(dialogtext)); + dp_strlcat(dialogtext, "\n", sizeof(dialogtext)); + } +#endif + dp_strlcat(dialogtext, "\n", sizeof(dialogtext)); + dp_strlcat(dialogtext, engineversion, sizeof(dialogtext)); - fflush(stderr); + host.state = host_failed; // make Sys_HandleSignal() call _Exit() + Sys_SDL_Dialog("Engine Crash", dialogtext); - exit (sig); + fflush(stderr); // not async-signal-safe :( + _Exit(sig); } static void Sys_HandleSignal(int sig) { -#ifdef WIN32 - // Windows users will likely never see this so no point replicating strsignal() - Con_Printf("\nReceived signal %d, exiting...\n", sig); -#else - Con_Printf("\nReceived %s signal (%d), exiting...\n", strsignal(sig), sig); -#endif + const char *sigdesc = Sys_SigDesc(sig); + Sys_Print("\nReceived ", 10); + Sys_Print(sigdesc, strlen(sigdesc)); + Sys_Print(" signal, exiting...\n", 20); + if (host.state == host_failed) + { + // user is trying to kill the process while the dialog is open + fflush(stderr); // not async-signal-safe :( + _Exit(sig); + } host.state = host_shutdown; } /// SDL2 only handles SIGINT and SIGTERM by default and doesn't log anything static void Sys_InitSignals(void) { -// Windows docs say its signal() only accepts these ones + // Windows only supports the C99 signals + signal(SIGINT, Sys_HandleSignal); + signal(SIGILL, Sys_HandleCrash); signal(SIGABRT, Sys_HandleCrash); signal(SIGFPE, Sys_HandleCrash); - signal(SIGILL, Sys_HandleCrash); - signal(SIGINT, Sys_HandleSignal); signal(SIGSEGV, Sys_HandleCrash); signal(SIGTERM, Sys_HandleSignal); #ifndef WIN32 + // POSIX has several others worth catching signal(SIGHUP, Sys_HandleSignal); signal(SIGQUIT, Sys_HandleSignal); signal(SIGBUS, Sys_HandleCrash); diff --git a/vid_sdl.c b/vid_sdl.c index 88ec122e..bcb2d139 100644 --- a/vid_sdl.c +++ b/vid_sdl.c @@ -1529,7 +1529,7 @@ void VID_Init (void) Cvar_RegisterCallback(&vid_minimize_on_focus_loss, VID_SetHints_c); if (SDL_Init(SDL_INIT_VIDEO) < 0) - Sys_Error ("Failed to init SDL video subsystem: %s", SDL_GetError()); + Sys_Abort ("Failed to init SDL video subsystem: %s", SDL_GetError()); if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) Con_Printf(CON_ERROR "Failed to init SDL joystick subsystem: %s\n", SDL_GetError()); @@ -1774,7 +1774,7 @@ static qbool VID_InitModeGL(viddef_mode_t *mode) context = SDL_GL_CreateContext(window); if (context == NULL) - Sys_Error("Failed to initialize OpenGL context: %s\n", SDL_GetError()); + Sys_Abort("Failed to initialize OpenGL context: %s\n", SDL_GetError()); GL_InitFunctions(); @@ -1789,7 +1789,7 @@ static qbool VID_InitModeGL(viddef_mode_t *mode) SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); context = SDL_GL_CreateContext(window); if (context == NULL) - Sys_Error("Failed to initialize OpenGL context: %s\n", SDL_GetError()); + Sys_Abort("Failed to initialize OpenGL context: %s\n", SDL_GetError()); } #endif @@ -1827,7 +1827,7 @@ qbool VID_InitMode(viddef_mode_t *mode) steelstorm_showing_mousecursor = Cvar_FindVar(&cvars_all, "steelstorm_showing_mousecursor", ~0); if (!SDL_WasInit(SDL_INIT_VIDEO) && SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) - Sys_Error ("Failed to init SDL video subsystem: %s", SDL_GetError()); + Sys_Abort ("Failed to init SDL video subsystem: %s", SDL_GetError()); Cvar_SetValueQuick(&vid_touchscreen_supportshowkeyboard, SDL_HasScreenKeyboardSupport() ? 1 : 0); return VID_InitModeGL(mode); diff --git a/vid_shared.c b/vid_shared.c index a3d86d3e..44bc9207 100644 --- a/vid_shared.c +++ b/vid_shared.c @@ -706,7 +706,7 @@ void GL_InitFunctions(void) } if (missingrequiredfuncs) - Sys_Error("OpenGL driver/hardware lacks required features:\n%s", missingfuncs); + Sys_Abort("OpenGL driver/hardware lacks required features:\n%s", missingfuncs); #endif } @@ -731,7 +731,7 @@ void GL_Setup(void) vid.support.glversion = 10 * majorv + minorv; if (vid.support.glversion < 32) // fallback, should never get here: GL context creation should have failed - Sys_Error("OpenGL driver/hardware supports version %i.%i but 3.2 is the minimum\n", majorv, minorv); + Sys_Abort("OpenGL driver/hardware supports version %i.%i but 3.2 is the minimum\n", majorv, minorv); qglGetIntegerv(GL_NUM_EXTENSIONS, &numextensions); Con_DPrint("GL_EXTENSIONS:\n"); @@ -1485,7 +1485,7 @@ void VID_Restart_f(cmd_state_t *cmd) { Con_Print("Video mode change failed\n"); if (!VID_Mode(vid.mode.fullscreen, vid.mode.width, vid.mode.height, vid.mode.bitsperpixel, vid.mode.refreshrate, vid.mode.stereobuffer)) - Sys_Error("Unable to restore to last working video mode"); + Sys_Abort("Unable to restore to last working video mode"); } R_Modules_Start(); Key_ReleaseAll(); @@ -1560,7 +1560,7 @@ void VID_Start(void) success = VID_Mode(vid_fullscreen.integer, vid_width.integer, vid_height.integer, vid_bitsperpixel.integer, vid_refreshrate.value, vid_stereobuffer.integer); } if (!success) - Sys_Error("Video modes failed"); + Sys_Abort("Video modes failed"); } R_Modules_Start(); diff --git a/world.c b/world.c index a95330fa..fb70ab02 100644 --- a/world.c +++ b/world.c @@ -2063,7 +2063,7 @@ static void World_Physics_Frame_JointFromEntity(world_t *world, prvm_edict_t *ed break; case 0: default: - Sys_Error("what? but above the joint was valid...\n"); + Sys_Abort("what? but above the joint was valid...\n"); break; } #undef SETPARAMS @@ -2624,7 +2624,7 @@ treatasbox: dMassSetCylinderTotal(&mass, massval, 3, radius, length); break; default: - Sys_Error("World_Physics_BodyFromEntity: unrecognized geomtype value %i was accepted by filter\n", solid); + Sys_Abort("World_Physics_BodyFromEntity: unrecognized geomtype value %i was accepted by filter\n", solid); // this goto only exists to prevent warnings from the compiler // about uninitialized variables (mass), while allowing it to // catch legitimate uninitialized variable warnings diff --git a/zone.c b/zone.c index 1035eb96..81525e4a 100644 --- a/zone.c +++ b/zone.c @@ -230,9 +230,9 @@ static void *Clump_AllocBlock(size_t size) return NULL; } if (clump->sentinel1 != MEMHEADER_SENTINEL_FOR_ADDRESS(&clump->sentinel1)) - Sys_Error("Clump_AllocBlock: trashed sentinel1\n"); + Sys_Abort("Clump_AllocBlock: trashed sentinel1\n"); if (clump->sentinel2 != MEMHEADER_SENTINEL_FOR_ADDRESS(&clump->sentinel2)) - Sys_Error("Clump_AllocBlock: trashed sentinel2\n"); + Sys_Abort("Clump_AllocBlock: trashed sentinel2\n"); startbit = 0; endbit = startbit + needbits; array = clump->bits; @@ -288,7 +288,7 @@ foundblock: // TODO: optimize for (bit = startbit;bit < endbit;bit++) if (clump->bits[bit>>5] & (1<<(bit & 31))) - Sys_Error("Clump_AllocBlock: internal error (%i needbits)\n", needbits); + Sys_Abort("Clump_AllocBlock: internal error (%i needbits)\n", needbits); for (bit = startbit;bit < endbit;bit++) clump->bits[bit>>5] |= (1<<(bit & 31)); clump->blocksinuse += needbits; @@ -328,11 +328,11 @@ static void Clump_FreeBlock(void *base, size_t size) if (start >= clump->block && start < clump->block + MEMCLUMPSIZE) { if (clump->sentinel1 != MEMHEADER_SENTINEL_FOR_ADDRESS(&clump->sentinel1)) - Sys_Error("Clump_FreeBlock: trashed sentinel1\n"); + Sys_Abort("Clump_FreeBlock: trashed sentinel1\n"); if (clump->sentinel2 != MEMHEADER_SENTINEL_FOR_ADDRESS(&clump->sentinel2)) - Sys_Error("Clump_FreeBlock: trashed sentinel2\n"); + Sys_Abort("Clump_FreeBlock: trashed sentinel2\n"); if (start + size > clump->block + MEMCLUMPSIZE) - Sys_Error("Clump_FreeBlock: block overrun\n"); + Sys_Abort("Clump_FreeBlock: block overrun\n"); // the block belongs to this clump, clear the range needbits = (size + MEMUNIT - 1) / MEMUNIT; startbit = (start - clump->block) / MEMUNIT; @@ -340,7 +340,7 @@ static void Clump_FreeBlock(void *base, size_t size) // first verify all bits are set, otherwise this may be misaligned or a double free for (bit = startbit;bit < endbit;bit++) if ((clump->bits[bit>>5] & (1<<(bit & 31))) == 0) - Sys_Error("Clump_FreeBlock: double free\n"); + Sys_Abort("Clump_FreeBlock: double free\n"); for (bit = startbit;bit < endbit;bit++) clump->bits[bit>>5] &= ~(1<<(bit & 31)); clump->blocksinuse -= needbits; @@ -388,7 +388,7 @@ void *_Mem_Alloc(mempool_t *pool, void *olddata, size_t size, size_t alignment, if(olddata) pool = ((memheader_t *)((unsigned char *) olddata - sizeof(memheader_t)))->pool; else - Sys_Error("Mem_Alloc: pool == NULL (alloc at %s:%i)", filename, fileline); + Sys_Abort("Mem_Alloc: pool == NULL (alloc at %s:%i)", filename, fileline); } if (mem_mutex) Thread_LockMutex(mem_mutex); @@ -406,7 +406,7 @@ void *_Mem_Alloc(mempool_t *pool, void *olddata, size_t size, size_t alignment, Mem_PrintStats(); Mem_PrintList(1<<30); Mem_PrintStats(); - Sys_Error("Mem_Alloc: out of memory (alloc of size %f (%.3fMB) at %s:%i)", (double)realsize, (double)realsize / (1 << 20), filename, fileline); + Sys_Abort("Mem_Alloc: out of memory (alloc of size %f (%.3fMB) at %s:%i)", (double)realsize, (double)realsize / (1 << 20), filename, fileline); } // calculate address that aligns the end of the memheader_t to the specified alignment mem = (memheader_t*)((((size_t)base + sizeof(memheader_t) + (alignment-1)) & ~(alignment-1)) - sizeof(memheader_t)); @@ -456,16 +456,16 @@ static void _Mem_FreeBlock(memheader_t *mem, const char *filename, int fileline) sentinel1 = MEMHEADER_SENTINEL_FOR_ADDRESS(&mem->sentinel); sentinel2 = MEMHEADER_SENTINEL_FOR_ADDRESS((unsigned char *) mem + sizeof(memheader_t) + mem->size); if (mem->sentinel != sentinel1) - Sys_Error("Mem_Free: trashed head sentinel (alloc at %s:%i, free at %s:%i)", mem->filename, mem->fileline, filename, fileline); + Sys_Abort("Mem_Free: trashed head sentinel (alloc at %s:%i, free at %s:%i)", mem->filename, mem->fileline, filename, fileline); if (memcmp((unsigned char *) mem + sizeof(memheader_t) + mem->size, &sentinel2, sizeof(sentinel2))) - Sys_Error("Mem_Free: trashed tail sentinel (alloc at %s:%i, free at %s:%i)", mem->filename, mem->fileline, filename, fileline); + Sys_Abort("Mem_Free: trashed tail sentinel (alloc at %s:%i, free at %s:%i)", mem->filename, mem->fileline, filename, fileline); pool = mem->pool; if (developer_memory.integer) Con_DPrintf("Mem_Free: pool %s, alloc %s:%i, free %s:%i, size %i bytes\n", pool->name, mem->filename, mem->fileline, filename, fileline, (int)(mem->size)); // unlink memheader from doubly linked list if (mem->list.prev->next != &mem->list || mem->list.next->prev != &mem->list) - Sys_Error("Mem_Free: not allocated or double freed (free at %s:%i)", filename, fileline); + Sys_Abort("Mem_Free: not allocated or double freed (free at %s:%i)", filename, fileline); if (mem_mutex) Thread_LockMutex(mem_mutex); List_Delete(&mem->list); @@ -491,7 +491,7 @@ void _Mem_Free(void *data, const char *filename, int fileline) { //_Mem_CheckSentinelsGlobal(filename, fileline); if (!Mem_IsAllocated(NULL, data)) - Sys_Error("Mem_Free: data is not allocated (called at %s:%i)", filename, fileline); + Sys_Abort("Mem_Free: data is not allocated (called at %s:%i)", filename, fileline); } _Mem_FreeBlock((memheader_t *)((unsigned char *) data - sizeof(memheader_t)), filename, fileline); @@ -509,7 +509,7 @@ mempool_t *_Mem_AllocPool(const char *name, int flags, mempool_t *parent, const Mem_PrintStats(); Mem_PrintList(1<<30); Mem_PrintStats(); - Sys_Error("Mem_AllocPool: out of memory (allocpool at %s:%i)", filename, fileline); + Sys_Abort("Mem_AllocPool: out of memory (allocpool at %s:%i)", filename, fileline); } memset(pool, 0, sizeof(mempool_t)); pool->sentinel1 = MEMHEADER_SENTINEL_FOR_ADDRESS(&pool->sentinel1); @@ -539,11 +539,11 @@ void _Mem_FreePool(mempool_t **poolpointer, const char *filename, int fileline) // unlink pool from chain for (chainaddress = &poolchain;*chainaddress && *chainaddress != pool;chainaddress = &((*chainaddress)->next)); if (*chainaddress != pool) - Sys_Error("Mem_FreePool: pool already free (freepool at %s:%i)", filename, fileline); + Sys_Abort("Mem_FreePool: pool already free (freepool at %s:%i)", filename, fileline); if (pool->sentinel1 != MEMHEADER_SENTINEL_FOR_ADDRESS(&pool->sentinel1)) - Sys_Error("Mem_FreePool: trashed pool sentinel 1 (allocpool at %s:%i, freepool at %s:%i)", pool->filename, pool->fileline, filename, fileline); + Sys_Abort("Mem_FreePool: trashed pool sentinel 1 (allocpool at %s:%i, freepool at %s:%i)", pool->filename, pool->fileline, filename, fileline); if (pool->sentinel2 != MEMHEADER_SENTINEL_FOR_ADDRESS(&pool->sentinel2)) - Sys_Error("Mem_FreePool: trashed pool sentinel 2 (allocpool at %s:%i, freepool at %s:%i)", pool->filename, pool->fileline, filename, fileline); + Sys_Abort("Mem_FreePool: trashed pool sentinel 2 (allocpool at %s:%i, freepool at %s:%i)", pool->filename, pool->fileline, filename, fileline); *chainaddress = pool->next; // free memory owned by the pool @@ -576,14 +576,14 @@ void _Mem_EmptyPool(mempool_t *pool, const char *filename, int fileline) if (chainaddress == pool) break; if (!chainaddress) - Sys_Error("Mem_EmptyPool: pool is already free (emptypool at %s:%i)", filename, fileline); + Sys_Abort("Mem_EmptyPool: pool is already free (emptypool at %s:%i)", filename, fileline); } if (pool == NULL) - Sys_Error("Mem_EmptyPool: pool == NULL (emptypool at %s:%i)", filename, fileline); + Sys_Abort("Mem_EmptyPool: pool == NULL (emptypool at %s:%i)", filename, fileline); if (pool->sentinel1 != MEMHEADER_SENTINEL_FOR_ADDRESS(&pool->sentinel1)) - Sys_Error("Mem_EmptyPool: trashed pool sentinel 1 (allocpool at %s:%i, emptypool at %s:%i)", pool->filename, pool->fileline, filename, fileline); + Sys_Abort("Mem_EmptyPool: trashed pool sentinel 1 (allocpool at %s:%i, emptypool at %s:%i)", pool->filename, pool->fileline, filename, fileline); if (pool->sentinel2 != MEMHEADER_SENTINEL_FOR_ADDRESS(&pool->sentinel2)) - Sys_Error("Mem_EmptyPool: trashed pool sentinel 2 (allocpool at %s:%i, emptypool at %s:%i)", pool->filename, pool->fileline, filename, fileline); + Sys_Abort("Mem_EmptyPool: trashed pool sentinel 2 (allocpool at %s:%i, emptypool at %s:%i)", pool->filename, pool->fileline, filename, fileline); // free memory owned by the pool while (!List_Is_Empty(&pool->chain)) @@ -603,15 +603,15 @@ void _Mem_CheckSentinels(void *data, const char *filename, int fileline) unsigned int sentinel2; if (data == NULL) - Sys_Error("Mem_CheckSentinels: data == NULL (sentinel check at %s:%i)", filename, fileline); + Sys_Abort("Mem_CheckSentinels: data == NULL (sentinel check at %s:%i)", filename, fileline); mem = (memheader_t *)((unsigned char *) data - sizeof(memheader_t)); sentinel1 = MEMHEADER_SENTINEL_FOR_ADDRESS(&mem->sentinel); sentinel2 = MEMHEADER_SENTINEL_FOR_ADDRESS((unsigned char *) mem + sizeof(memheader_t) + mem->size); if (mem->sentinel != sentinel1) - Sys_Error("Mem_Free: trashed head sentinel (alloc at %s:%i, sentinel check at %s:%i)", mem->filename, mem->fileline, filename, fileline); + Sys_Abort("Mem_Free: trashed head sentinel (alloc at %s:%i, sentinel check at %s:%i)", mem->filename, mem->fileline, filename, fileline); if (memcmp((unsigned char *) mem + sizeof(memheader_t) + mem->size, &sentinel2, sizeof(sentinel2))) - Sys_Error("Mem_Free: trashed tail sentinel (alloc at %s:%i, sentinel check at %s:%i)", mem->filename, mem->fileline, filename, fileline); + Sys_Abort("Mem_Free: trashed tail sentinel (alloc at %s:%i, sentinel check at %s:%i)", mem->filename, mem->fileline, filename, fileline); } #if MEMCLUMPING @@ -619,9 +619,9 @@ static void _Mem_CheckClumpSentinels(memclump_t *clump, const char *filename, in { // this isn't really very useful if (clump->sentinel1 != MEMHEADER_SENTINEL_FOR_ADDRESS(&clump->sentinel1)) - Sys_Error("Mem_CheckClumpSentinels: trashed sentinel 1 (sentinel check at %s:%i)", filename, fileline); + Sys_Abort("Mem_CheckClumpSentinels: trashed sentinel 1 (sentinel check at %s:%i)", filename, fileline); if (clump->sentinel2 != MEMHEADER_SENTINEL_FOR_ADDRESS(&clump->sentinel2)) - Sys_Error("Mem_CheckClumpSentinels: trashed sentinel 2 (sentinel check at %s:%i)", filename, fileline); + Sys_Abort("Mem_CheckClumpSentinels: trashed sentinel 2 (sentinel check at %s:%i)", filename, fileline); } #endif @@ -635,9 +635,9 @@ void _Mem_CheckSentinelsGlobal(const char *filename, int fileline) for (pool = poolchain;pool;pool = pool->next) { if (pool->sentinel1 != MEMHEADER_SENTINEL_FOR_ADDRESS(&pool->sentinel1)) - Sys_Error("Mem_CheckSentinelsGlobal: trashed pool sentinel 1 (allocpool at %s:%i, sentinel check at %s:%i)", pool->filename, pool->fileline, filename, fileline); + Sys_Abort("Mem_CheckSentinelsGlobal: trashed pool sentinel 1 (allocpool at %s:%i, sentinel check at %s:%i)", pool->filename, pool->fileline, filename, fileline); if (pool->sentinel2 != MEMHEADER_SENTINEL_FOR_ADDRESS(&pool->sentinel2)) - Sys_Error("Mem_CheckSentinelsGlobal: trashed pool sentinel 2 (allocpool at %s:%i, sentinel check at %s:%i)", pool->filename, pool->fileline, filename, fileline); + Sys_Abort("Mem_CheckSentinelsGlobal: trashed pool sentinel 2 (allocpool at %s:%i, sentinel check at %s:%i)", pool->filename, pool->fileline, filename, fileline); } for (pool = poolchain;pool;pool = pool->next) List_For_Each_Entry(mem, &pool->chain, memheader_t, list) @@ -750,9 +750,9 @@ void Mem_ExpandableArray_FreeRecord(memexpandablearray_t *l, void *record) // co { j = (p - l->arrays[i].data) / l->recordsize; if (p != l->arrays[i].data + j * l->recordsize) - Sys_Error("Mem_ExpandableArray_FreeRecord: no such record %p\n", (void *)p); + Sys_Abort("Mem_ExpandableArray_FreeRecord: no such record %p\n", (void *)p); if (!l->arrays[i].allocflags[j]) - Sys_Error("Mem_ExpandableArray_FreeRecord: record %p is already free!\n", (void *)p); + Sys_Abort("Mem_ExpandableArray_FreeRecord: record %p is already free!\n", (void *)p); l->arrays[i].allocflags[j] = false; l->arrays[i].numflaggedrecords--; return; -- 2.39.2