From 939e101fe600d8a7f0d08ccdcf1974bdb78c7bef Mon Sep 17 00:00:00 2001 From: Amos Date: Wed, 28 Jun 2023 10:03:10 +0200 Subject: [PATCH] Properly override all malloc wrappers This covers the entire source code, including thirdparty libraries if memstd.cpp is compiled. Things left to be done: - Utilize the debug methods of the CStdMemAlloc class by routing the debug variants to those. - Move this to a standalone library, so tools and stuff not interfacing directly with the game engine can still link against tier0. --- r5dev/core/dllmain.cpp | 13 +-- r5dev/public/tier0/platform.h | 10 ++ r5dev/tier0/memstd.cpp | 185 ++++++++++++++++++++-------------- r5dev/tier0/memstd.h | 26 ++--- 4 files changed, 130 insertions(+), 104 deletions(-) diff --git a/r5dev/core/dllmain.cpp b/r5dev/core/dllmain.cpp index 0c9ef3cd..b81fbbcb 100644 --- a/r5dev/core/dllmain.cpp +++ b/r5dev/core/dllmain.cpp @@ -98,18 +98,7 @@ void SDK_Init() Input_Init(); #endif // !DEDICATED - // Initialize cURL with rebuilt memory callbacks - // featuring the game's memalloc implementation. - // this is required in order to hook cURL code - // in-game, as we otherwise would manage memory - // memory created by the game's implementation, - // using the standard one. - curl_global_init_mem(CURL_GLOBAL_ALL, - &R_malloc, - &R_free, - &R_realloc, - &R_strdup, - &R_calloc); + curl_global_init(CURL_GLOBAL_ALL); lzham_enable_fail_exceptions(true); } diff --git a/r5dev/public/tier0/platform.h b/r5dev/public/tier0/platform.h index 3608e5da..4fc12d6e 100644 --- a/r5dev/public/tier0/platform.h +++ b/r5dev/public/tier0/platform.h @@ -430,8 +430,18 @@ inline int64 CastPtrToInt64(const void* p) //----------------------------------------------------------------------------- #if defined( COMPILER_GCC ) || defined( COMPILER_SNC ) #define stackalloc( _size ) alloca( ALIGN_VALUE( _size, 16 ) ) + +#ifdef PLATFORM_OSX +#define mallocsize( _p ) ( malloc_size( _p ) ) +#else +#define mallocsize( _p ) ( malloc_usable_size( _p ) ) +#endif + #elif defined ( COMPILER_MSVC ) + #define stackalloc( _size ) _alloca( ALIGN_VALUE( _size, 16 ) ) +#define mallocsize( _p ) ( _msize( _p ) ) + #endif #define stackalloc_aligned( _size, _align ) (void*)( ( ((uintp)alloca( ALIGN_VALUE( ( _size ) + (_align ), ( _align ) ) )) + ( _align ) ) & ~_align ) diff --git a/r5dev/tier0/memstd.cpp b/r5dev/tier0/memstd.cpp index 4122eeba..b30fd6b0 100644 --- a/r5dev/tier0/memstd.cpp +++ b/r5dev/tier0/memstd.cpp @@ -29,83 +29,6 @@ static void InitAllocator() // --------------------------------------------------------------------------- // The replacement functions use the game's internal memalloc system instead //=============================================================================// -extern "C" void* R_malloc(size_t nSize) -{ - Assert(nSize); - InitAllocator(); - return MemAllocSingleton()->Alloc(nSize); -} - -extern "C" void R_free(void* pBlock) -{ - //Assert(pBlock); - InitAllocator(); - MemAllocSingleton()->Free(pBlock); -} - -extern "C" void* R_realloc(void* pBlock, size_t nSize) -{ - //Assert(pBlock && nSize); - - InitAllocator(); - - if (nSize) - return MemAllocSingleton()->Realloc(pBlock, nSize); - else - { - MemAllocSingleton()->InternalFree(pBlock, "tier0_static128", 0); - return nullptr; - } -} - -extern "C" char* R_strdup(const char* pString) -{ - Assert(pString); - - InitAllocator(); - - const size_t nLen = strlen(pString) + 1; - void* pNew = MemAllocSingleton()->Alloc(nLen); - - if (!pNew) - return nullptr; - - return reinterpret_cast(memcpy(pNew, pString, nLen)); -} - -extern "C" void* R_calloc(size_t nCount, size_t nSize) -{ - Assert(nCount && nSize); - - InitAllocator(); - - const size_t nTotal = nCount * nSize; - void* pNew = MemAllocSingleton()->Alloc(nTotal); - - memset(pNew, NULL, nTotal); - return pNew; -} - -extern "C" void* R_recalloc(void* pBlock, size_t nSize) -{ - InitAllocator(); - - void* pMemOut = MemAllocSingleton()->Realloc(pBlock, nSize); - - if (!pBlock) - memset(pMemOut, NULL, nSize); - - return pMemOut; -} - -extern "C" size_t R_mallocsize(void* pBlock) -{ - InitAllocator(); - size_t nSize = MemAllocSingleton()->GetSize(pBlock); - return nSize; -} - - // !TODO: other 'new' operators introduced in C++17. void* operator new(std::size_t n) noexcept(false) { @@ -115,3 +38,111 @@ void operator delete(void* p) throw() { return free(p); } + +extern "C" +{ + __declspec(restrict) void* __cdecl _malloc_base(size_t const nSize) + { + InitAllocator(); + return MemAllocSingleton()->Alloc(nSize); + } + __declspec(restrict) void* __cdecl _calloc_base(size_t const nCount, size_t const nSize) + { + InitAllocator(); + + const size_t nTotal = nCount * nSize; + void* pNew = MemAllocSingleton()->Alloc(nTotal); + + memset(pNew, NULL, nTotal); + return pNew; + } + __declspec(restrict) void* __cdecl _realloc_base(void* const pBlock, size_t const nSize) + { + InitAllocator(); + + if (nSize) + return MemAllocSingleton()->Realloc(pBlock, nSize); + else + { + MemAllocSingleton()->InternalFree(pBlock, "tier0_static128", 0); + return nullptr; + } + } + __declspec(restrict) void* __cdecl _recalloc_base(void* const pBlock, size_t const nCount, size_t const nSize) + { + InitAllocator(); + + void* pMemOut = MemAllocSingleton()->Realloc(pBlock, nSize); + + if (!pBlock) + memset(pMemOut, NULL, nSize); + + return pMemOut; + } + __declspec(noinline) void __cdecl _free_base(void* const pBlock) + { + InitAllocator(); + MemAllocSingleton()->Free(pBlock); + } + __declspec(noinline) size_t __cdecl _msize_base(void* const pBlock) + { + InitAllocator(); + + size_t nSize = MemAllocSingleton()->GetSize(pBlock); + return nSize; + } + char* __cdecl _strdup(const char* pString) + { + InitAllocator(); + + const size_t nLen = strlen(pString) + 1; + void* pNew = MemAllocSingleton()->Alloc(nLen); + + if (!pNew) + return nullptr; + + return reinterpret_cast(memcpy(pNew, pString, nLen)); + } + void* __cdecl _expand_base(void* const pBlock, size_t const nNewSize, int const nBlockUse) + { + // Expanding isn't supported!!! + Assert(0); + return NULL; + } +} + + +extern "C" +{ + __declspec(restrict) void* __cdecl _malloc_dbg(size_t const nSize, int const, char const* const, int const) + { + return _malloc_base(nSize); + } + __declspec(restrict) void* __cdecl _calloc_dbg(size_t const nCount, size_t const nSize, int const, char const* const, int const) + { + return _calloc_base(nCount, nSize); + } + __declspec(restrict) void* __cdecl _realloc_dbg(void* const pBlock, size_t const nSize, int const, char const* const, int const) + { + return _realloc_base(pBlock, nSize); + } + __declspec(restrict) void* __cdecl _recalloc_dbg(void* const pBlock, size_t const nCount, size_t const nSize, int const, char const* const, int const) + { + return _recalloc_base(pBlock, nCount, nSize); + } + __declspec(noinline) void __cdecl _free_dbg(void* const pBlock, int const) + { + return _free_base(pBlock); + } + __declspec(noinline) size_t __cdecl _msize_dbg(void* const pBlock, int const) + { + return _msize_base(pBlock); + } + void* __cdecl _expand_dbg(void* pBlock, size_t nNewSize, int nBlockUse, + const char* pFileName, int nLine) + { + // Expanding isn't supported!!! + Assert(0); + return NULL; + } +} diff --git a/r5dev/tier0/memstd.h b/r5dev/tier0/memstd.h index 5e0a7f10..f0b1e7ce 100644 --- a/r5dev/tier0/memstd.h +++ b/r5dev/tier0/memstd.h @@ -1,21 +1,17 @@ #ifndef MEMSTD_H #define MEMSTD_H -extern "C" void* R_malloc(size_t nSize); -extern "C" void R_free(void* pBlock); -extern "C" void* R_realloc(void* pBlock, size_t nSize); -extern "C" char* R_strdup(const char* pString); -extern "C" void* R_calloc(size_t nCount, size_t nSize); -extern "C" size_t R_mallocsize(void* pBlock); - -// Shadow standard implementation with ours. -#define malloc(nSize) R_malloc(nSize) -#define free(pBlock) R_free(pBlock) -#define realloc(pBlock, nSize) R_realloc(pBlock, nSize) -#define strdup(pString) R_strdup(pString) -#define calloc(nCount, nSize) R_calloc(nCount, nSize) -#define recalloc(pBlock, nSize) R_recalloc(pBlock, nSize) -#define mallocsize(pBlock) R_mallocsize(pBlock) +extern "C" +{ + __declspec(restrict) void* __cdecl _malloc_base(size_t const nSize); + __declspec(restrict) void* __cdecl _calloc_base(size_t const nCount, size_t const nSize); + __declspec(restrict) void* __cdecl _realloc_base(void* const pBlock, size_t const nSize); + __declspec(restrict) void* __cdecl _recalloc_base(void* const pBlock, size_t const nCount, size_t const nSize); + __declspec(noinline) void __cdecl _free_base(void* const pBlock); + __declspec(noinline) size_t __cdecl _msize_base(void* const pBlock); + char* __cdecl _strdup(const char* pString); + void* __cdecl _expand(void* pBlock, size_t nSize); +} class IMemAlloc {