diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 72df81e98..766bdbc08 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -717,6 +717,7 @@ set (PCH_SOURCES core/utility/i_module.cpp core/utility/i_time.cpp core/utility/name.cpp + core/utility/m_alloc.cpp core/utility/cmdlib.cpp core/utility/m_argv.cpp core/utility/files.cpp diff --git a/source/build/include/compat.h b/source/build/include/compat.h index 137d15a87..1589cf78a 100644 --- a/source/build/include/compat.h +++ b/source/build/include/compat.h @@ -8,6 +8,7 @@ #pragma once #include "xs_Float.h" +#include "m_alloc.h" ////////// Compiler detection ////////// @@ -986,7 +987,11 @@ static inline void append_ext_UNSAFE(char *outbuf, const char *ext) ////////// String manipulation ////////// -char *Bstrtolower(char *str); +inline char* Bstrtolower(char* str) +{ + if (str) for (int i = 0; str[i]; i++) str[i] = tolower(str[i]); + return str; +} ////////// Miscellaneous ////////// @@ -1002,102 +1007,16 @@ extern void xalloc_set_location(int32_t line, const char *file, const char *func void set_memerr_handler(void (*handlerfunc)(int32_t, const char *, const char *)); void *handle_memerr(void *); -static FORCE_INLINE char *xstrdup(const char *s) -{ - char *ptr = strdup(s); - return (EDUKE32_PREDICT_TRUE(ptr != NULL)) ? ptr : (char *)handle_memerr(ptr); -} -static FORCE_INLINE void *xmalloc(const bsize_t size) -{ - void *ptr = Bmalloc(size); - return (EDUKE32_PREDICT_TRUE(ptr != NULL)) ? ptr : handle_memerr(ptr); -} - -static FORCE_INLINE void *xcalloc(const bsize_t nmemb, const bsize_t size) -{ - void *ptr = Bcalloc(nmemb, size); - return (EDUKE32_PREDICT_TRUE(ptr != NULL)) ? ptr : handle_memerr(ptr); -} - -static FORCE_INLINE void *xrealloc(void * const ptr, const bsize_t size) -{ - void *newptr = Brealloc(ptr, size); - - // According to the C Standard, - // - ptr == NULL makes realloc() behave like malloc() - // - size == 0 make it behave like free() if ptr != NULL - // Since we want to catch an out-of-mem in the first case, this leaves: - return (EDUKE32_PREDICT_TRUE(newptr != NULL || size == 0)) ? newptr: handle_memerr(ptr); -} - - -static FORCE_INLINE void xfree(void *const ptr) { free(ptr); } - -static FORCE_INLINE void xaligned_free(void *const ptr) { Baligned_free(ptr); } - -#if !defined NO_ALIGNED_MALLOC -static FORCE_INLINE void *xaligned_alloc(const bsize_t alignment, const bsize_t size) -{ - void *ptr = Baligned_alloc(alignment, size); - return (EDUKE32_PREDICT_TRUE(ptr != NULL)) ? ptr : handle_memerr(ptr); -} - -static FORCE_INLINE void *xaligned_calloc(const bsize_t alignment, const bsize_t count, const bsize_t size) -{ - bsize_t const blocksize = count * size; - void *ptr = Baligned_alloc(alignment, blocksize); - if (EDUKE32_PREDICT_TRUE(ptr != NULL)) - { - Bmemset(ptr, 0, blocksize); - return ptr; - } - return handle_memerr(ptr); -} -#else -# define xaligned_alloc(alignment, size) xmalloc(size) -# define xaligned_calloc(alignment, count, size) xcalloc(count, size) -#endif - -#ifdef DEBUGGINGAIDS -# define EDUKE32_PRE_XALLOC xalloc_set_location(__LINE__, __FILE__, EDUKE32_FUNCTION), -#else -# define EDUKE32_PRE_XALLOC -#endif - -#ifndef _DEBUG -#define Xstrdup(s) (EDUKE32_PRE_XALLOC xstrdup(s)) -#define Xmalloc(size) (EDUKE32_PRE_XALLOC xmalloc(size)) -#define Xcalloc(nmemb, size) (EDUKE32_PRE_XALLOC xcalloc(nmemb, size)) -#define Xrealloc(ptr, size) (EDUKE32_PRE_XALLOC xrealloc(ptr, size)) -#define Xaligned_alloc(alignment, size) (EDUKE32_PRE_XALLOC xaligned_alloc(alignment, size)) -#define Xaligned_calloc(alignment, count, size) (EDUKE32_PRE_XALLOC xaligned_calloc(alignment, count, size)) -#define Xfree(ptr) (EDUKE32_PRE_XALLOC xfree(ptr)) -#define Xaligned_free(ptr) (EDUKE32_PRE_XALLOC xaligned_free(ptr)) -#else // This is for allowing the compiler's heap checker to do its job. When wrapped it only points to the wrapper for a memory leak, not to the real location where the allocation takes place. #define Xstrdup(s) (strdup(s)) -#define Xmalloc(size) (malloc(size)) -#define Xcalloc(nmemb, size) (calloc(nmemb, size)) -#define Xrealloc(ptr, size) (realloc(ptr, size)) -#define Xaligned_alloc(alignment, size) (malloc(size)) -#define Xaligned_calloc(alignment, count, size) (calloc(count, size)) -#define Xfree(ptr) (free(ptr)) -#define Xaligned_free(ptr) (free(ptr)) -#endif - - -////////// More utility functions ////////// - -static inline void maybe_grow_buffer(char ** const buffer, int32_t * const buffersize, int32_t const newsize) -{ - if (newsize > *buffersize) - { - *buffer = (char *)Xrealloc(*buffer, newsize); - *buffersize = newsize; - } -} - +#define Xmalloc(size) (M_Malloc(size)) +#define Xcalloc(nmemb, size) (M_Calloc(nmemb, size)) +#define Xrealloc(ptr, size) (M_Realloc(ptr, size)) +#define Xaligned_alloc(alignment, size) (M_Malloc(size)) +#define Xaligned_calloc(alignment, count, size) (M_Calloc(count, size)) +#define Xfree(ptr) (M_Free(ptr)) +#define Xaligned_free(ptr) (M_Free(ptr)) ////////// Inlined external libraries ////////// diff --git a/source/build/src/compat.cpp b/source/build/src/compat.cpp index 20a361393..9d125589c 100644 --- a/source/build/src/compat.cpp +++ b/source/build/src/compat.cpp @@ -9,52 +9,4 @@ #include "baselayer.h" -////////// PANICKING ALLOCATION FUNCTIONS ////////// -static void (*g_MemErrHandler)(int32_t line, const char *file, const char *func); - -#ifdef DEBUGGINGAIDS -static const char *g_MemErrFunc = "???"; -static const char *g_MemErrFile = "???"; -static int32_t g_MemErrLine; - -void xalloc_set_location(int32_t line, const char *file, const char *func) -{ - g_MemErrLine = line; - g_MemErrFile = file; - - if (func) - g_MemErrFunc = func; -} -#endif - -void *handle_memerr(void *p) -{ - UNREFERENCED_PARAMETER(p); - debug_break(); - - if (g_MemErrHandler) - { -#ifdef DEBUGGINGAIDS - g_MemErrHandler(g_MemErrLine, g_MemErrFile, g_MemErrFunc); -#else - g_MemErrHandler(0, "???", "???"); -#endif - } - - Bexit(EXIT_FAILURE); - EDUKE32_UNREACHABLE_SECTION(return &handle_memerr); -} - -void set_memerr_handler(void(*handlerfunc)(int32_t, const char *, const char *)) -{ - g_MemErrHandler = handlerfunc; -} - - - -char *Bstrtolower(char *str) -{ - if (str) for (int i = 0; str[i]; i++) str[i] = tolower(str[i]); - return str; -} diff --git a/source/core/gamecontrol.cpp b/source/core/gamecontrol.cpp index 1057fc90e..3a3826c1f 100644 --- a/source/core/gamecontrol.cpp +++ b/source/core/gamecontrol.cpp @@ -362,8 +362,6 @@ int RunGame(); int GameMain() { - set_memerr_handler(G_HandleMemErr); - int r; try { @@ -707,11 +705,6 @@ int RunGame() return gi->app_main(); } -void G_HandleMemErr(int32_t lineNum, const char* fileName, const char* funcName) -{ - I_FatalError("Out of memory in %s:%d (%s)\n", fileName, lineNum, funcName); -} - void G_FatalEngineError(void) { I_FatalError("There was a problem initializing the engine: %s\n\nThe application will now close.", engineerrstr); diff --git a/source/core/gamecontrol.h b/source/core/gamecontrol.h index 289c720e7..402d83a6d 100644 --- a/source/core/gamecontrol.h +++ b/source/core/gamecontrol.h @@ -158,7 +158,6 @@ const char* G_ConFile(void); TArray GrpScan(); void S_SetSoundPaused(int state); -void G_HandleMemErr(int32_t lineNum, const char* fileName, const char* funcName); void G_FatalEngineError(void); int CalcSmoothRatio(const ClockTicks& totalclk, const ClockTicks& ototalclk, int realgameticspersec); diff --git a/source/core/utility/m_alloc.cpp b/source/core/utility/m_alloc.cpp new file mode 100644 index 000000000..755e7b1b5 --- /dev/null +++ b/source/core/utility/m_alloc.cpp @@ -0,0 +1,188 @@ +/* +** m_alloc.cpp +** Wrappers for the malloc family of functions that count used bytes. +** +**--------------------------------------------------------------------------- +** Copyright 1998-2008 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#if defined(__FreeBSD__) +#include +#include +#elif defined(__APPLE__) +#include +#include +#elif defined(__OpenBSD__) +#include +#else +#include +#endif + +#include "printf.h" +#include "m_alloc.h" + +#ifndef _MSC_VER +#define _NORMAL_BLOCK 0 +#define _malloc_dbg(s,b,f,l) malloc(s) +#define _realloc_dbg(p,s,b,f,l) realloc(p,s) +#endif + +#ifndef _DEBUG +#if !defined(__solaris__) && !defined(__OpenBSD__) +void *M_Malloc(size_t size) +{ + void *block = malloc(size); + + if (block == NULL) + I_FatalError("Could not malloc %zu bytes", size); + + return block; +} + +void *M_Realloc(void *memblock, size_t size) +{ + void *block = realloc(memblock, size); + if (block == NULL) + { + I_FatalError("Could not realloc %zu bytes", size); + } + return block; +} +#else +void *M_Malloc(size_t size) +{ + void *block = malloc(size+sizeof(size_t)); + + if (block == NULL) + I_FatalError("Could not malloc %zu bytes", size); + + size_t *sizeStore = (size_t *) block; + *sizeStore = size; + block = sizeStore+1; + + return block; +} + +void *M_Realloc(void *memblock, size_t size) +{ + if(memblock == NULL) + return M_Malloc(size); + + void *block = realloc(((size_t*) memblock)-1, size+sizeof(size_t)); + if (block == NULL) + { + I_FatalError("Could not realloc %zu bytes", size); + } + + size_t *sizeStore = (size_t *) block; + *sizeStore = size; + block = sizeStore+1; + + return block; +} +#endif +#else +#ifdef _MSC_VER +#include +#endif + +#if !defined(__solaris__) && !defined(__OpenBSD__) +void *M_Malloc_Dbg(size_t size, const char *file, int lineno) +{ + void *block = _malloc_dbg(size, _NORMAL_BLOCK, file, lineno); + + if (block == NULL) + I_FatalError("Could not malloc %zu bytes in %s, line %d", size, file, lineno); + + return block; +} + +void *M_Realloc_Dbg(void *memblock, size_t size, const char *file, int lineno) +{ + void *block = _realloc_dbg(memblock, size, _NORMAL_BLOCK, file, lineno); + if (block == NULL) + { + I_FatalError("Could not realloc %zu bytes in %s, line %d", size, file, lineno); + } + return block; +} +#else +void *M_Malloc_Dbg(size_t size, const char *file, int lineno) +{ + void *block = _malloc_dbg(size+sizeof(size_t), _NORMAL_BLOCK, file, lineno); + + if (block == NULL) + I_FatalError("Could not malloc %zu bytes in %s, line %d", size, file, lineno); + + size_t *sizeStore = (size_t *) block; + *sizeStore = size; + block = sizeStore+1; + + return block; +} + +void *M_Realloc_Dbg(void *memblock, size_t size, const char *file, int lineno) +{ + if(memblock == NULL) + return M_Malloc_Dbg(size, file, lineno); + + void *block = _realloc_dbg(((size_t*) memblock)-1, size+sizeof(size_t), _NORMAL_BLOCK, file, lineno); + + if (block == NULL) + { + I_FatalError("Could not realloc %zu bytes in %s, line %d", size, file, lineno); + } + + size_t *sizeStore = (size_t *) block; + *sizeStore = size; + block = sizeStore+1; + + return block; +} +#endif +#endif + +#if !defined(__solaris__) && !defined(__OpenBSD__) +void M_Free (void *block) +{ + if (block != NULL) + { + free(block); + } +} +#else +void M_Free (void *block) +{ + if(block != NULL) + { + free(((size_t*) block)-1); + } +} +#endif + diff --git a/source/core/utility/m_alloc.h b/source/core/utility/m_alloc.h new file mode 100644 index 000000000..3da124bff --- /dev/null +++ b/source/core/utility/m_alloc.h @@ -0,0 +1,81 @@ +/* +** m_alloc.h +** +**--------------------------------------------------------------------------- +** Copyright 1998-2008 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#ifndef __M_ALLOC_H__ +#define __M_ALLOC_H__ + +#include +#include + +#if defined(__APPLE__) +#define _msize(p) malloc_size(p) +#elif defined(__solaris__) || defined(__OpenBSD__) +#define _msize(p) (*((size_t*)(p)-1)) +#elif !defined(_WIN32) +#define _msize(p) malloc_usable_size(p) // from glibc/FreeBSD +#endif + +// These are the same as the same stdlib functions, +// except they bomb out with a fatal error +// when they can't get the memory. + +#if defined(_DEBUG) +#define M_Calloc(s,t) M_Calloc_Dbg(s, t, __FILE__, __LINE__) +#define M_Malloc(s) M_Malloc_Dbg(s, __FILE__, __LINE__) +#define M_Realloc(p,s) M_Realloc_Dbg(p, s, __FILE__, __LINE__) + +void *M_Malloc_Dbg (size_t size, const char *file, int lineno); +void *M_Realloc_Dbg (void *memblock, size_t size, const char *file, int lineno); +inline void* M_Calloc_Dbg(size_t v1, size_t v2, const char* file, int lineno) +{ + auto p = M_Malloc_Dbg(v1 * v2, file, lineno); + memset(p, 0, v1 * v2); + return p; +} + +#else +void *M_Malloc (size_t size); +void *M_Realloc (void *memblock, size_t size); +inline void* M_Calloc(size_t v1, size_t v2) +{ + auto p = M_Malloc(v1 * v2); + memset(p, 0, v1 * v2); + return p; +} + +#endif + + +void M_Free (void *memblock); + +#endif //__M_ALLOC_H__