diff --git a/inc/common/common.h b/inc/common/common.h index 50a0f0ef1..739758d37 100644 --- a/inc/common/common.h +++ b/inc/common/common.h @@ -135,7 +135,9 @@ void Com_AddConfigFile(const char *name, unsigned flags); #define Com_DDDDPrintf(...) ((void)0) #endif -extern cvar_t *z_perturb; +#if USE_TESTS +extern cvar_t *z_perturb; +#endif #if USE_DEBUG extern cvar_t *developer; diff --git a/inc/common/zone.h b/inc/common/zone.h index 31ec13f9f..c39100794 100644 --- a/inc/common/zone.h +++ b/inc/common/zone.h @@ -19,9 +19,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #ifndef ZONE_H #define ZONE_H -#define Z_Malloc(size) Z_TagMalloc(size, TAG_GENERAL) -#define Z_Mallocz(size) Z_TagMallocz(size, TAG_GENERAL) -#define Z_Reserve(size) Z_TagReserve(size, TAG_GENERAL) #define Z_CopyString(string) Z_TagCopyString(string, TAG_GENERAL) #define Z_CopyStruct(ptr) memcpy(Z_Malloc(sizeof(*ptr)), ptr, sizeof(*ptr)) @@ -47,7 +44,11 @@ typedef enum { void Z_Init(void); void Z_Free(void *ptr); +// Frees the memory block pointed at by (*ptr), if that's nonzero, and sets (*ptr) to zero. +void Z_Freep(void **ptr); void *Z_Realloc(void *ptr, size_t size); +void *Z_Malloc(size_t size) q_malloc; +void *Z_Mallocz(size_t size) q_malloc; void *Z_TagMalloc(size_t size, memtag_t tag) q_malloc; void *Z_TagMallocz(size_t size, memtag_t tag) q_malloc; char *Z_TagCopyString(const char *in, memtag_t tag) q_malloc; @@ -55,11 +56,6 @@ void Z_FreeTags(memtag_t tag); void Z_LeakTest(memtag_t tag); void Z_Stats_f(void); -void Z_TagReserve(size_t size, memtag_t tag); -void *Z_ReservedAlloc(size_t size) q_malloc; -void *Z_ReservedAllocz(size_t size) q_malloc; -char *Z_ReservedCopyString(const char *in) q_malloc; - // may return pointer to static memory char *Z_CvarCopyString(const char *in); diff --git a/inc/refresh/models.h b/inc/refresh/models.h index e88f7ee7e..10241d923 100644 --- a/inc/refresh/models.h +++ b/inc/refresh/models.h @@ -28,7 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "system/hunk.h" #include "common/error.h" -#define MOD_Malloc(size) Hunk_Alloc(&model->hunk, size) +#define MOD_Malloc(size) Hunk_TryAlloc(&model->hunk, size) #define CHECK(x) if (!(x)) { ret = Q_ERR(ENOMEM); goto fail; } diff --git a/inc/shared/list.h b/inc/shared/list.h index 2b4a13fe0..de8955051 100644 --- a/inc/shared/list.h +++ b/inc/shared/list.h @@ -44,6 +44,12 @@ static inline void List_Unlink(list_t *prev, list_t *next) next->prev = prev; } +static inline void List_Relink(list_t *elem) +{ + elem->prev->next = elem; + elem->next->prev = elem; +} + static inline void List_Init(list_t *list) { list->prev = list->next = list; diff --git a/inc/system/hunk.h b/inc/system/hunk.h index cc564bbff..58f22d0f1 100644 --- a/inc/system/hunk.h +++ b/inc/system/hunk.h @@ -28,6 +28,7 @@ typedef struct { void Hunk_Init(void); void Hunk_Begin(memhunk_t *hunk, size_t maxsize); +void *Hunk_TryAlloc(memhunk_t *hunk, size_t size); void *Hunk_Alloc(memhunk_t *hunk, size_t size); void Hunk_End(memhunk_t *hunk); void Hunk_Free(memhunk_t *hunk); diff --git a/src/client/http.c b/src/client/http.c index 60f2bbe54..cf0b94073 100644 --- a/src/client/http.c +++ b/src/client/http.c @@ -405,10 +405,7 @@ void HTTP_CleanupDownloads(void) dl->file = NULL; } - if (dl->buffer) { - Z_Free(dl->buffer); - dl->buffer = NULL; - } + Z_Freep((void**)&dl->buffer); if (dl->curl) { if (curl_multi && dl->multi_added) @@ -682,8 +679,7 @@ static void parse_file_list(dlhandle_t *dl) } } - Z_Free(dl->buffer); - dl->buffer = NULL; + Z_Freep((void**)&dl->buffer); } // A pak file just downloaded, let's see if we can remove some stuff from @@ -830,10 +826,7 @@ static bool finish_download(void) remove(dl->path); dl->path[0] = 0; } - if (dl->buffer) { - Z_Free(dl->buffer); - dl->buffer = NULL; - } + Z_Freep((void**)&dl->buffer); if (dl->multi_added) { //remove the handle and mark it as such curl_multi_remove_handle(curl_multi, curl); diff --git a/src/client/sound/ogg.c b/src/client/sound/ogg.c index 3d4465979..a13a6ac9c 100644 --- a/src/client/sound/ogg.c +++ b/src/client/sound/ogg.c @@ -379,8 +379,7 @@ void OGG_LoadTrackList(void) { tracklist_free(); - Z_Free(ogg.music_dir); - ogg.music_dir = NULL; + Z_Freep((void**)&ogg.music_dir); const char* potMusicDirs[4] = {0}; char fullMusicDir[MAX_OSPATH] = {0}; @@ -796,8 +795,7 @@ OGG_Shutdown(void) // Free file lsit. tracklist_free(); - Z_Free(ogg.music_dir); - ogg.music_dir = NULL; + Z_Freep((void**)&ogg.music_dir); // Remove console commands Cmd_RemoveCommand("ogg"); diff --git a/src/client/ui/demos.c b/src/client/ui/demos.c index efdce1148..b19f5aec6 100644 --- a/src/client/ui/demos.c +++ b/src/client/ui/demos.c @@ -366,8 +366,7 @@ static void FreeList(void) for (i = 0; i < m_demos.list.numItems; i++) { Z_Free(m_demos.list.items[i]); } - Z_Free(m_demos.list.items); - m_demos.list.items = NULL; + Z_Freep((void**)&m_demos.list.items); m_demos.list.numItems = 0; } } diff --git a/src/client/ui/servers.c b/src/client/ui/servers.c index 1b1acd763..ffdcd42b4 100644 --- a/src/client/ui/servers.c +++ b/src/client/ui/servers.c @@ -1052,10 +1052,7 @@ static bool Push(menuFrameWork_t *self) static void Pop(menuFrameWork_t *self) { ClearServers(); - if (m_servers.args) { - Z_Free(m_servers.args); - m_servers.args = NULL; - } + Z_Freep((void**)&m_servers.args); } static void Expose(menuFrameWork_t *self) diff --git a/src/common/common.c b/src/common/common.c index 6deaf333e..6cc7df68b 100644 --- a/src/common/common.c +++ b/src/common/common.c @@ -72,7 +72,9 @@ static bool com_logNewline; static char **com_argv; static int com_argc; +#if USE_TESTS cvar_t *z_perturb; +#endif #if USE_DEBUG cvar_t *developer; @@ -887,7 +889,9 @@ void Qcommon_Init(int argc, char **argv) // // init commands and vars // +#if USE_TESTS z_perturb = Cvar_Get("z_perturb", "0", 0); +#endif #if USE_CLIENT host_speeds = Cvar_Get("host_speeds", "0", 0); #endif diff --git a/src/common/cvar.c b/src/common/cvar.c index 6fbaf2107..f97c47174 100644 --- a/src/common/cvar.c +++ b/src/common/cvar.c @@ -328,10 +328,7 @@ static void set_back_cvar(cvar_t *var) { if (var->flags & CVAR_LATCH) { // set back to current value - if (var->latched_string) { - Z_Free(var->latched_string); - var->latched_string = NULL; - } + Z_Freep((void**)&var->latched_string); } } @@ -390,10 +387,7 @@ void Cvar_SetByVar(cvar_t *var, const char *value, from_t from) } // free latched string, if any - if (var->latched_string) { - Z_Free(var->latched_string); - var->latched_string = NULL; - } + Z_Freep((void**)&var->latched_string); change_string_value(var, value, from); } diff --git a/src/common/net/chan.c b/src/common/net/chan.c index bae1f1584..6d38fb933 100644 --- a/src/common/net/chan.c +++ b/src/common/net/chan.c @@ -95,6 +95,8 @@ static cvar_t *showdrop; #define SHOWDROP(...) #endif +#define SOCK_TAG(sock) ((sock) == NS_SERVER ? TAG_SERVER : TAG_GENERAL) + cvar_t *net_qport; cvar_t *net_maxmsglen; cvar_t *net_chantype; @@ -398,11 +400,7 @@ static netchan_t *NetchanOld_Setup(netsrc_t sock, const netadr_t *adr, netchan_old_t *chan; netchan_t *netchan; - Z_TagReserve(sizeof(*chan) + maxpacketlen * 2, - sock == NS_SERVER ? TAG_SERVER : TAG_GENERAL); - - chan = Z_ReservedAlloc(sizeof(*chan)); - memset(chan, 0, sizeof(*chan)); + chan = Z_TagMallocz(sizeof(*chan), SOCK_TAG(sock)); netchan = (netchan_t *)chan; netchan->sock = sock; netchan->remote_address = *adr; @@ -418,10 +416,10 @@ static netchan_t *NetchanOld_Setup(netsrc_t sock, const netadr_t *adr, netchan->TransmitNextFragment = NetchanOld_TransmitNextFragment; netchan->ShouldUpdate = NetchanOld_ShouldUpdate; - chan->message_buf = Z_ReservedAlloc(maxpacketlen); + chan->message_buf = Z_TagMalloc(maxpacketlen, SOCK_TAG(sock)); SZ_Init(&netchan->message, chan->message_buf, maxpacketlen); - chan->reliable_buf = Z_ReservedAlloc(maxpacketlen); + chan->reliable_buf = Z_TagMalloc(maxpacketlen, SOCK_TAG(sock)); return netchan; } @@ -800,8 +798,7 @@ static netchan_t *NetchanNew_Setup(netsrc_t sock, const netadr_t *adr, netchan_new_t *chan; netchan_t *netchan; - chan = Z_TagMallocz(sizeof(*chan), - sock == NS_SERVER ? TAG_SERVER : TAG_GENERAL); + chan = Z_TagMallocz(sizeof(*chan), SOCK_TAG(sock)); netchan = (netchan_t *)chan; netchan->sock = sock; netchan->remote_address = *adr; @@ -865,6 +862,12 @@ Netchan_Close */ void Netchan_Close(netchan_t *netchan) { + if (netchan->type == NETCHAN_OLD) { + netchan_old_t *chan = (netchan_old_t *)netchan; + + Z_Free(chan->message_buf); + Z_Free(chan->reliable_buf); + } Z_Free(netchan); } diff --git a/src/common/prompt.c b/src/common/prompt.c index 5b7d57c3b..a159330f6 100644 --- a/src/common/prompt.c +++ b/src/common/prompt.c @@ -415,10 +415,7 @@ void Prompt_CompleteHistory(commandPrompt_t *prompt, bool forward) void Prompt_ClearState(commandPrompt_t *prompt) { prompt->tooMany = false; - if (prompt->search) { - Z_Free(prompt->search); - prompt->search = NULL; - } + Z_Freep((void**)&prompt->search); } /* @@ -522,10 +519,7 @@ void Prompt_Clear(commandPrompt_t *prompt) Prompt_ClearState(prompt); for (i = 0; i < HISTORY_SIZE; i++) { - if (prompt->history[i]) { - Z_Free(prompt->history[i]); - prompt->history[i] = NULL; - } + Z_Freep((void**)&prompt->history[i]); } prompt->historyLineNum = 0; diff --git a/src/common/zone.c b/src/common/zone.c index 5c2274d53..46a29b32d 100644 --- a/src/common/zone.c +++ b/src/common/zone.c @@ -17,23 +17,17 @@ with this program; if not, write to the Free Software Foundation, Inc., */ #include "shared/shared.h" +#include "shared/list.h" #include "common/common.h" #include "common/zone.h" #define Z_MAGIC 0x1d0d -#define Z_FOR_EACH(z) \ - for ((z) = z_chain.next; (z) != &z_chain; (z) = (z)->next) - -#define Z_FOR_EACH_SAFE(z, n) \ - for ((z) = z_chain.next; (n) = (z)->next, (z) != &z_chain; (z) = (n)) - -typedef struct zhead_s { +typedef struct { uint16_t magic; uint16_t tag; // for group free size_t size; - struct zhead_s *prev; - struct zhead_s *next; + list_t entry; } zhead_t; typedef struct { @@ -46,11 +40,19 @@ typedef struct { size_t bytes; } zstats_t; -static zhead_t z_chain; -static zstatic_t z_static[11]; +static list_t z_chain; static zstats_t z_stats[TAG_MAX]; -static const char z_tagnames[TAG_MAX][8] = { +#define S(d) \ + { .z = { .magic = Z_MAGIC, .tag = TAG_STATIC, .size = sizeof(zstatic_t) }, .data = d } + +static const zstatic_t z_static[11] = { + S("0"), S("1"), S("2"), S("3"), S("4"), S("5"), S("6"), S("7"), S("8"), S("9"), S("") +}; + +#undef S + +static const char *const z_tagnames[TAG_MAX] = { "game", "static", "generic", @@ -65,32 +67,33 @@ static const char z_tagnames[TAG_MAX][8] = { "cmodel" }; -static inline void Z_CountFree(zhead_t *z) +#define TAG_INDEX(tag) ((tag) < TAG_MAX ? (tag) : TAG_FREE) + +static inline void Z_CountFree(const zhead_t *z) { - zstats_t *s = &z_stats[z->tag < TAG_MAX ? z->tag : TAG_FREE]; + zstats_t *s = &z_stats[TAG_INDEX(z->tag)]; s->count--; s->bytes -= z->size; } -static inline void Z_CountAlloc(zhead_t *z) +static inline void Z_CountAlloc(const zhead_t *z) { - zstats_t *s = &z_stats[z->tag < TAG_MAX ? z->tag : TAG_FREE]; + zstats_t *s = &z_stats[TAG_INDEX(z->tag)]; s->count++; s->bytes += z->size; } #define Z_Validate(z) \ - Q_assert(z->magic == Z_MAGIC); \ - Q_assert(z->tag != TAG_FREE); + Q_assert((z)->magic == Z_MAGIC && (z)->tag != TAG_FREE) void Z_LeakTest(memtag_t tag) { zhead_t *z; size_t numLeaks = 0, numBytes = 0; - Z_FOR_EACH(z) { + LIST_FOR_EACH(zhead_t, z, &z_chain, entry) { Z_Validate(z); - if (z->tag == tag) { + if (z->tag == tag || (tag == TAG_FREE && z->tag >= TAG_MAX)) { numLeaks++; numBytes += z->size; } @@ -100,7 +103,7 @@ void Z_LeakTest(memtag_t tag) Com_WPrintf("************* Z_LeakTest *************\n" "%s leaked %zu bytes of memory (%zu object%s)\n" "**************************************\n", - z_tagnames[tag < TAG_MAX ? tag : TAG_FREE], + z_tagnames[TAG_INDEX(tag)], numBytes, numLeaks, numLeaks == 1 ? "" : "s"); } } @@ -125,14 +128,27 @@ void Z_Free(void *ptr) Z_CountFree(z); if (z->tag != TAG_STATIC) { - z->prev->next = z->next; - z->next->prev = z->prev; + List_Remove(&z->entry); z->magic = 0xdead; z->tag = TAG_FREE; free(z); } } +/* +======================== +Z_Freep +======================== +*/ +void Z_Freep(void **ptr) +{ + Q_assert(ptr); + if (*ptr) { + Z_Free(*ptr); + *ptr = NULL; + } +} + /* ======================== Z_Realloc @@ -172,8 +188,7 @@ void *Z_Realloc(void *ptr, size_t size) } z->size = size; - z->prev->next = z; - z->next->prev = z; + List_Relink(&z->entry); Z_CountAlloc(z); @@ -217,7 +232,7 @@ void Z_FreeTags(memtag_t tag) { zhead_t *z, *n; - Z_FOR_EACH_SAFE(z, n) { + LIST_FOR_EACH_SAFE(zhead_t, z, n, &z_chain, entry) { Z_Validate(z); if (z->tag == tag) { Z_Free(z + 1); @@ -230,7 +245,7 @@ void Z_FreeTags(memtag_t tag) Z_TagMalloc ======================== */ -void *Z_TagMalloc(size_t size, memtag_t tag) +static void *Z_TagMallocInternal(size_t size, memtag_t tag, bool init) { zhead_t *z; @@ -239,10 +254,10 @@ void *Z_TagMalloc(size_t size, memtag_t tag) } Q_assert(size <= INT_MAX); - Q_assert(tag != TAG_FREE); + Q_assert(tag > TAG_FREE && tag <= UINT16_MAX); size += sizeof(*z); - z = malloc(size); + z = init ? calloc(1, size) : malloc(size); if (!z) { Com_Error(ERR_FATAL, "%s: couldn't allocate %zu bytes", __func__, size); } @@ -250,75 +265,37 @@ void *Z_TagMalloc(size_t size, memtag_t tag) z->tag = tag; z->size = size; - z->next = z_chain.next; - z->prev = &z_chain; - z_chain.next->prev = z; - z_chain.next = z; + List_Insert(&z_chain, &z->entry); - if (z_perturb && z_perturb->integer) { +#if USE_TESTS + if (!init && z_perturb && z_perturb->integer) { memset(z + 1, z_perturb->integer, size - sizeof(*z)); } +#endif Z_CountAlloc(z); return z + 1; } -void *Z_TagMallocz(size_t size, memtag_t tag) -{ - if (!size) { - return NULL; - } - return memset(Z_TagMalloc(size, tag), 0, size); -} - -static byte *z_reserved_data; -static size_t z_reserved_inuse; -static size_t z_reserved_total; - -void Z_TagReserve(size_t size, memtag_t tag) +void *Z_TagMalloc(size_t size, memtag_t tag) { - z_reserved_data = Z_TagMalloc(size, tag); - z_reserved_total = size; - z_reserved_inuse = 0; + return Z_TagMallocInternal(size, tag, false); } -void *Z_ReservedAlloc(size_t size) +void *Z_TagMallocz(size_t size, memtag_t tag) { - void *ptr; - - if (!size) { - return NULL; - } - - if (size > z_reserved_total - z_reserved_inuse) { - Com_Error(ERR_FATAL, "%s: couldn't allocate %zu bytes", __func__, size); - } - - ptr = z_reserved_data + z_reserved_inuse; - z_reserved_inuse += size; - - return ptr; + return Z_TagMallocInternal(size, tag, true); } -void *Z_ReservedAllocz(size_t size) +void *Z_Malloc(size_t size) { - if (!size) { - return NULL; - } - return memset(Z_ReservedAlloc(size), 0, size); + return Z_TagMalloc(size, TAG_GENERAL); } -char *Z_ReservedCopyString(const char *in) +void *Z_Mallocz(size_t size) { - size_t len; - - if (!in) { - return NULL; - } - - len = strlen(in) + 1; - return memcpy(Z_ReservedAlloc(len), in, len); + return Z_TagMallocz(size, TAG_GENERAL); } /* @@ -328,18 +305,7 @@ Z_Init */ void Z_Init(void) { - zstatic_t *z; - int i; - - z_chain.next = z_chain.prev = &z_chain; - - for (i = 0, z = z_static; i < 11; i++, z++) { - z->z.magic = Z_MAGIC; - z->z.tag = TAG_STATIC; - z->z.size = sizeof(*z); - if (i < 10) - z->data[0] = '0' + i; - } + List_Init(&z_chain); } /* @@ -366,7 +332,7 @@ Z_CvarCopyString */ char *Z_CvarCopyString(const char *in) { - zstatic_t *z; + const zstatic_t *z; int i; if (!in) { @@ -384,5 +350,5 @@ char *Z_CvarCopyString(const char *in) // return static storage z = &z_static[i]; Z_CountAlloc(&z->z); - return z->data; + return (char *)z->data; } diff --git a/src/refresh/vkpt/main.c b/src/refresh/vkpt/main.c index 827bb988c..9beca92d4 100644 --- a/src/refresh/vkpt/main.c +++ b/src/refresh/vkpt/main.c @@ -4265,12 +4265,10 @@ void vkpt_free_command_buffers(cmd_buf_group_t* group) vkFreeCommandBuffers(qvk.device, group->command_pool, group->count_per_frame * MAX_FRAMES_IN_FLIGHT, group->buffers); - Z_Free(group->buffers); - group->buffers = NULL; + Z_Freep((void**)&group->buffers); #ifdef USE_DEBUG - Z_Free(group->buffer_begin_addrs); - group->buffer_begin_addrs = NULL; + Z_Freep((void**)&group->buffer_begin_addrs); #endif group->count_per_frame = 0; diff --git a/src/refresh/vkpt/transparency.c b/src/refresh/vkpt/transparency.c index 129683fdc..9d73ad1da 100644 --- a/src/refresh/vkpt/transparency.c +++ b/src/refresh/vkpt/transparency.c @@ -158,8 +158,7 @@ void destroy_transparency() if (transparency.host_buffer_shadow) { - Z_Free(transparency.host_buffer_shadow); - transparency.host_buffer_shadow = NULL; + Z_Freep((void**)&transparency.host_buffer_shadow); } } diff --git a/src/refresh/vkpt/vertex_buffer.c b/src/refresh/vkpt/vertex_buffer.c index f55353dc0..5b5e309ee 100644 --- a/src/refresh/vkpt/vertex_buffer.c +++ b/src/refresh/vkpt/vertex_buffer.c @@ -74,8 +74,7 @@ void vkpt_destroy_model_geometry(model_geometry_t* info) if (!info->geometry_storage) return; - Z_Free(info->geometry_storage); - info->geometry_storage = NULL; + Z_Freep((void**)&info->geometry_storage); info->geometries = NULL; info->build_ranges = NULL; info->prim_counts = NULL; @@ -1485,10 +1484,8 @@ vkpt_vertex_buffer_destroy() buffer_destroy(&qvk.buf_tonemap); buffer_destroy(&qvk.buf_sun_color); - Z_Free(qvk.iqm_matrices_shadow); - Z_Free(qvk.iqm_matrices_prev); - qvk.iqm_matrices_shadow = NULL; - qvk.iqm_matrices_prev = NULL; + Z_Freep((void**)&qvk.iqm_matrices_shadow); + Z_Freep((void**)&qvk.iqm_matrices_prev); return VK_SUCCESS; } diff --git a/src/server/ac.c b/src/server/ac.c index 8962d2791..3f10f66f7 100644 --- a/src/server/ac.c +++ b/src/server/ac.c @@ -288,7 +288,6 @@ static void AC_ParseHash(char *data, int linenum, const char *path) static void AC_ParseCvar(char *data, int linenum, const char *path) { char *values[256], *p; - byte lengths[256]; char *name, *opstr, *val, *def; size_t len, namelen, vallen, deflen; ac_cvar_t *cvar; @@ -350,26 +349,20 @@ static void AC_ParseCvar(char *data, int linenum, const char *path) Com_WPrintf("ANTICHEAT: Too long value on line %d in %s\n", linenum, path); return; } - values[num_values] = val; - lengths[num_values++] = (byte)(len + 1); + values[num_values++] = val; if (!p) { break; } val = p + 1; } - Z_TagReserve(sizeof(*cvar) + num_values * sizeof(char *) + - namelen + 1 + deflen + 1 + vallen + 1, TAG_SERVER); - cvar = Z_ReservedAlloc(sizeof(*cvar)); - cvar->values = Z_ReservedAlloc(num_values * sizeof(char *)); - cvar->name = Z_ReservedAlloc(namelen + 1); - memcpy(cvar->name, name, namelen + 1); - cvar->def = Z_ReservedAlloc(deflen + 1); - memcpy(cvar->def, def, deflen + 1); + cvar = SV_Malloc(sizeof(*cvar)); + cvar->values = SV_Malloc(num_values * sizeof(char *)); + cvar->name = SV_CopyString(name); + cvar->def = SV_CopyString(def); cvar->num_values = num_values; for (i = 0; i < num_values; i++) { - cvar->values[i] = Z_ReservedAlloc(lengths[i]); - memcpy(cvar->values[i], values[i], lengths[i]); + cvar->values[i] = SV_CopyString(values[i]); } cvar->op = op->code; cvar->next = acs.cvars; @@ -377,6 +370,16 @@ static void AC_ParseCvar(char *data, int linenum, const char *path) acs.num_cvars++; } +static void AC_FreeCvar(ac_cvar_t *cvar) +{ + for (int i = 0; i < cvar->num_values; i++) + Z_Free(cvar->values[i]); + Z_Free(cvar->values); + Z_Free(cvar->def); + Z_Free(cvar->name); + Z_Free(cvar); +} + static void AC_ParseToken(char *data, int linenum, const char *path) { string_entry_t *tok; @@ -487,7 +490,7 @@ static void AC_FreeChecks(void) for (c = acs.cvars; c; c = cn) { cn = c->next; - Z_Free(c); + AC_FreeCvar(c); } acs.cvars = NULL; diff --git a/src/server/game.c b/src/server/game.c index 1f8472e27..9b1ff1786 100644 --- a/src/server/game.c +++ b/src/server/game.c @@ -699,16 +699,13 @@ static qboolean PF_AreasConnected(int area1, int area2) static void *PF_TagMalloc(unsigned size, unsigned tag) { - Q_assert(tag + TAG_MAX > tag); - if (!size) { - return NULL; - } - return memset(Z_TagMalloc(size, tag + TAG_MAX), 0, size); + Q_assert(tag <= UINT16_MAX - TAG_MAX); + return Z_TagMallocz(size, tag + TAG_MAX); } static void PF_FreeTags(unsigned tag) { - Q_assert(tag + TAG_MAX > tag); + Q_assert(tag <= UINT16_MAX - TAG_MAX); Z_FreeTags(tag + TAG_MAX); } @@ -739,6 +736,8 @@ void SV_ShutdownGameProgs(void) game_library = NULL; } Cvar_Set("g_features", "0"); + + Z_LeakTest(TAG_FREE); } static void *_SV_LoadGameLibrary(const char *path) diff --git a/src/server/main.c b/src/server/main.c index fb0a406dd..88a9eb0e0 100644 --- a/src/server/main.c +++ b/src/server/main.c @@ -160,17 +160,11 @@ void SV_CleanClient(client_t *client) // close any existing donwload SV_CloseDownload(client); - if (client->version_string) { - Z_Free(client->version_string); - client->version_string = NULL; - } + Z_Freep((void**)&client->version_string); // free baselines allocated for this client for (i = 0; i < SV_BASELINES_CHUNKS; i++) { - if (client->baselines[i]) { - Z_Free(client->baselines[i]); - client->baselines[i] = NULL; - } + Z_Freep((void**)&client->baselines[i]); } } diff --git a/src/server/mvd.c b/src/server/mvd.c index 7218ef517..794f5fc12 100644 --- a/src/server/mvd.c +++ b/src/server/mvd.c @@ -1293,10 +1293,7 @@ static void remove_client(gtv_client_t *client) { NET_CloseStream(&client->stream); List_Remove(&client->entry); - if (client->data) { - Z_Free(client->data); - client->data = NULL; - } + Z_Freep((void**)&client->data); client->state = cs_free; } @@ -2059,12 +2056,10 @@ void SV_MvdInit(void) } // allocate buffers - Z_TagReserve(sizeof(player_packed_t) * sv_maxclients->integer + - sizeof(entity_packed_t) * MAX_EDICTS + MAX_MSGLEN * 2, TAG_SERVER); - SZ_Init(&mvd.message, Z_ReservedAlloc(MAX_MSGLEN), MAX_MSGLEN); - SZ_Init(&mvd.datagram, Z_ReservedAlloc(MAX_MSGLEN), MAX_MSGLEN); - mvd.players = Z_ReservedAlloc(sizeof(player_packed_t) * sv_maxclients->integer); - mvd.entities = Z_ReservedAlloc(sizeof(entity_packed_t) * MAX_EDICTS); + SZ_Init(&mvd.message, SV_Malloc(MAX_MSGLEN), MAX_MSGLEN); + SZ_Init(&mvd.datagram, SV_Malloc(MAX_MSGLEN), MAX_MSGLEN); + mvd.players = SV_Malloc(sizeof(player_packed_t) * sv_maxclients->integer); + mvd.entities = SV_Malloc(sizeof(entity_packed_t) * MAX_EDICTS); // reserve the slot for dummy MVD client if (!sv_reserved_slots->integer) { @@ -2120,6 +2115,9 @@ void SV_MvdShutdown(error_type_t type) // free static data Z_Free(mvd.message.data); + Z_Free(mvd.datagram.data); + Z_Free(mvd.players); + Z_Free(mvd.entities); Z_Free(mvd.clients); // close server TCP socket diff --git a/src/server/mvd/client.c b/src/server/mvd/client.c index 9be4130bf..76105b09d 100644 --- a/src/server/mvd/client.c +++ b/src/server/mvd/client.c @@ -132,8 +132,7 @@ void MVD_StopRecord(mvd_t *mvd) FS_CloseFile(mvd->demorecording); mvd->demorecording = 0; - Z_Free(mvd->demoname); - mvd->demoname = NULL; + Z_Freep((void**)&mvd->demoname); } static void MVD_Free(mvd_t *mvd) @@ -2514,8 +2513,8 @@ void MVD_Shutdown(void) List_Init(&mvd_gtv_list); List_Init(&mvd_channel_list); - Z_Free(mvd_clients); - mvd_clients = NULL; + Z_Freep((void**)&mvd_clients); + Z_Freep((void**)&mvd_ge.edicts); mvd_chanid = 0; diff --git a/src/server/mvd/game.c b/src/server/mvd/game.c index 3bfa5fb19..72ebdb458 100644 --- a/src/server/mvd/game.c +++ b/src/server/mvd/game.c @@ -1726,13 +1726,8 @@ static void MVD_GameInit(void) mvd_chase_prefix = Cvar_Get("mvd_chase_prefix", "xv 0 yb -64", 0); Cvar_Set("g_features", va("%d", MVD_FEATURES)); - Z_TagReserve((sizeof(edict_t) + - sizeof(mvd_client_t)) * sv_maxclients->integer + - sizeof(edict_t), TAG_MVD); - mvd_clients = Z_ReservedAllocz(sizeof(mvd_client_t) * - sv_maxclients->integer); - edicts = Z_ReservedAllocz(sizeof(edict_t) * - (sv_maxclients->integer + 1)); + mvd_clients = MVD_Mallocz(sizeof(mvd_client_t) * sv_maxclients->integer); + edicts = MVD_Mallocz(sizeof(edict_t) * (sv_maxclients->integer + 1)); for (i = 0; i < sv_maxclients->integer; i++) { mvd_clients[i].cl = &svs.client_pool[i]; diff --git a/src/server/send.c b/src/server/send.c index f03517153..4860d263e 100644 --- a/src/server/send.c +++ b/src/server/send.c @@ -1062,9 +1062,7 @@ void SV_ShutdownClientSend(client_t *client) { free_all_messages(client); - Z_Free(client->msg_pool); - client->msg_pool = NULL; - + Z_Freep((void**)&client->msg_pool); List_Init(&client->msg_free_list); } diff --git a/src/server/user.c b/src/server/user.c index 5120ee0d9..04ed8861d 100644 --- a/src/server/user.c +++ b/src/server/user.c @@ -453,14 +453,8 @@ void SV_Begin_f(void) void SV_CloseDownload(client_t *client) { - if (client->download) { - Z_Free(client->download); - client->download = NULL; - } - if (client->downloadname) { - Z_Free(client->downloadname); - client->downloadname = NULL; - } + Z_Freep((void**)&client->download); + Z_Freep((void**)&client->downloadname); client->downloadsize = 0; client->downloadcount = 0; client->downloadcmd = 0; diff --git a/src/unix/hunk.c b/src/unix/hunk.c index ccea2cd8a..c3d131cae 100644 --- a/src/unix/hunk.c +++ b/src/unix/hunk.c @@ -48,7 +48,7 @@ void Hunk_Begin(memhunk_t *hunk, size_t maxsize) hunk->mapped = hunk->maxsize; } -void *Hunk_Alloc(memhunk_t *hunk, size_t size) +void *Hunk_TryAlloc(memhunk_t *hunk, size_t size) { void *buf; @@ -65,6 +65,14 @@ void *Hunk_Alloc(memhunk_t *hunk, size_t size) return buf; } +void *Hunk_Alloc(memhunk_t *hunk, size_t size) +{ + void *buf = Hunk_TryAlloc(hunk, size); + if (!buf) + Com_Error(ERR_FATAL, "%s: couldn't allocate %zu bytes", __func__, size); + return buf; +} + void Hunk_End(memhunk_t *hunk) { size_t newsize; diff --git a/src/unix/sound/sdl.c b/src/unix/sound/sdl.c index a864133c6..25cf24a07 100644 --- a/src/unix/sound/sdl.c +++ b/src/unix/sound/sdl.c @@ -49,10 +49,7 @@ static void Shutdown(void) SDL_CloseAudio(); SDL_QuitSubSystem(SDL_INIT_AUDIO); - if (dma.buffer) { - Z_Free(dma.buffer); - dma.buffer = NULL; - } + Z_Freep((void**)&dma.buffer); } static sndinitstat_t Init(void) diff --git a/src/windows/hunk.c b/src/windows/hunk.c index 5892ff458..29a913a7a 100644 --- a/src/windows/hunk.c +++ b/src/windows/hunk.c @@ -45,7 +45,7 @@ void Hunk_Begin(memhunk_t *hunk, size_t maxsize) hunk->maxsize, GetLastError()); } -void *Hunk_Alloc(memhunk_t *hunk, size_t size) +void *Hunk_TryAlloc(memhunk_t *hunk, size_t size) { void *buf; @@ -69,6 +69,14 @@ void *Hunk_Alloc(memhunk_t *hunk, size_t size) return (byte *)hunk->base + hunk->cursize - size; } +void *Hunk_Alloc(memhunk_t *hunk, size_t size) +{ + void *buf = Hunk_TryAlloc(hunk, size); + if (!buf) + Com_Error(ERR_FATAL, "%s: couldn't allocate %zu bytes", __func__, size); + return buf; +} + void Hunk_End(memhunk_t *hunk) { Q_assert(hunk->cursize <= hunk->maxsize);