From 7d038c57c2426bcd26ccb661972b9d4c39ad07da Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sat, 14 Jun 2025 22:58:12 +0200 Subject: [PATCH 01/20] [GEN][ZH] Prevent AMD/ATI driver crash on game launch by temporarily unloading and renaming dbghelp.dll --- CMakeLists.txt | 1 - .../Source/WWVegas/WWLib/CMakeLists.txt | 7 + .../Source/WWVegas/WWLib/DbgHelpGuard.cpp | 63 ++++ .../Source/WWVegas/WWLib/DbgHelpGuard.h | 47 +++ .../Source/WWVegas/WWLib/DbgHelpLoader.cpp | 283 ++++++++++++++++++ .../Source/WWVegas/WWLib/DbgHelpLoader.h | 187 ++++++++++++ .../Source/WWVegas/WWLib/MallocAllocator.h | 129 ++++++++ .../WWVegas/WWLib/ScopedFileRenamer.cpp | 98 ++++++ .../Source/WWVegas/WWLib/ScopedFileRenamer.h | 47 +++ Core/Tools/ImagePacker/CMakeLists.txt | 1 - Core/Tools/MapCacheBuilder/CMakeLists.txt | 1 - Core/Tools/PATCHGET/CMakeLists.txt | 1 - .../Source/Common/System/StackDump.cpp | 120 ++++---- .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 32 +- Generals/Code/Main/CMakeLists.txt | 1 - Generals/Code/Tools/GUIEdit/CMakeLists.txt | 1 - .../Code/Tools/ParticleEditor/CMakeLists.txt | 1 - Generals/Code/Tools/W3DView/CMakeLists.txt | 1 - .../Code/Tools/WorldBuilder/CMakeLists.txt | 1 - .../Source/Common/System/StackDump.cpp | 120 ++++---- .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 32 +- GeneralsMD/Code/Main/CMakeLists.txt | 1 - GeneralsMD/Code/Tools/GUIEdit/CMakeLists.txt | 1 - .../Code/Tools/ParticleEditor/CMakeLists.txt | 1 - GeneralsMD/Code/Tools/W3DView/CMakeLists.txt | 1 - .../Code/Tools/WorldBuilder/CMakeLists.txt | 1 - GeneralsMD/Code/Tools/wdump/CMakeLists.txt | 1 - cmake/dbghelp.cmake | 7 - 28 files changed, 1005 insertions(+), 182 deletions(-) create mode 100644 Core/Libraries/Source/WWVegas/WWLib/DbgHelpGuard.cpp create mode 100644 Core/Libraries/Source/WWVegas/WWLib/DbgHelpGuard.h create mode 100644 Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp create mode 100644 Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.h create mode 100644 Core/Libraries/Source/WWVegas/WWLib/MallocAllocator.h create mode 100644 Core/Libraries/Source/WWVegas/WWLib/ScopedFileRenamer.cpp create mode 100644 Core/Libraries/Source/WWVegas/WWLib/ScopedFileRenamer.h delete mode 100644 cmake/dbghelp.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index d2b41feab51..4160c918c74 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,7 +43,6 @@ if((WIN32 OR "${CMAKE_SYSTEM}" MATCHES "Windows") AND ${CMAKE_SIZEOF_VOID_P} EQU include(cmake/miles.cmake) include(cmake/bink.cmake) include(cmake/dx8.cmake) - include(cmake/dbghelp.cmake) endif() # Define a dummy stlport target when not on VC6. diff --git a/Core/Libraries/Source/WWVegas/WWLib/CMakeLists.txt b/Core/Libraries/Source/WWVegas/WWLib/CMakeLists.txt index 99ae03ab2e8..2f8ff16000e 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/CMakeLists.txt +++ b/Core/Libraries/Source/WWVegas/WWLib/CMakeLists.txt @@ -32,6 +32,10 @@ set(WWLIB_SRC #crcstraw.h cstraw.cpp cstraw.h + DbgHelpGuard.cpp + DbgHelpGuard.h + DbgHelpLoader.cpp + DbgHelpLoader.h Except.cpp Except.h FastAllocator.cpp @@ -66,6 +70,7 @@ set(WWLIB_SRC #lzostraw.cpp #lzostraw.h #lzo_conf.h + MallocAllocator.h #md5.cpp #md5.h mempool.h @@ -98,6 +103,8 @@ set(WWLIB_SRC #regexpr.cpp #regexpr.h #search.h + ScopedFileRenamer.cpp + ScopedFileRenamer.h sharebuf.h Signaler.h simplevec.h diff --git a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpGuard.cpp b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpGuard.cpp new file mode 100644 index 00000000000..9a0acc82148 --- /dev/null +++ b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpGuard.cpp @@ -0,0 +1,63 @@ +/* +** Command & Conquer Generals Zero Hour(tm) +** Copyright 2025 TheSuperHackers +** +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +*/ + +#include "DbgHelpGuard.h" + +#include "DbgHelpLoader.h" + + +DbgHelpGuard::DbgHelpGuard() +{ + deactivate(); +} + +DbgHelpGuard::~DbgHelpGuard() +{ + reactivate(); +} + +void DbgHelpGuard::deactivate() +{ + DbgHelpLoader::blockLoad(); + + if (DbgHelpLoader::isLoadedFromSystem()) + { + // This is ok. Do nothing. + } + else if (DbgHelpLoader::isLoaded()) + { + DbgHelpLoader::unload(); + m_wasLoaded = true; + m_dbgHelpRenamer.rename("dbghelp.dll", "dbghelp.dll.bak"); + } + else + { + m_dbgHelpRenamer.rename("dbghelp.dll", "dbghelp.dll.bak"); + } +} + +void DbgHelpGuard::reactivate() +{ + m_dbgHelpRenamer.revert(); + DbgHelpLoader::unblockLoad(); + + if (m_wasLoaded) + { + DbgHelpLoader::load(); + } +} diff --git a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpGuard.h b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpGuard.h new file mode 100644 index 00000000000..243f4ed1cf4 --- /dev/null +++ b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpGuard.h @@ -0,0 +1,47 @@ +/* +** Command & Conquer Generals Zero Hour(tm) +** Copyright 2025 TheSuperHackers +** +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +*/ + +#pragma once + +#include "always.h" + +#include "ScopedFileRenamer.h" + + +// This class temporarily unloads dbghelp.dll and prevents it from loading during its lifetime. +// This helps avoid crashing on boot using recent AMD/ATI drivers, which attempt to load and use +// dbghelp.dll from the game install directory but are unable to do so correctly because +// the dbghelp.dll that ships with the game is very old and the AMD/ATI code does not handle +// that correctly. This workaround is not required if the dbghelp.dll was loaded from the system +// directory. + +class DbgHelpGuard +{ +public: + + DbgHelpGuard(); + ~DbgHelpGuard(); + + void deactivate(); + void reactivate(); + +private: + + ScopedFileRenamer m_dbgHelpRenamer; + bool m_wasLoaded; +}; diff --git a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp new file mode 100644 index 00000000000..b99ae06be7e --- /dev/null +++ b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp @@ -0,0 +1,283 @@ +/* +** Command & Conquer Generals Zero Hour(tm) +** Copyright 2025 TheSuperHackers +** +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +*/ + +#include "DbgHelpLoader.h" + + +int DbgHelpLoader::BlockLoadCounter = 0; +DbgHelpLoader* DbgHelpLoader::Inst = NULL; + +DbgHelpLoader::DbgHelpLoader() + : m_symInitialize(NULL) + , m_symCleanup(NULL) + , m_symLoadModule(NULL) + , m_symUnloadModule(NULL) + , m_symGetModuleBase(NULL) + , m_symGetSymFromAddr(NULL) + , m_symGetLineFromAddr(NULL) + , m_symSetOptions(NULL) + , m_symFunctionTableAccess(NULL) + , m_stackWalk(NULL) + , m_dllModule(HMODULE(0)) + , m_failed(false) + , m_loadedFromSystem(false) +{ +} + +DbgHelpLoader::~DbgHelpLoader() +{ +} + +bool DbgHelpLoader::isLoaded() +{ + return Inst != NULL && Inst->m_dllModule != HMODULE(0); +} + +bool DbgHelpLoader::isLoadedFromSystem() +{ + return Inst != NULL && Inst->m_loadedFromSystem; +} + +void DbgHelpLoader::blockLoad() +{ + ++BlockLoadCounter; +} + +bool DbgHelpLoader::unblockLoad() +{ + return --BlockLoadCounter == 0; +} + +bool DbgHelpLoader::load() +{ + if (BlockLoadCounter > 0) + return false; + + if (Inst == NULL) + { + // Cannot use new/delete here when this is loaded during game memory initialization. + void* p = ::malloc(sizeof(DbgHelpLoader)); + Inst = new (p) DbgHelpLoader(); + } + + // Optimization: return early if it failed before. + if (Inst->m_failed) + return false; + + // Try load dbghelp.dll from the system directory first. + char dllFilename[MAX_PATH]; + ::GetSystemDirectoryA(dllFilename, ARRAY_SIZE(dllFilename)); + strcat(dllFilename, "\\dbghelp.dll"); + + Inst->m_dllModule = ::LoadLibraryA(dllFilename); + if (Inst->m_dllModule == HMODULE(0)) + { + // Not found. Try load dbghelp.dll from the work directory. + Inst->m_dllModule = ::LoadLibraryA("dbghelp.dll"); + if (Inst->m_dllModule == HMODULE(0)) + { + Inst->m_failed = true; + return false; + } + } + else + { + Inst->m_loadedFromSystem = true; + } + + Inst->m_symInitialize = reinterpret_cast(::GetProcAddress(Inst->m_dllModule, "SymInitialize")); + Inst->m_symCleanup = reinterpret_cast(::GetProcAddress(Inst->m_dllModule, "SymCleanup")); + Inst->m_symLoadModule = reinterpret_cast(::GetProcAddress(Inst->m_dllModule, "SymLoadModule")); + Inst->m_symUnloadModule = reinterpret_cast(::GetProcAddress(Inst->m_dllModule, "SymUnloadModule")); + Inst->m_symGetModuleBase = reinterpret_cast(::GetProcAddress(Inst->m_dllModule, "SymGetModuleBase")); + Inst->m_symGetSymFromAddr = reinterpret_cast(::GetProcAddress(Inst->m_dllModule, "SymGetSymFromAddr")); + Inst->m_symGetLineFromAddr = reinterpret_cast(::GetProcAddress(Inst->m_dllModule, "SymGetLineFromAddr")); + Inst->m_symSetOptions = reinterpret_cast(::GetProcAddress(Inst->m_dllModule, "SymSetOptions")); + Inst->m_symFunctionTableAccess = reinterpret_cast(::GetProcAddress(Inst->m_dllModule, "SymFunctionTableAccess")); + Inst->m_stackWalk = reinterpret_cast(::GetProcAddress(Inst->m_dllModule, "StackWalk")); + + if (Inst->m_symInitialize == NULL || Inst->m_symCleanup == NULL) + { + unload(); + Inst->m_failed = true; + return false; + } + + return true; +} + +bool DbgHelpLoader::reload() +{ + unload(); + return load(); +} + +void DbgHelpLoader::unload() +{ + if (Inst == NULL) + return; + + while (!Inst->m_initializedProcesses.empty()) + { + symCleanup(*Inst->m_initializedProcesses.begin()); + } + + if (Inst->m_dllModule != HMODULE(0)) + { + ::FreeLibrary(Inst->m_dllModule); + Inst->m_dllModule = HMODULE(0); + } + + Inst->~DbgHelpLoader(); + ::free(Inst); + Inst = NULL; +} + +BOOL DbgHelpLoader::symInitialize( + HANDLE hProcess, + LPSTR UserSearchPath, + BOOL fInvadeProcess) +{ + if (Inst == NULL) + return FALSE; + + if (Inst->m_initializedProcesses.find(hProcess) != Inst->m_initializedProcesses.end()) + return FALSE; + + if (Inst->m_symInitialize) + { + if (Inst->m_symInitialize(hProcess, UserSearchPath, fInvadeProcess) != FALSE) + { + Inst->m_initializedProcesses.insert(hProcess); + return TRUE; + } + } + + return FALSE; +} + +BOOL DbgHelpLoader::symCleanup( + HANDLE hProcess) +{ + if (Inst == NULL) + return FALSE; + + // @todo stl::find_and_erase + Processes::iterator it = Inst->m_initializedProcesses.find(hProcess); + if (it != Inst->m_initializedProcesses.end()) + Inst->m_initializedProcesses.erase(it); + + if (Inst->m_symCleanup) + return Inst->m_symCleanup(hProcess); + + return FALSE; +} + +BOOL DbgHelpLoader::symLoadModule( + HANDLE hProcess, + HANDLE hFile, + LPSTR ImageName, + LPSTR ModuleName, + DWORD BaseOfDll, + DWORD SizeOfDll) +{ + if (Inst != NULL && Inst->m_symLoadModule) + return Inst->m_symLoadModule(hProcess, hFile, ImageName, ModuleName, BaseOfDll, SizeOfDll); + + return FALSE; +} + +DWORD DbgHelpLoader::symGetModuleBase( + HANDLE hProcess, + DWORD dwAddr) +{ + if (Inst != NULL && Inst->m_symGetModuleBase) + return Inst->m_symGetModuleBase(hProcess, dwAddr); + + return 0u; +} + +BOOL DbgHelpLoader::symUnloadModule( + HANDLE hProcess, + DWORD BaseOfDll) +{ + if (Inst != NULL && Inst->m_symUnloadModule) + return Inst->m_symUnloadModule(hProcess, BaseOfDll); + + return FALSE; +} + +BOOL DbgHelpLoader::symGetSymFromAddr( + HANDLE hProcess, + DWORD Address, + LPDWORD Displacement, + PIMAGEHLP_SYMBOL Symbol) +{ + if (Inst != NULL && Inst->m_symGetSymFromAddr) + return Inst->m_symGetSymFromAddr(hProcess, Address, Displacement, Symbol); + + return FALSE; +} + +BOOL DbgHelpLoader::symGetLineFromAddr( + HANDLE hProcess, + DWORD dwAddr, + PDWORD pdwDisplacement, + PIMAGEHLP_LINE Line) +{ + if (Inst != NULL && Inst->m_symGetLineFromAddr) + return Inst->m_symGetLineFromAddr(hProcess, dwAddr, pdwDisplacement, Line); + + return FALSE; +} + +DWORD DbgHelpLoader::symSetOptions( + DWORD SymOptions) +{ + if (Inst != NULL && Inst->m_symSetOptions) + return Inst->m_symSetOptions(SymOptions); + + return 0u; +} + +LPVOID DbgHelpLoader::symFunctionTableAccess( + HANDLE hProcess, + DWORD AddrBase) +{ + if (Inst != NULL && Inst->m_symFunctionTableAccess) + return Inst->m_symFunctionTableAccess(hProcess, AddrBase); + + return NULL; +} + +BOOL DbgHelpLoader::stackWalk( + DWORD MachineType, + HANDLE hProcess, + HANDLE hThread, + LPSTACKFRAME StackFrame, + LPVOID ContextRecord, + PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine, + PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine, + PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine, + PTRANSLATE_ADDRESS_ROUTINE TranslateAddress) +{ + if (Inst != NULL && Inst->m_stackWalk) + return Inst->m_stackWalk(MachineType, hProcess, hThread, StackFrame, ContextRecord, ReadMemoryRoutine, FunctionTableAccessRoutine, GetModuleBaseRoutine, TranslateAddress); + + return FALSE; +} diff --git a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.h b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.h new file mode 100644 index 00000000000..8b6079e3c82 --- /dev/null +++ b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.h @@ -0,0 +1,187 @@ +/* +** Command & Conquer Generals Zero Hour(tm) +** Copyright 2025 TheSuperHackers +** +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +*/ + +#pragma once + +#include "always.h" + +#include +#include // Must be included after Windows.h +#include + +#include "MallocAllocator.h" + +// This static class can load and unload dbghelp.dll +// Internally it must not use new and delete because it can be created during game memory initialization. + +class DbgHelpLoader +{ +private: + + static int BlockLoadCounter; + static DbgHelpLoader* Inst; // Is singleton class + + DbgHelpLoader(); + ~DbgHelpLoader(); + +public: + + // Returns whether dbghelp.dll is loaded + static bool isLoaded(); + + // Returns whether dbghelp.dll is loaded from the system directory + static bool isLoadedFromSystem(); + + // Blocks loading a dbghelp.dll + static void blockLoad(); + + // Unblocks loading a dbghelp.dll. Returns true if unblocked. + static bool unblockLoad(); + + static bool load(); + static bool reload(); + static void unload(); + + static BOOL WINAPI symInitialize( + HANDLE hProcess, + LPSTR UserSearchPath, + BOOL fInvadeProcess); + + static BOOL WINAPI symCleanup( + HANDLE hProcess); + + static BOOL WINAPI symLoadModule( + HANDLE hProcess, + HANDLE hFile, + LPSTR ImageName, + LPSTR ModuleName, + DWORD BaseOfDll, + DWORD SizeOfDll); + + static DWORD WINAPI symGetModuleBase( + HANDLE hProcess, + DWORD dwAddr); + + static BOOL WINAPI symUnloadModule( + HANDLE hProcess, + DWORD BaseOfDll); + + static BOOL WINAPI symGetSymFromAddr( + HANDLE hProcess, + DWORD Address, + LPDWORD Displacement, + PIMAGEHLP_SYMBOL Symbol); + + static BOOL WINAPI symGetLineFromAddr( + HANDLE hProcess, + DWORD dwAddr, + PDWORD pdwDisplacement, + PIMAGEHLP_LINE Line); + + static DWORD WINAPI symSetOptions( + DWORD SymOptions); + + static LPVOID WINAPI symFunctionTableAccess( + HANDLE hProcess, + DWORD AddrBase); + + static BOOL WINAPI stackWalk( + DWORD MachineType, + HANDLE hProcess, + HANDLE hThread, + LPSTACKFRAME StackFrame, + LPVOID ContextRecord, + PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine, + PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine, + PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine, + PTRANSLATE_ADDRESS_ROUTINE TranslateAddress); + +private: + + typedef BOOL (WINAPI *SymInitialize_t) ( + HANDLE hProcess, + LPSTR UserSearchPath, + BOOL fInvadeProcess); + + typedef BOOL (WINAPI *SymCleanup_t) ( + HANDLE hProcess); + + typedef BOOL (WINAPI *SymLoadModule_t) ( + HANDLE hProcess, + HANDLE hFile, + LPSTR ImageName, + LPSTR ModuleName, + DWORD BaseOfDll, + DWORD SizeOfDll); + + typedef DWORD (WINAPI *SymGetModuleBase_t) ( + HANDLE hProcess, + DWORD dwAddr); + + typedef BOOL (WINAPI *SymUnloadModule_t) ( + HANDLE hProcess, + DWORD BaseOfDll); + + typedef BOOL (WINAPI *SymGetSymFromAddr_t) ( + HANDLE hProcess, + DWORD Address, + LPDWORD Displacement, + PIMAGEHLP_SYMBOL Symbol); + + typedef BOOL (WINAPI* SymGetLineFromAddr_t) ( + HANDLE hProcess, + DWORD dwAddr, + PDWORD pdwDisplacement, + PIMAGEHLP_LINE Line); + + typedef DWORD (WINAPI *SymSetOptions_t) ( + DWORD SymOptions); + + typedef LPVOID (WINAPI *SymFunctionTableAccess_t) ( + HANDLE hProcess, + DWORD AddrBase); + + typedef BOOL (WINAPI *StackWalk_t) ( + DWORD MachineType, + HANDLE hProcess, + HANDLE hThread, + LPSTACKFRAME StackFrame, + LPVOID ContextRecord, + PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine, + PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine, + PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine, + PTRANSLATE_ADDRESS_ROUTINE TranslateAddress); + + SymInitialize_t m_symInitialize; + SymCleanup_t m_symCleanup; + SymLoadModule_t m_symLoadModule; + SymUnloadModule_t m_symUnloadModule; + SymGetModuleBase_t m_symGetModuleBase; + SymGetSymFromAddr_t m_symGetSymFromAddr; + SymGetLineFromAddr_t m_symGetLineFromAddr; + SymSetOptions_t m_symSetOptions; + SymFunctionTableAccess_t m_symFunctionTableAccess; + StackWalk_t m_stackWalk; + + typedef std::set, stl::malloc_allocator > Processes; + + Processes m_initializedProcesses; + HMODULE m_dllModule; + bool m_failed; + bool m_loadedFromSystem; +}; diff --git a/Core/Libraries/Source/WWVegas/WWLib/MallocAllocator.h b/Core/Libraries/Source/WWVegas/WWLib/MallocAllocator.h new file mode 100644 index 00000000000..e465b0ad5d1 --- /dev/null +++ b/Core/Libraries/Source/WWVegas/WWLib/MallocAllocator.h @@ -0,0 +1,129 @@ +/* +** Command & Conquer Generals Zero Hour(tm) +** Copyright 2025 TheSuperHackers +** +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +*/ + +#pragma once + +#include // malloc, free +#include // std::size_t, std::ptrdiff_t +#include // std::bad_alloc + + +namespace stl +{ + +// STL allocator that uses malloc and free. Useful if allocations are meant to bypass new and delete. + +template +class malloc_allocator +{ +public: + + typedef T value_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + template + struct rebind + { + typedef malloc_allocator other; + }; + + malloc_allocator() throw() {} + +#if !(defined(_MSC_VER) && _MSC_VER < 1300) + malloc_allocator(const malloc_allocator&) throw() {} +#endif + + template + malloc_allocator(const malloc_allocator&) throw() {} + + ~malloc_allocator() throw() {} + + pointer address(reference x) const { return &x; } + const_pointer address(const_reference x) const { return &x; } + + pointer allocate(size_type n, const void* = 0) + { + if (n > max_size()) + throw std::bad_alloc(); + + void* p = ::malloc(n * sizeof(T)); + if (!p) + throw std::bad_alloc(); + return static_cast(p); + } + + void deallocate(pointer p, size_type) + { + ::free(p); + } + + void construct(pointer p, const T& val) + { + new (static_cast(p)) T(val); + } + + void destroy(pointer p) + { + p->~T(); + } + + size_type max_size() const throw() + { + return ~size_type(0) / sizeof(T); + } +}; + +// Allocators of same type are always equal +template +bool operator==(const malloc_allocator&, const malloc_allocator&) throw() { + return true; +} + +template +bool operator!=(const malloc_allocator&, const malloc_allocator&) throw() { + return false; +} + +} // namespace stl + + +#if defined(USING_STLPORT) + +// This tells STLport how to rebind malloc_allocator +namespace std +{ + template + struct __stl_alloc_rebind_helper; + + template + inline stl::malloc_allocator& __stl_alloc_rebind(stl::malloc_allocator& a, const Tp2*) { + return *reinterpret_cast*>(&a); + } + + template + inline const stl::malloc_allocator& __stl_alloc_rebind(const stl::malloc_allocator& a, const Tp2*) { + return *reinterpret_cast*>(&a); + } +} + +#endif diff --git a/Core/Libraries/Source/WWVegas/WWLib/ScopedFileRenamer.cpp b/Core/Libraries/Source/WWVegas/WWLib/ScopedFileRenamer.cpp new file mode 100644 index 00000000000..d13c089426f --- /dev/null +++ b/Core/Libraries/Source/WWVegas/WWLib/ScopedFileRenamer.cpp @@ -0,0 +1,98 @@ +/* +** Command & Conquer Generals Zero Hour(tm) +** Copyright 2025 TheSuperHackers +** +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +*/ + +#include "ScopedFileRenamer.h" + + +ScopedFileRenamer::ScopedFileRenamer() + : m_file(NULL) +{ +} + +ScopedFileRenamer::ScopedFileRenamer(const char* oldName, const char* newName) + : m_file(NULL) +{ + this->rename(oldName, newName); +} + +ScopedFileRenamer::~ScopedFileRenamer() +{ + revert(); +} + +bool ScopedFileRenamer::rename(const char* oldName, const char* newName) +{ + revert(); + + m_oldName = oldName; + m_newName = newName; + + if (0 == ::rename(m_oldName.c_str(), m_newName.c_str())) + { + // Creates an empty *.tmp dummy file to remember that this program has renamed the file. + // If the program would crash before the file was renamed back to the previous name, then + // the rename condition will be able to recover the next time this code runs successfully. + std::string tmpFilename = createTmpName(); + m_file = ::fopen(tmpFilename.c_str(), "wb"); + + return true; + } + + return false; +} + +bool ScopedFileRenamer::revert() +{ + if (m_oldName.empty()) + return false; + + bool success = false; + std::string tmpName; + + if (m_file == NULL) + { + tmpName = createTmpName(); + m_file = ::fopen(tmpName.c_str(), "rb"); + } + + if (m_file != NULL) + { + ::fclose(m_file); + m_file = NULL; + + if (0 == ::rename(m_newName.c_str(), m_oldName.c_str())) + success = true; + + if (tmpName.empty()) + tmpName = createTmpName(); + + ::remove(tmpName.c_str()); + } + + m_oldName.clear(); + m_newName.clear(); + + return success; +} + +std::string ScopedFileRenamer::createTmpName() const +{ + std::string tmpFilename = m_oldName; + tmpFilename.append(".tmp"); + return tmpFilename; +} diff --git a/Core/Libraries/Source/WWVegas/WWLib/ScopedFileRenamer.h b/Core/Libraries/Source/WWVegas/WWLib/ScopedFileRenamer.h new file mode 100644 index 00000000000..594192eceb2 --- /dev/null +++ b/Core/Libraries/Source/WWVegas/WWLib/ScopedFileRenamer.h @@ -0,0 +1,47 @@ +/* +** Command & Conquer Generals Zero Hour(tm) +** Copyright 2025 TheSuperHackers +** +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +*/ + +#pragma once + +#include "always.h" + +#include +#include + + +class ScopedFileRenamer +{ +public: + + ScopedFileRenamer(); + ScopedFileRenamer(const char* oldName, const char* newName); + ~ScopedFileRenamer(); + + bool rename(const char* oldName, const char* newName); + bool revert(); + +private: + + std::string createTmpName() const; + +private: + + std::string m_oldName; + std::string m_newName; + FILE* m_file; +}; diff --git a/Core/Tools/ImagePacker/CMakeLists.txt b/Core/Tools/ImagePacker/CMakeLists.txt index c71eefca56d..db8aaf2d157 100644 --- a/Core/Tools/ImagePacker/CMakeLists.txt +++ b/Core/Tools/ImagePacker/CMakeLists.txt @@ -30,7 +30,6 @@ target_link_libraries(corei_imagepacker INTERFACE core_debug core_profile core_wwcommon - dbghelplib imm32 vfw32 winmm diff --git a/Core/Tools/MapCacheBuilder/CMakeLists.txt b/Core/Tools/MapCacheBuilder/CMakeLists.txt index 5d390853a8f..bdb38951a54 100644 --- a/Core/Tools/MapCacheBuilder/CMakeLists.txt +++ b/Core/Tools/MapCacheBuilder/CMakeLists.txt @@ -17,7 +17,6 @@ target_link_libraries(corei_mapcachebuilder INTERFACE comctl32 core_debug core_profile - dbghelplib imm32 vfw32 winmm diff --git a/Core/Tools/PATCHGET/CMakeLists.txt b/Core/Tools/PATCHGET/CMakeLists.txt index 265a74c785b..d2822c3ddbb 100644 --- a/Core/Tools/PATCHGET/CMakeLists.txt +++ b/Core/Tools/PATCHGET/CMakeLists.txt @@ -25,7 +25,6 @@ target_link_libraries(corei_patchgrabber INTERFACE comctl32 core_debug core_profile - dbghelplib gamespy::gamespy imm32 vfw32 diff --git a/Generals/Code/GameEngine/Source/Common/System/StackDump.cpp b/Generals/Code/GameEngine/Source/Common/System/StackDump.cpp index 669264aa222..a0041ee8ccd 100644 --- a/Generals/Code/GameEngine/Source/Common/System/StackDump.cpp +++ b/Generals/Code/GameEngine/Source/Common/System/StackDump.cpp @@ -31,6 +31,7 @@ #include "Common/StackDump.h" #include "Common/Debug.h" +#include "DbgHelpLoader.h" //***************************************************************************** // Prototypes @@ -45,14 +46,6 @@ void WriteStackLine(void*address, void (*callback)(const char*)); // Mis-named globals :-) //***************************************************************************** static CONTEXT gsContext; -static Bool gsInit=FALSE; - -BOOL (__stdcall *gsSymGetLineFromAddr)( - IN HANDLE hProcess, - IN DWORD dwAddr, - OUT PDWORD pdwDisplacement, - OUT PIMAGEHLP_LINE Line - ); //***************************************************************************** @@ -72,7 +65,8 @@ void StackDump(void (*callback)(const char*)) callback = StackDumpDefaultHandler; } - InitSymbolInfo(); + if (!InitSymbolInfo()) + return; DWORD myeip,myesp,myebp; @@ -101,7 +95,8 @@ void StackDumpFromContext(DWORD eip,DWORD esp,DWORD ebp, void (*callback)(const callback = StackDumpDefaultHandler; } - InitSymbolInfo(); + if (!InitSymbolInfo()) + return; MakeStackTrace(eip,esp,ebp, 0, callback); } @@ -111,27 +106,20 @@ void StackDumpFromContext(DWORD eip,DWORD esp,DWORD ebp, void (*callback)(const //***************************************************************************** BOOL InitSymbolInfo() { - if (gsInit == TRUE) + if (DbgHelpLoader::isLoaded()) return TRUE; - gsInit = TRUE; + if (!DbgHelpLoader::load()) + return FALSE; atexit(UninitSymbolInfo); - // See if we have the line from address function - // We use GetProcAddress to stop link failures at dll loadup - HINSTANCE hInstDebugHlp = GetModuleHandle("dbghelp.dll"); - - gsSymGetLineFromAddr = (BOOL (__stdcall *)( IN HANDLE,IN DWORD,OUT PDWORD,OUT PIMAGEHLP_LINE)) - GetProcAddress(hInstDebugHlp , "SymGetLineFromAddr"); - char pathname[_MAX_PATH+1]; char drive[10]; char directory[_MAX_PATH+1]; HANDLE process; - - ::SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_OMAP_FIND_NEAREST); + DbgHelpLoader::symSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_OMAP_FIND_NEAREST); process = GetCurrentProcess(); @@ -145,18 +133,18 @@ BOOL InitSymbolInfo() // append the current directory to build a search path for SymInit ::lstrcat(pathname, ";.;"); - if(::SymInitialize(process, pathname, FALSE)) + if(DbgHelpLoader::symInitialize(process, pathname, FALSE)) { // regenerate the name of the app ::GetModuleFileName(NULL, pathname, _MAX_PATH); - if(::SymLoadModule(process, NULL, pathname, NULL, 0, 0)) + if(DbgHelpLoader::symLoadModule(process, NULL, pathname, NULL, 0, 0)) { //Load any other relevant modules (ie dlls) here return TRUE; } - ::SymCleanup(process); } + DbgHelpLoader::unload(); return(FALSE); } @@ -165,14 +153,7 @@ BOOL InitSymbolInfo() //***************************************************************************** void UninitSymbolInfo(void) { - if (gsInit == FALSE) - { - return; - } - - gsInit = FALSE; - - ::SymCleanup(GetCurrentProcess()); + DbgHelpLoader::unload(); } @@ -217,14 +198,14 @@ stack_frame.AddrFrame.Offset = myebp; unsigned int skip = skipFrames; while (b_ret&&skip) { - b_ret = StackWalk( IMAGE_FILE_MACHINE_I386, + b_ret = DbgHelpLoader::stackWalk( IMAGE_FILE_MACHINE_I386, process, thread, &stack_frame, NULL, //&gsContext, NULL, - SymFunctionTableAccess, - SymGetModuleBase, + DbgHelpLoader::symFunctionTableAccess, + DbgHelpLoader::symGetModuleBase, NULL); skip--; } @@ -233,14 +214,14 @@ stack_frame.AddrFrame.Offset = myebp; while(b_ret&&skip) { - b_ret = StackWalk( IMAGE_FILE_MACHINE_I386, + b_ret = DbgHelpLoader::stackWalk( IMAGE_FILE_MACHINE_I386, process, thread, &stack_frame, NULL, //&gsContext, NULL, - SymFunctionTableAccess, - SymGetModuleBase, + DbgHelpLoader::symFunctionTableAccess, + DbgHelpLoader::symGetModuleBase, NULL); @@ -256,7 +237,9 @@ stack_frame.AddrFrame.Offset = myebp; //***************************************************************************** void GetFunctionDetails(void *pointer, char*name, char*filename, unsigned int* linenumber, unsigned int* address) { - InitSymbolInfo(); + if (!InitSymbolInfo()) + return; + if (name) { strcpy(name, ""); @@ -285,8 +268,8 @@ void GetFunctionDetails(void *pointer, char*name, char*filename, unsigned int* l psymbol->SizeOfStruct = sizeof(symbol_buffer); psymbol->MaxNameLength = 512; - if (SymGetSymFromAddr(process, (DWORD) pointer, &displacement, psymbol)) - { + if (DbgHelpLoader::symGetSymFromAddr(process, (DWORD) pointer, &displacement, psymbol)) + { if (name) { strcpy(name, psymbol->Name); @@ -294,32 +277,27 @@ void GetFunctionDetails(void *pointer, char*name, char*filename, unsigned int* l } // Get line now - if (gsSymGetLineFromAddr) - { - // Unsupported for win95/98 at least with my current dbghelp.dll - IMAGEHLP_LINE line; - memset(&line,0,sizeof(line)); - line.SizeOfStruct = sizeof(line); + IMAGEHLP_LINE line; + memset(&line,0,sizeof(line)); + line.SizeOfStruct = sizeof(line); - - if (gsSymGetLineFromAddr(process, (DWORD) pointer, &displacement, &line)) + if (DbgHelpLoader::symGetLineFromAddr(process, (DWORD) pointer, &displacement, &line)) + { + if (filename) + { + strcpy(filename, line.FileName); + } + if (linenumber) + { + *linenumber = (unsigned int)line.LineNumber; + } + if (address) { - if (filename) - { - strcpy(filename, line.FileName); - } - if (linenumber) - { - *linenumber = (unsigned int)line.LineNumber; - } - if (address) - { - *address = (unsigned int)line.Address; - } + *address = (unsigned int)line.Address; } } - } + } } @@ -328,7 +306,8 @@ void GetFunctionDetails(void *pointer, char*name, char*filename, unsigned int* l //***************************************************************************** void FillStackAddresses(void**addresses, unsigned int count, unsigned int skip) { - InitSymbolInfo(); + if (!InitSymbolInfo()) + return; STACKFRAME stack_frame; @@ -378,28 +357,28 @@ stack_frame.AddrFrame.Offset = myebp; // Skip some? while (stillgoing&&skip) { - stillgoing = StackWalk(IMAGE_FILE_MACHINE_I386, + stillgoing = DbgHelpLoader::stackWalk(IMAGE_FILE_MACHINE_I386, process, thread, &stack_frame, NULL, //&gsContext, NULL, - SymFunctionTableAccess, - SymGetModuleBase, + DbgHelpLoader::symFunctionTableAccess, + DbgHelpLoader::symGetModuleBase, NULL) != 0; skip--; } while(stillgoing&&count) { - stillgoing = StackWalk(IMAGE_FILE_MACHINE_I386, + stillgoing = DbgHelpLoader::stackWalk(IMAGE_FILE_MACHINE_I386, process, thread, &stack_frame, NULL, //&gsContext, NULL, - SymFunctionTableAccess, - SymGetModuleBase, + DbgHelpLoader::symFunctionTableAccess, + DbgHelpLoader::symGetModuleBase, NULL) != 0; if (stillgoing) { @@ -438,7 +417,8 @@ void StackDumpFromAddresses(void**addresses, unsigned int count, void (*callback callback = StackDumpDefaultHandler; } - InitSymbolInfo(); + if (!InitSymbolInfo()) + return; while ((count--) && (*addresses!=NULL)) { diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index a94c8d239c2..3f017b79964 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -81,6 +81,7 @@ #include "dx8texman.h" #include "bound.h" #include "dx8webbrowser.h" +#include "DbgHelpGuard.h" const int DEFAULT_RESOLUTION_WIDTH = 640; @@ -312,7 +313,12 @@ bool DX8Wrapper::Init(void * hwnd, bool lite) ** Create the D3D interface object */ WWDEBUG_SAY(("Create Direct3D8")); - D3DInterface = Direct3DCreate8Ptr(D3D_SDK_VERSION); // TODO: handle failure cases... + { + // TheSuperHackers @bugfix xezon 13/06/2025 Temporarily unload dbghelp.dll and prevent it from loading. + DbgHelpGuard dbgHelpGuard; + + D3DInterface = Direct3DCreate8Ptr(D3D_SDK_VERSION); // TODO: handle failure cases... + } if (D3DInterface == NULL) { return(false); } @@ -558,15 +564,21 @@ bool DX8Wrapper::Create_Device(void) Vertex_Processing_Behavior|=D3DCREATE_FPU_PRESERVE; #endif - HRESULT hr=D3DInterface->CreateDevice - ( - CurRenderDevice, - WW3D_DEVTYPE, - _Hwnd, - Vertex_Processing_Behavior, - &_PresentParameters, - &D3DDevice - ); + HRESULT hr; + { + // TheSuperHackers @bugfix xezon 13/06/2025 Temporarily unload dbghelp.dll and prevent it from loading. + DbgHelpGuard dbgHelpGuard; + + hr=D3DInterface->CreateDevice + ( + CurRenderDevice, + WW3D_DEVTYPE, + _Hwnd, + Vertex_Processing_Behavior, + &_PresentParameters, + &D3DDevice + ); + } if (FAILED(hr)) { diff --git a/Generals/Code/Main/CMakeLists.txt b/Generals/Code/Main/CMakeLists.txt index 51ca97d5afb..f6b7a4640bd 100644 --- a/Generals/Code/Main/CMakeLists.txt +++ b/Generals/Code/Main/CMakeLists.txt @@ -12,7 +12,6 @@ target_link_libraries(g_generals PRIVATE comctl32 d3d8 d3dx8 - dbghelplib dinput8 dxguid g_gameengine diff --git a/Generals/Code/Tools/GUIEdit/CMakeLists.txt b/Generals/Code/Tools/GUIEdit/CMakeLists.txt index c9bb07a3c06..a3c397408c8 100644 --- a/Generals/Code/Tools/GUIEdit/CMakeLists.txt +++ b/Generals/Code/Tools/GUIEdit/CMakeLists.txt @@ -48,7 +48,6 @@ target_include_directories(g_guiedit PRIVATE target_link_libraries(g_guiedit PRIVATE comctl32 d3d8lib - dbghelplib g_gameengine g_gameenginedevice g_wwvegas diff --git a/Generals/Code/Tools/ParticleEditor/CMakeLists.txt b/Generals/Code/Tools/ParticleEditor/CMakeLists.txt index bf7005ea58a..0ea7325438a 100644 --- a/Generals/Code/Tools/ParticleEditor/CMakeLists.txt +++ b/Generals/Code/Tools/ParticleEditor/CMakeLists.txt @@ -42,7 +42,6 @@ target_link_libraries(g_particleeditor PRIVATE corei_libraries_source_wwvegas corei_libraries_source_wwvegas_wwlib d3d8lib - dbghelplib gi_gameengine_include gi_always gi_libraries_source_wwvegas diff --git a/Generals/Code/Tools/W3DView/CMakeLists.txt b/Generals/Code/Tools/W3DView/CMakeLists.txt index 80ab604011f..7a3f14db37e 100644 --- a/Generals/Code/Tools/W3DView/CMakeLists.txt +++ b/Generals/Code/Tools/W3DView/CMakeLists.txt @@ -8,7 +8,6 @@ target_link_libraries(g_w3dview PRIVATE d3d8 d3d8lib d3dx8 - dbghelplib imm32 milesstub Version diff --git a/Generals/Code/Tools/WorldBuilder/CMakeLists.txt b/Generals/Code/Tools/WorldBuilder/CMakeLists.txt index 3cb3b49c265..502d84d5e3c 100644 --- a/Generals/Code/Tools/WorldBuilder/CMakeLists.txt +++ b/Generals/Code/Tools/WorldBuilder/CMakeLists.txt @@ -206,7 +206,6 @@ target_compile_definitions(g_worldbuilder PRIVATE _AFXDLL) target_link_libraries(g_worldbuilder PRIVATE d3d8lib - dbghelplib core_browserdispatch g_gameengine g_gameenginedevice diff --git a/GeneralsMD/Code/GameEngine/Source/Common/System/StackDump.cpp b/GeneralsMD/Code/GameEngine/Source/Common/System/StackDump.cpp index 012f649a16c..3474fc8b074 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/System/StackDump.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/System/StackDump.cpp @@ -31,6 +31,7 @@ #include "Common/StackDump.h" #include "Common/Debug.h" +#include "DbgHelpLoader.h" //***************************************************************************** // Prototypes @@ -45,14 +46,6 @@ void WriteStackLine(void*address, void (*callback)(const char*)); // Mis-named globals :-) //***************************************************************************** static CONTEXT gsContext; -static Bool gsInit=FALSE; - -BOOL (__stdcall *gsSymGetLineFromAddr)( - IN HANDLE hProcess, - IN DWORD dwAddr, - OUT PDWORD pdwDisplacement, - OUT PIMAGEHLP_LINE Line - ); //***************************************************************************** @@ -72,7 +65,8 @@ void StackDump(void (*callback)(const char*)) callback = StackDumpDefaultHandler; } - InitSymbolInfo(); + if (!InitSymbolInfo()) + return; DWORD myeip,myesp,myebp; @@ -101,7 +95,8 @@ void StackDumpFromContext(DWORD eip,DWORD esp,DWORD ebp, void (*callback)(const callback = StackDumpDefaultHandler; } - InitSymbolInfo(); + if (!InitSymbolInfo()) + return; MakeStackTrace(eip,esp,ebp, 0, callback); } @@ -111,27 +106,20 @@ void StackDumpFromContext(DWORD eip,DWORD esp,DWORD ebp, void (*callback)(const //***************************************************************************** BOOL InitSymbolInfo() { - if (gsInit == TRUE) + if (DbgHelpLoader::isLoaded()) return TRUE; - gsInit = TRUE; + if (!DbgHelpLoader::load()) + return FALSE; atexit(UninitSymbolInfo); - // See if we have the line from address function - // We use GetProcAddress to stop link failures at dll loadup - HINSTANCE hInstDebugHlp = GetModuleHandle("dbghelp.dll"); - - gsSymGetLineFromAddr = (BOOL (__stdcall *)( IN HANDLE,IN DWORD,OUT PDWORD,OUT PIMAGEHLP_LINE)) - GetProcAddress(hInstDebugHlp , "SymGetLineFromAddr"); - char pathname[_MAX_PATH+1]; char drive[10]; char directory[_MAX_PATH+1]; HANDLE process; - - ::SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_OMAP_FIND_NEAREST); + DbgHelpLoader::symSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_OMAP_FIND_NEAREST); process = GetCurrentProcess(); @@ -145,18 +133,18 @@ BOOL InitSymbolInfo() // append the current directory to build a search path for SymInit ::lstrcat(pathname, ";.;"); - if(::SymInitialize(process, pathname, FALSE)) + if(DbgHelpLoader::symInitialize(process, pathname, FALSE)) { // regenerate the name of the app ::GetModuleFileName(NULL, pathname, _MAX_PATH); - if(::SymLoadModule(process, NULL, pathname, NULL, 0, 0)) + if(DbgHelpLoader::symLoadModule(process, NULL, pathname, NULL, 0, 0)) { //Load any other relevant modules (ie dlls) here return TRUE; } - ::SymCleanup(process); } + DbgHelpLoader::unload(); return(FALSE); } @@ -165,14 +153,7 @@ BOOL InitSymbolInfo() //***************************************************************************** void UninitSymbolInfo(void) { - if (gsInit == FALSE) - { - return; - } - - gsInit = FALSE; - - ::SymCleanup(GetCurrentProcess()); + DbgHelpLoader::unload(); } @@ -217,14 +198,14 @@ stack_frame.AddrFrame.Offset = myebp; unsigned int skip = skipFrames; while (b_ret&&skip) { - b_ret = StackWalk( IMAGE_FILE_MACHINE_I386, + b_ret = DbgHelpLoader::stackWalk( IMAGE_FILE_MACHINE_I386, process, thread, &stack_frame, NULL, //&gsContext, NULL, - SymFunctionTableAccess, - SymGetModuleBase, + DbgHelpLoader::symFunctionTableAccess, + DbgHelpLoader::symGetModuleBase, NULL); skip--; } @@ -233,14 +214,14 @@ stack_frame.AddrFrame.Offset = myebp; while(b_ret&&skip) { - b_ret = StackWalk( IMAGE_FILE_MACHINE_I386, + b_ret = DbgHelpLoader::stackWalk( IMAGE_FILE_MACHINE_I386, process, thread, &stack_frame, NULL, //&gsContext, NULL, - SymFunctionTableAccess, - SymGetModuleBase, + DbgHelpLoader::symFunctionTableAccess, + DbgHelpLoader::symGetModuleBase, NULL); @@ -256,7 +237,9 @@ stack_frame.AddrFrame.Offset = myebp; //***************************************************************************** void GetFunctionDetails(void *pointer, char*name, char*filename, unsigned int* linenumber, unsigned int* address) { - InitSymbolInfo(); + if (!InitSymbolInfo()) + return; + if (name) { strcpy(name, ""); @@ -285,8 +268,8 @@ void GetFunctionDetails(void *pointer, char*name, char*filename, unsigned int* l psymbol->SizeOfStruct = sizeof(symbol_buffer); psymbol->MaxNameLength = 512; - if (SymGetSymFromAddr(process, (DWORD) pointer, &displacement, psymbol)) - { + if (DbgHelpLoader::symGetSymFromAddr(process, (DWORD) pointer, &displacement, psymbol)) + { if (name) { strcpy(name, psymbol->Name); @@ -294,32 +277,27 @@ void GetFunctionDetails(void *pointer, char*name, char*filename, unsigned int* l } // Get line now - if (gsSymGetLineFromAddr) - { - // Unsupported for win95/98 at least with my current dbghelp.dll - IMAGEHLP_LINE line; - memset(&line,0,sizeof(line)); - line.SizeOfStruct = sizeof(line); + IMAGEHLP_LINE line; + memset(&line,0,sizeof(line)); + line.SizeOfStruct = sizeof(line); - - if (gsSymGetLineFromAddr(process, (DWORD) pointer, &displacement, &line)) + if (DbgHelpLoader::symGetLineFromAddr(process, (DWORD) pointer, &displacement, &line)) + { + if (filename) + { + strcpy(filename, line.FileName); + } + if (linenumber) + { + *linenumber = (unsigned int)line.LineNumber; + } + if (address) { - if (filename) - { - strcpy(filename, line.FileName); - } - if (linenumber) - { - *linenumber = (unsigned int)line.LineNumber; - } - if (address) - { - *address = (unsigned int)line.Address; - } + *address = (unsigned int)line.Address; } } - } + } } @@ -328,7 +306,8 @@ void GetFunctionDetails(void *pointer, char*name, char*filename, unsigned int* l //***************************************************************************** void FillStackAddresses(void**addresses, unsigned int count, unsigned int skip) { - InitSymbolInfo(); + if (!InitSymbolInfo()) + return; STACKFRAME stack_frame; @@ -378,28 +357,28 @@ stack_frame.AddrFrame.Offset = myebp; // Skip some? while (stillgoing&&skip) { - stillgoing = StackWalk(IMAGE_FILE_MACHINE_I386, + stillgoing = DbgHelpLoader::stackWalk(IMAGE_FILE_MACHINE_I386, process, thread, &stack_frame, NULL, //&gsContext, NULL, - SymFunctionTableAccess, - SymGetModuleBase, + DbgHelpLoader::symFunctionTableAccess, + DbgHelpLoader::symGetModuleBase, NULL) != 0; skip--; } while(stillgoing&&count) { - stillgoing = StackWalk(IMAGE_FILE_MACHINE_I386, + stillgoing = DbgHelpLoader::stackWalk(IMAGE_FILE_MACHINE_I386, process, thread, &stack_frame, NULL, //&gsContext, NULL, - SymFunctionTableAccess, - SymGetModuleBase, + DbgHelpLoader::symFunctionTableAccess, + DbgHelpLoader::symGetModuleBase, NULL) != 0; if (stillgoing) { @@ -438,7 +417,8 @@ void StackDumpFromAddresses(void**addresses, unsigned int count, void (*callback callback = StackDumpDefaultHandler; } - InitSymbolInfo(); + if (!InitSymbolInfo()) + return; while ((count--) && (*addresses!=NULL)) { diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 33adbebd630..48b0222ec08 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -85,6 +85,7 @@ #include "dx8texman.h" #include "bound.h" #include "dx8webbrowser.h" +#include "DbgHelpGuard.h" #include "shdlib.h" @@ -331,7 +332,12 @@ bool DX8Wrapper::Init(void * hwnd, bool lite) ** Create the D3D interface object */ WWDEBUG_SAY(("Create Direct3D8")); - D3DInterface = Direct3DCreate8Ptr(D3D_SDK_VERSION); // TODO: handle failure cases... + { + // TheSuperHackers @bugfix xezon 13/06/2025 Temporarily unload dbghelp.dll and prevent it from loading. + DbgHelpGuard dbgHelpGuard; + + D3DInterface = Direct3DCreate8Ptr(D3D_SDK_VERSION); // TODO: handle failure cases... + } if (D3DInterface == NULL) { return(false); } @@ -590,15 +596,21 @@ bool DX8Wrapper::Create_Device(void) Vertex_Processing_Behavior|=D3DCREATE_FPU_PRESERVE; #endif - HRESULT hr=D3DInterface->CreateDevice - ( - CurRenderDevice, - WW3D_DEVTYPE, - _Hwnd, - Vertex_Processing_Behavior, - &_PresentParameters, - &D3DDevice - ); + HRESULT hr; + { + // TheSuperHackers @bugfix xezon 13/06/2025 Temporarily unload dbghelp.dll and prevent it from loading. + DbgHelpGuard dbgHelpGuard; + + hr=D3DInterface->CreateDevice + ( + CurRenderDevice, + WW3D_DEVTYPE, + _Hwnd, + Vertex_Processing_Behavior, + &_PresentParameters, + &D3DDevice + ); + } if (FAILED(hr)) { diff --git a/GeneralsMD/Code/Main/CMakeLists.txt b/GeneralsMD/Code/Main/CMakeLists.txt index fa73f03c136..cabc45befa4 100644 --- a/GeneralsMD/Code/Main/CMakeLists.txt +++ b/GeneralsMD/Code/Main/CMakeLists.txt @@ -14,7 +14,6 @@ target_link_libraries(z_generals PRIVATE core_profile d3d8 d3dx8 - dbghelplib dinput8 dxguid imm32 diff --git a/GeneralsMD/Code/Tools/GUIEdit/CMakeLists.txt b/GeneralsMD/Code/Tools/GUIEdit/CMakeLists.txt index 64af9ee3b22..2b36b302134 100644 --- a/GeneralsMD/Code/Tools/GUIEdit/CMakeLists.txt +++ b/GeneralsMD/Code/Tools/GUIEdit/CMakeLists.txt @@ -50,7 +50,6 @@ target_link_libraries(z_guiedit PRIVATE core_debug core_profile d3d8lib - dbghelplib imm32 stlport vfw32 diff --git a/GeneralsMD/Code/Tools/ParticleEditor/CMakeLists.txt b/GeneralsMD/Code/Tools/ParticleEditor/CMakeLists.txt index 0b410f34701..4d09c98ec22 100644 --- a/GeneralsMD/Code/Tools/ParticleEditor/CMakeLists.txt +++ b/GeneralsMD/Code/Tools/ParticleEditor/CMakeLists.txt @@ -42,7 +42,6 @@ target_link_libraries(z_particleeditor PRIVATE corei_libraries_source_wwvegas corei_libraries_source_wwvegas_wwlib d3d8lib - dbghelplib imm32 core_config stlport diff --git a/GeneralsMD/Code/Tools/W3DView/CMakeLists.txt b/GeneralsMD/Code/Tools/W3DView/CMakeLists.txt index 7225e63bd5f..9f321bc93db 100644 --- a/GeneralsMD/Code/Tools/W3DView/CMakeLists.txt +++ b/GeneralsMD/Code/Tools/W3DView/CMakeLists.txt @@ -8,7 +8,6 @@ target_link_libraries(z_w3dview PRIVATE d3d8 d3d8lib d3dx8 - dbghelplib imm32 milesstub Version diff --git a/GeneralsMD/Code/Tools/WorldBuilder/CMakeLists.txt b/GeneralsMD/Code/Tools/WorldBuilder/CMakeLists.txt index 1daa5339e90..1aaa85c92b9 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/CMakeLists.txt +++ b/GeneralsMD/Code/Tools/WorldBuilder/CMakeLists.txt @@ -213,7 +213,6 @@ target_link_libraries(z_worldbuilder PRIVATE core_debug core_profile d3d8lib - dbghelplib imm32 vfw32 winmm diff --git a/GeneralsMD/Code/Tools/wdump/CMakeLists.txt b/GeneralsMD/Code/Tools/wdump/CMakeLists.txt index a363e40260b..65d190703e4 100644 --- a/GeneralsMD/Code/Tools/wdump/CMakeLists.txt +++ b/GeneralsMD/Code/Tools/wdump/CMakeLists.txt @@ -21,7 +21,6 @@ target_link_libraries(z_wdump PRIVATE core_config core_utility core_wwstub # avoid linking GameEngine - dbghelplib imm32 vfw32 winmm diff --git a/cmake/dbghelp.cmake b/cmake/dbghelp.cmake deleted file mode 100644 index 7940400e3e9..00000000000 --- a/cmake/dbghelp.cmake +++ /dev/null @@ -1,7 +0,0 @@ -FetchContent_Declare( - dbghelp - GIT_REPOSITORY https://github.com/TheSuperHackers/dbghelp-import-lib.git - GIT_TAG afeb423d4597167c8fa94215f4574f3ae310f920 -) - -FetchContent_MakeAvailable(dbghelp) \ No newline at end of file From c63da9192513c6c8197a72dbbbfb57bc473a9854 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sat, 14 Jun 2025 23:42:59 +0200 Subject: [PATCH 02/20] Minor improvement in DbgHelpGuard --- Core/Libraries/Source/WWVegas/WWLib/DbgHelpGuard.cpp | 5 +++-- Core/Libraries/Source/WWVegas/WWLib/DbgHelpGuard.h | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpGuard.cpp b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpGuard.cpp index 9a0acc82148..16c705c8b55 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpGuard.cpp +++ b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpGuard.cpp @@ -42,7 +42,7 @@ void DbgHelpGuard::deactivate() else if (DbgHelpLoader::isLoaded()) { DbgHelpLoader::unload(); - m_wasLoaded = true; + m_requiresLoad = true; m_dbgHelpRenamer.rename("dbghelp.dll", "dbghelp.dll.bak"); } else @@ -56,8 +56,9 @@ void DbgHelpGuard::reactivate() m_dbgHelpRenamer.revert(); DbgHelpLoader::unblockLoad(); - if (m_wasLoaded) + if (m_requiresLoad) { DbgHelpLoader::load(); + m_requiresLoad = false; } } diff --git a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpGuard.h b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpGuard.h index 243f4ed1cf4..ddb534c520b 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpGuard.h +++ b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpGuard.h @@ -43,5 +43,5 @@ class DbgHelpGuard private: ScopedFileRenamer m_dbgHelpRenamer; - bool m_wasLoaded; + bool m_requiresLoad; }; From ea04cee910f57d8cfe0ca72142059ab8bf3a17bc Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Wed, 18 Jun 2025 18:35:48 +0200 Subject: [PATCH 03/20] Remove ScopeFileRenamer and use dbghelp front loading strategy instead of file renaming --- .../Source/WWVegas/WWLib/CMakeLists.txt | 2 - .../Source/WWVegas/WWLib/DbgHelpGuard.cpp | 27 +++-- .../Source/WWVegas/WWLib/DbgHelpGuard.h | 13 +-- .../Source/WWVegas/WWLib/DbgHelpLoader.cpp | 14 --- .../Source/WWVegas/WWLib/DbgHelpLoader.h | 7 -- .../WWVegas/WWLib/ScopedFileRenamer.cpp | 98 ------------------- .../Source/WWVegas/WWLib/ScopedFileRenamer.h | 47 --------- 7 files changed, 16 insertions(+), 192 deletions(-) delete mode 100644 Core/Libraries/Source/WWVegas/WWLib/ScopedFileRenamer.cpp delete mode 100644 Core/Libraries/Source/WWVegas/WWLib/ScopedFileRenamer.h diff --git a/Core/Libraries/Source/WWVegas/WWLib/CMakeLists.txt b/Core/Libraries/Source/WWVegas/WWLib/CMakeLists.txt index 2f8ff16000e..81579754a38 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/CMakeLists.txt +++ b/Core/Libraries/Source/WWVegas/WWLib/CMakeLists.txt @@ -103,8 +103,6 @@ set(WWLIB_SRC #regexpr.cpp #regexpr.h #search.h - ScopedFileRenamer.cpp - ScopedFileRenamer.h sharebuf.h Signaler.h simplevec.h diff --git a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpGuard.cpp b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpGuard.cpp index 16c705c8b55..f53b89adcc1 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpGuard.cpp +++ b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpGuard.cpp @@ -22,43 +22,38 @@ DbgHelpGuard::DbgHelpGuard() + : m_hasLoaded(false) { - deactivate(); + activate(); } DbgHelpGuard::~DbgHelpGuard() { - reactivate(); + deactivate(); } -void DbgHelpGuard::deactivate() +void DbgHelpGuard::activate() { - DbgHelpLoader::blockLoad(); - if (DbgHelpLoader::isLoadedFromSystem()) { // This is ok. Do nothing. } else if (DbgHelpLoader::isLoaded()) { - DbgHelpLoader::unload(); - m_requiresLoad = true; - m_dbgHelpRenamer.rename("dbghelp.dll", "dbghelp.dll.bak"); + // This is maybe not ok. But do nothing until this becomes a user facing problem. } else { - m_dbgHelpRenamer.rename("dbghelp.dll", "dbghelp.dll.bak"); + // Front load the DLL now to prevent other code from loading the potentially wrong DLL. + m_hasLoaded = DbgHelpLoader::load(); } } -void DbgHelpGuard::reactivate() +void DbgHelpGuard::deactivate() { - m_dbgHelpRenamer.revert(); - DbgHelpLoader::unblockLoad(); - - if (m_requiresLoad) + if (m_hasLoaded) { - DbgHelpLoader::load(); - m_requiresLoad = false; + DbgHelpLoader::unload(); + m_hasLoaded = false; } } diff --git a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpGuard.h b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpGuard.h index ddb534c520b..c613cb3b4cd 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpGuard.h +++ b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpGuard.h @@ -20,15 +20,13 @@ #include "always.h" -#include "ScopedFileRenamer.h" - -// This class temporarily unloads dbghelp.dll and prevents it from loading during its lifetime. +// This class temporarily loads and unloads dbghelp.dll from the desired location to prevent +// other code from potentially loading it from an undesired location. // This helps avoid crashing on boot using recent AMD/ATI drivers, which attempt to load and use // dbghelp.dll from the game install directory but are unable to do so correctly because // the dbghelp.dll that ships with the game is very old and the AMD/ATI code does not handle -// that correctly. This workaround is not required if the dbghelp.dll was loaded from the system -// directory. +// that correctly. class DbgHelpGuard { @@ -37,11 +35,10 @@ class DbgHelpGuard DbgHelpGuard(); ~DbgHelpGuard(); + void activate(); void deactivate(); - void reactivate(); private: - ScopedFileRenamer m_dbgHelpRenamer; - bool m_requiresLoad; + bool m_hasLoaded; }; diff --git a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp index b99ae06be7e..4449ff15a60 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp +++ b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp @@ -19,7 +19,6 @@ #include "DbgHelpLoader.h" -int DbgHelpLoader::BlockLoadCounter = 0; DbgHelpLoader* DbgHelpLoader::Inst = NULL; DbgHelpLoader::DbgHelpLoader() @@ -53,21 +52,8 @@ bool DbgHelpLoader::isLoadedFromSystem() return Inst != NULL && Inst->m_loadedFromSystem; } -void DbgHelpLoader::blockLoad() -{ - ++BlockLoadCounter; -} - -bool DbgHelpLoader::unblockLoad() -{ - return --BlockLoadCounter == 0; -} - bool DbgHelpLoader::load() { - if (BlockLoadCounter > 0) - return false; - if (Inst == NULL) { // Cannot use new/delete here when this is loaded during game memory initialization. diff --git a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.h b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.h index 8b6079e3c82..3a7d9cafa90 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.h +++ b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.h @@ -33,7 +33,6 @@ class DbgHelpLoader { private: - static int BlockLoadCounter; static DbgHelpLoader* Inst; // Is singleton class DbgHelpLoader(); @@ -47,12 +46,6 @@ class DbgHelpLoader // Returns whether dbghelp.dll is loaded from the system directory static bool isLoadedFromSystem(); - // Blocks loading a dbghelp.dll - static void blockLoad(); - - // Unblocks loading a dbghelp.dll. Returns true if unblocked. - static bool unblockLoad(); - static bool load(); static bool reload(); static void unload(); diff --git a/Core/Libraries/Source/WWVegas/WWLib/ScopedFileRenamer.cpp b/Core/Libraries/Source/WWVegas/WWLib/ScopedFileRenamer.cpp deleted file mode 100644 index d13c089426f..00000000000 --- a/Core/Libraries/Source/WWVegas/WWLib/ScopedFileRenamer.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* -** Command & Conquer Generals Zero Hour(tm) -** Copyright 2025 TheSuperHackers -** -** This program is free software: you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation, either version 3 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program. If not, see . -*/ - -#include "ScopedFileRenamer.h" - - -ScopedFileRenamer::ScopedFileRenamer() - : m_file(NULL) -{ -} - -ScopedFileRenamer::ScopedFileRenamer(const char* oldName, const char* newName) - : m_file(NULL) -{ - this->rename(oldName, newName); -} - -ScopedFileRenamer::~ScopedFileRenamer() -{ - revert(); -} - -bool ScopedFileRenamer::rename(const char* oldName, const char* newName) -{ - revert(); - - m_oldName = oldName; - m_newName = newName; - - if (0 == ::rename(m_oldName.c_str(), m_newName.c_str())) - { - // Creates an empty *.tmp dummy file to remember that this program has renamed the file. - // If the program would crash before the file was renamed back to the previous name, then - // the rename condition will be able to recover the next time this code runs successfully. - std::string tmpFilename = createTmpName(); - m_file = ::fopen(tmpFilename.c_str(), "wb"); - - return true; - } - - return false; -} - -bool ScopedFileRenamer::revert() -{ - if (m_oldName.empty()) - return false; - - bool success = false; - std::string tmpName; - - if (m_file == NULL) - { - tmpName = createTmpName(); - m_file = ::fopen(tmpName.c_str(), "rb"); - } - - if (m_file != NULL) - { - ::fclose(m_file); - m_file = NULL; - - if (0 == ::rename(m_newName.c_str(), m_oldName.c_str())) - success = true; - - if (tmpName.empty()) - tmpName = createTmpName(); - - ::remove(tmpName.c_str()); - } - - m_oldName.clear(); - m_newName.clear(); - - return success; -} - -std::string ScopedFileRenamer::createTmpName() const -{ - std::string tmpFilename = m_oldName; - tmpFilename.append(".tmp"); - return tmpFilename; -} diff --git a/Core/Libraries/Source/WWVegas/WWLib/ScopedFileRenamer.h b/Core/Libraries/Source/WWVegas/WWLib/ScopedFileRenamer.h deleted file mode 100644 index 594192eceb2..00000000000 --- a/Core/Libraries/Source/WWVegas/WWLib/ScopedFileRenamer.h +++ /dev/null @@ -1,47 +0,0 @@ -/* -** Command & Conquer Generals Zero Hour(tm) -** Copyright 2025 TheSuperHackers -** -** This program is free software: you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation, either version 3 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program. If not, see . -*/ - -#pragma once - -#include "always.h" - -#include -#include - - -class ScopedFileRenamer -{ -public: - - ScopedFileRenamer(); - ScopedFileRenamer(const char* oldName, const char* newName); - ~ScopedFileRenamer(); - - bool rename(const char* oldName, const char* newName); - bool revert(); - -private: - - std::string createTmpName() const; - -private: - - std::string m_oldName; - std::string m_newName; - FILE* m_file; -}; From f92f4ff84aed2867c88f683215d3830b7af85a98 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sat, 5 Jul 2025 20:23:56 +0200 Subject: [PATCH 04/20] Update comments --- Core/Libraries/Source/WWVegas/WWLib/DbgHelpGuard.h | 2 +- Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp | 6 ++++-- .../Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp | 6 ++++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpGuard.h b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpGuard.h index c613cb3b4cd..1a3e8931a4a 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpGuard.h +++ b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpGuard.h @@ -24,7 +24,7 @@ // This class temporarily loads and unloads dbghelp.dll from the desired location to prevent // other code from potentially loading it from an undesired location. // This helps avoid crashing on boot using recent AMD/ATI drivers, which attempt to load and use -// dbghelp.dll from the game install directory but are unable to do so correctly because +// dbghelp.dll from the game install directory but are unable to do so without crashing because // the dbghelp.dll that ships with the game is very old and the AMD/ATI code does not handle // that correctly. diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 3f017b79964..0b012124bfd 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -314,7 +314,8 @@ bool DX8Wrapper::Init(void * hwnd, bool lite) */ WWDEBUG_SAY(("Create Direct3D8")); { - // TheSuperHackers @bugfix xezon 13/06/2025 Temporarily unload dbghelp.dll and prevent it from loading. + // TheSuperHackers @bugfix xezon 13/06/2025 Front load the system dbghelp.dll + // to prevent the graphics driver from potentially loading the old game dbghelp.dll. DbgHelpGuard dbgHelpGuard; D3DInterface = Direct3DCreate8Ptr(D3D_SDK_VERSION); // TODO: handle failure cases... @@ -566,7 +567,8 @@ bool DX8Wrapper::Create_Device(void) HRESULT hr; { - // TheSuperHackers @bugfix xezon 13/06/2025 Temporarily unload dbghelp.dll and prevent it from loading. + // TheSuperHackers @bugfix xezon 13/06/2025 Front load the system dbghelp.dll + // to prevent the graphics driver from potentially loading the old game dbghelp.dll. DbgHelpGuard dbgHelpGuard; hr=D3DInterface->CreateDevice diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 48b0222ec08..16d085081bc 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -333,7 +333,8 @@ bool DX8Wrapper::Init(void * hwnd, bool lite) */ WWDEBUG_SAY(("Create Direct3D8")); { - // TheSuperHackers @bugfix xezon 13/06/2025 Temporarily unload dbghelp.dll and prevent it from loading. + // TheSuperHackers @bugfix xezon 13/06/2025 Front load the system dbghelp.dll + // to prevent the graphics driver from potentially loading the old game dbghelp.dll. DbgHelpGuard dbgHelpGuard; D3DInterface = Direct3DCreate8Ptr(D3D_SDK_VERSION); // TODO: handle failure cases... @@ -598,7 +599,8 @@ bool DX8Wrapper::Create_Device(void) HRESULT hr; { - // TheSuperHackers @bugfix xezon 13/06/2025 Temporarily unload dbghelp.dll and prevent it from loading. + // TheSuperHackers @bugfix xezon 13/06/2025 Front load the system dbghelp.dll + // to prevent the graphics driver from potentially loading the old game dbghelp.dll. DbgHelpGuard dbgHelpGuard; hr=D3DInterface->CreateDevice From 071dd7cd6422fe9bb0dd2d93ff5e42ab168e28ff Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Wed, 8 Oct 2025 19:33:56 +0200 Subject: [PATCH 05/20] Use leading tabs --- .../Source/WWVegas/WWLib/DbgHelpLoader.cpp | 336 +++++++++--------- .../Source/WWVegas/WWLib/DbgHelpLoader.h | 274 +++++++------- .../Source/WWVegas/WWLib/MallocAllocator.h | 120 +++---- 3 files changed, 365 insertions(+), 365 deletions(-) diff --git a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp index 4449ff15a60..31e8fa82e86 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp +++ b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp @@ -22,19 +22,19 @@ DbgHelpLoader* DbgHelpLoader::Inst = NULL; DbgHelpLoader::DbgHelpLoader() - : m_symInitialize(NULL) - , m_symCleanup(NULL) - , m_symLoadModule(NULL) - , m_symUnloadModule(NULL) - , m_symGetModuleBase(NULL) - , m_symGetSymFromAddr(NULL) - , m_symGetLineFromAddr(NULL) - , m_symSetOptions(NULL) - , m_symFunctionTableAccess(NULL) - , m_stackWalk(NULL) - , m_dllModule(HMODULE(0)) - , m_failed(false) - , m_loadedFromSystem(false) + : m_symInitialize(NULL) + , m_symCleanup(NULL) + , m_symLoadModule(NULL) + , m_symUnloadModule(NULL) + , m_symGetModuleBase(NULL) + , m_symGetSymFromAddr(NULL) + , m_symGetLineFromAddr(NULL) + , m_symSetOptions(NULL) + , m_symFunctionTableAccess(NULL) + , m_stackWalk(NULL) + , m_dllModule(HMODULE(0)) + , m_failed(false) + , m_loadedFromSystem(false) { } @@ -44,226 +44,226 @@ DbgHelpLoader::~DbgHelpLoader() bool DbgHelpLoader::isLoaded() { - return Inst != NULL && Inst->m_dllModule != HMODULE(0); + return Inst != NULL && Inst->m_dllModule != HMODULE(0); } bool DbgHelpLoader::isLoadedFromSystem() { - return Inst != NULL && Inst->m_loadedFromSystem; + return Inst != NULL && Inst->m_loadedFromSystem; } bool DbgHelpLoader::load() { - if (Inst == NULL) - { - // Cannot use new/delete here when this is loaded during game memory initialization. - void* p = ::malloc(sizeof(DbgHelpLoader)); - Inst = new (p) DbgHelpLoader(); - } - - // Optimization: return early if it failed before. - if (Inst->m_failed) - return false; - - // Try load dbghelp.dll from the system directory first. - char dllFilename[MAX_PATH]; - ::GetSystemDirectoryA(dllFilename, ARRAY_SIZE(dllFilename)); - strcat(dllFilename, "\\dbghelp.dll"); - - Inst->m_dllModule = ::LoadLibraryA(dllFilename); - if (Inst->m_dllModule == HMODULE(0)) - { - // Not found. Try load dbghelp.dll from the work directory. - Inst->m_dllModule = ::LoadLibraryA("dbghelp.dll"); - if (Inst->m_dllModule == HMODULE(0)) - { - Inst->m_failed = true; - return false; - } - } - else - { - Inst->m_loadedFromSystem = true; - } - - Inst->m_symInitialize = reinterpret_cast(::GetProcAddress(Inst->m_dllModule, "SymInitialize")); - Inst->m_symCleanup = reinterpret_cast(::GetProcAddress(Inst->m_dllModule, "SymCleanup")); - Inst->m_symLoadModule = reinterpret_cast(::GetProcAddress(Inst->m_dllModule, "SymLoadModule")); - Inst->m_symUnloadModule = reinterpret_cast(::GetProcAddress(Inst->m_dllModule, "SymUnloadModule")); - Inst->m_symGetModuleBase = reinterpret_cast(::GetProcAddress(Inst->m_dllModule, "SymGetModuleBase")); - Inst->m_symGetSymFromAddr = reinterpret_cast(::GetProcAddress(Inst->m_dllModule, "SymGetSymFromAddr")); - Inst->m_symGetLineFromAddr = reinterpret_cast(::GetProcAddress(Inst->m_dllModule, "SymGetLineFromAddr")); - Inst->m_symSetOptions = reinterpret_cast(::GetProcAddress(Inst->m_dllModule, "SymSetOptions")); - Inst->m_symFunctionTableAccess = reinterpret_cast(::GetProcAddress(Inst->m_dllModule, "SymFunctionTableAccess")); - Inst->m_stackWalk = reinterpret_cast(::GetProcAddress(Inst->m_dllModule, "StackWalk")); - - if (Inst->m_symInitialize == NULL || Inst->m_symCleanup == NULL) - { - unload(); - Inst->m_failed = true; - return false; - } - - return true; + if (Inst == NULL) + { + // Cannot use new/delete here when this is loaded during game memory initialization. + void* p = ::malloc(sizeof(DbgHelpLoader)); + Inst = new (p) DbgHelpLoader(); + } + + // Optimization: return early if it failed before. + if (Inst->m_failed) + return false; + + // Try load dbghelp.dll from the system directory first. + char dllFilename[MAX_PATH]; + ::GetSystemDirectoryA(dllFilename, ARRAY_SIZE(dllFilename)); + strcat(dllFilename, "\\dbghelp.dll"); + + Inst->m_dllModule = ::LoadLibraryA(dllFilename); + if (Inst->m_dllModule == HMODULE(0)) + { + // Not found. Try load dbghelp.dll from the work directory. + Inst->m_dllModule = ::LoadLibraryA("dbghelp.dll"); + if (Inst->m_dllModule == HMODULE(0)) + { + Inst->m_failed = true; + return false; + } + } + else + { + Inst->m_loadedFromSystem = true; + } + + Inst->m_symInitialize = reinterpret_cast(::GetProcAddress(Inst->m_dllModule, "SymInitialize")); + Inst->m_symCleanup = reinterpret_cast(::GetProcAddress(Inst->m_dllModule, "SymCleanup")); + Inst->m_symLoadModule = reinterpret_cast(::GetProcAddress(Inst->m_dllModule, "SymLoadModule")); + Inst->m_symUnloadModule = reinterpret_cast(::GetProcAddress(Inst->m_dllModule, "SymUnloadModule")); + Inst->m_symGetModuleBase = reinterpret_cast(::GetProcAddress(Inst->m_dllModule, "SymGetModuleBase")); + Inst->m_symGetSymFromAddr = reinterpret_cast(::GetProcAddress(Inst->m_dllModule, "SymGetSymFromAddr")); + Inst->m_symGetLineFromAddr = reinterpret_cast(::GetProcAddress(Inst->m_dllModule, "SymGetLineFromAddr")); + Inst->m_symSetOptions = reinterpret_cast(::GetProcAddress(Inst->m_dllModule, "SymSetOptions")); + Inst->m_symFunctionTableAccess = reinterpret_cast(::GetProcAddress(Inst->m_dllModule, "SymFunctionTableAccess")); + Inst->m_stackWalk = reinterpret_cast(::GetProcAddress(Inst->m_dllModule, "StackWalk")); + + if (Inst->m_symInitialize == NULL || Inst->m_symCleanup == NULL) + { + unload(); + Inst->m_failed = true; + return false; + } + + return true; } bool DbgHelpLoader::reload() { - unload(); - return load(); + unload(); + return load(); } void DbgHelpLoader::unload() { - if (Inst == NULL) - return; - - while (!Inst->m_initializedProcesses.empty()) - { - symCleanup(*Inst->m_initializedProcesses.begin()); - } - - if (Inst->m_dllModule != HMODULE(0)) - { - ::FreeLibrary(Inst->m_dllModule); - Inst->m_dllModule = HMODULE(0); - } - - Inst->~DbgHelpLoader(); - ::free(Inst); - Inst = NULL; + if (Inst == NULL) + return; + + while (!Inst->m_initializedProcesses.empty()) + { + symCleanup(*Inst->m_initializedProcesses.begin()); + } + + if (Inst->m_dllModule != HMODULE(0)) + { + ::FreeLibrary(Inst->m_dllModule); + Inst->m_dllModule = HMODULE(0); + } + + Inst->~DbgHelpLoader(); + ::free(Inst); + Inst = NULL; } BOOL DbgHelpLoader::symInitialize( - HANDLE hProcess, - LPSTR UserSearchPath, - BOOL fInvadeProcess) + HANDLE hProcess, + LPSTR UserSearchPath, + BOOL fInvadeProcess) { - if (Inst == NULL) - return FALSE; - - if (Inst->m_initializedProcesses.find(hProcess) != Inst->m_initializedProcesses.end()) - return FALSE; - - if (Inst->m_symInitialize) - { - if (Inst->m_symInitialize(hProcess, UserSearchPath, fInvadeProcess) != FALSE) - { - Inst->m_initializedProcesses.insert(hProcess); - return TRUE; - } - } - - return FALSE; + if (Inst == NULL) + return FALSE; + + if (Inst->m_initializedProcesses.find(hProcess) != Inst->m_initializedProcesses.end()) + return FALSE; + + if (Inst->m_symInitialize) + { + if (Inst->m_symInitialize(hProcess, UserSearchPath, fInvadeProcess) != FALSE) + { + Inst->m_initializedProcesses.insert(hProcess); + return TRUE; + } + } + + return FALSE; } BOOL DbgHelpLoader::symCleanup( - HANDLE hProcess) + HANDLE hProcess) { - if (Inst == NULL) - return FALSE; + if (Inst == NULL) + return FALSE; - // @todo stl::find_and_erase - Processes::iterator it = Inst->m_initializedProcesses.find(hProcess); - if (it != Inst->m_initializedProcesses.end()) - Inst->m_initializedProcesses.erase(it); + // @todo stl::find_and_erase + Processes::iterator it = Inst->m_initializedProcesses.find(hProcess); + if (it != Inst->m_initializedProcesses.end()) + Inst->m_initializedProcesses.erase(it); - if (Inst->m_symCleanup) - return Inst->m_symCleanup(hProcess); + if (Inst->m_symCleanup) + return Inst->m_symCleanup(hProcess); - return FALSE; + return FALSE; } BOOL DbgHelpLoader::symLoadModule( - HANDLE hProcess, - HANDLE hFile, - LPSTR ImageName, - LPSTR ModuleName, - DWORD BaseOfDll, - DWORD SizeOfDll) + HANDLE hProcess, + HANDLE hFile, + LPSTR ImageName, + LPSTR ModuleName, + DWORD BaseOfDll, + DWORD SizeOfDll) { - if (Inst != NULL && Inst->m_symLoadModule) - return Inst->m_symLoadModule(hProcess, hFile, ImageName, ModuleName, BaseOfDll, SizeOfDll); + if (Inst != NULL && Inst->m_symLoadModule) + return Inst->m_symLoadModule(hProcess, hFile, ImageName, ModuleName, BaseOfDll, SizeOfDll); - return FALSE; + return FALSE; } DWORD DbgHelpLoader::symGetModuleBase( - HANDLE hProcess, - DWORD dwAddr) + HANDLE hProcess, + DWORD dwAddr) { - if (Inst != NULL && Inst->m_symGetModuleBase) - return Inst->m_symGetModuleBase(hProcess, dwAddr); + if (Inst != NULL && Inst->m_symGetModuleBase) + return Inst->m_symGetModuleBase(hProcess, dwAddr); - return 0u; + return 0u; } BOOL DbgHelpLoader::symUnloadModule( - HANDLE hProcess, - DWORD BaseOfDll) + HANDLE hProcess, + DWORD BaseOfDll) { - if (Inst != NULL && Inst->m_symUnloadModule) - return Inst->m_symUnloadModule(hProcess, BaseOfDll); + if (Inst != NULL && Inst->m_symUnloadModule) + return Inst->m_symUnloadModule(hProcess, BaseOfDll); - return FALSE; + return FALSE; } BOOL DbgHelpLoader::symGetSymFromAddr( - HANDLE hProcess, - DWORD Address, - LPDWORD Displacement, - PIMAGEHLP_SYMBOL Symbol) + HANDLE hProcess, + DWORD Address, + LPDWORD Displacement, + PIMAGEHLP_SYMBOL Symbol) { - if (Inst != NULL && Inst->m_symGetSymFromAddr) - return Inst->m_symGetSymFromAddr(hProcess, Address, Displacement, Symbol); + if (Inst != NULL && Inst->m_symGetSymFromAddr) + return Inst->m_symGetSymFromAddr(hProcess, Address, Displacement, Symbol); - return FALSE; + return FALSE; } BOOL DbgHelpLoader::symGetLineFromAddr( - HANDLE hProcess, - DWORD dwAddr, - PDWORD pdwDisplacement, - PIMAGEHLP_LINE Line) + HANDLE hProcess, + DWORD dwAddr, + PDWORD pdwDisplacement, + PIMAGEHLP_LINE Line) { - if (Inst != NULL && Inst->m_symGetLineFromAddr) - return Inst->m_symGetLineFromAddr(hProcess, dwAddr, pdwDisplacement, Line); + if (Inst != NULL && Inst->m_symGetLineFromAddr) + return Inst->m_symGetLineFromAddr(hProcess, dwAddr, pdwDisplacement, Line); - return FALSE; + return FALSE; } DWORD DbgHelpLoader::symSetOptions( - DWORD SymOptions) + DWORD SymOptions) { - if (Inst != NULL && Inst->m_symSetOptions) - return Inst->m_symSetOptions(SymOptions); + if (Inst != NULL && Inst->m_symSetOptions) + return Inst->m_symSetOptions(SymOptions); - return 0u; + return 0u; } LPVOID DbgHelpLoader::symFunctionTableAccess( - HANDLE hProcess, - DWORD AddrBase) + HANDLE hProcess, + DWORD AddrBase) { - if (Inst != NULL && Inst->m_symFunctionTableAccess) - return Inst->m_symFunctionTableAccess(hProcess, AddrBase); + if (Inst != NULL && Inst->m_symFunctionTableAccess) + return Inst->m_symFunctionTableAccess(hProcess, AddrBase); - return NULL; + return NULL; } BOOL DbgHelpLoader::stackWalk( - DWORD MachineType, - HANDLE hProcess, - HANDLE hThread, - LPSTACKFRAME StackFrame, - LPVOID ContextRecord, - PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine, - PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine, - PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine, - PTRANSLATE_ADDRESS_ROUTINE TranslateAddress) + DWORD MachineType, + HANDLE hProcess, + HANDLE hThread, + LPSTACKFRAME StackFrame, + LPVOID ContextRecord, + PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine, + PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine, + PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine, + PTRANSLATE_ADDRESS_ROUTINE TranslateAddress) { - if (Inst != NULL && Inst->m_stackWalk) - return Inst->m_stackWalk(MachineType, hProcess, hThread, StackFrame, ContextRecord, ReadMemoryRoutine, FunctionTableAccessRoutine, GetModuleBaseRoutine, TranslateAddress); + if (Inst != NULL && Inst->m_stackWalk) + return Inst->m_stackWalk(MachineType, hProcess, hThread, StackFrame, ContextRecord, ReadMemoryRoutine, FunctionTableAccessRoutine, GetModuleBaseRoutine, TranslateAddress); - return FALSE; + return FALSE; } diff --git a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.h b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.h index 3a7d9cafa90..ab5780b96c9 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.h +++ b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.h @@ -33,148 +33,148 @@ class DbgHelpLoader { private: - static DbgHelpLoader* Inst; // Is singleton class + static DbgHelpLoader* Inst; // Is singleton class - DbgHelpLoader(); - ~DbgHelpLoader(); + DbgHelpLoader(); + ~DbgHelpLoader(); public: - // Returns whether dbghelp.dll is loaded - static bool isLoaded(); - - // Returns whether dbghelp.dll is loaded from the system directory - static bool isLoadedFromSystem(); - - static bool load(); - static bool reload(); - static void unload(); - - static BOOL WINAPI symInitialize( - HANDLE hProcess, - LPSTR UserSearchPath, - BOOL fInvadeProcess); - - static BOOL WINAPI symCleanup( - HANDLE hProcess); - - static BOOL WINAPI symLoadModule( - HANDLE hProcess, - HANDLE hFile, - LPSTR ImageName, - LPSTR ModuleName, - DWORD BaseOfDll, - DWORD SizeOfDll); - - static DWORD WINAPI symGetModuleBase( - HANDLE hProcess, - DWORD dwAddr); - - static BOOL WINAPI symUnloadModule( - HANDLE hProcess, - DWORD BaseOfDll); - - static BOOL WINAPI symGetSymFromAddr( - HANDLE hProcess, - DWORD Address, - LPDWORD Displacement, - PIMAGEHLP_SYMBOL Symbol); - - static BOOL WINAPI symGetLineFromAddr( - HANDLE hProcess, - DWORD dwAddr, - PDWORD pdwDisplacement, - PIMAGEHLP_LINE Line); - - static DWORD WINAPI symSetOptions( - DWORD SymOptions); - - static LPVOID WINAPI symFunctionTableAccess( - HANDLE hProcess, - DWORD AddrBase); - - static BOOL WINAPI stackWalk( - DWORD MachineType, - HANDLE hProcess, - HANDLE hThread, - LPSTACKFRAME StackFrame, - LPVOID ContextRecord, - PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine, - PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine, - PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine, - PTRANSLATE_ADDRESS_ROUTINE TranslateAddress); + // Returns whether dbghelp.dll is loaded + static bool isLoaded(); + + // Returns whether dbghelp.dll is loaded from the system directory + static bool isLoadedFromSystem(); + + static bool load(); + static bool reload(); + static void unload(); + + static BOOL WINAPI symInitialize( + HANDLE hProcess, + LPSTR UserSearchPath, + BOOL fInvadeProcess); + + static BOOL WINAPI symCleanup( + HANDLE hProcess); + + static BOOL WINAPI symLoadModule( + HANDLE hProcess, + HANDLE hFile, + LPSTR ImageName, + LPSTR ModuleName, + DWORD BaseOfDll, + DWORD SizeOfDll); + + static DWORD WINAPI symGetModuleBase( + HANDLE hProcess, + DWORD dwAddr); + + static BOOL WINAPI symUnloadModule( + HANDLE hProcess, + DWORD BaseOfDll); + + static BOOL WINAPI symGetSymFromAddr( + HANDLE hProcess, + DWORD Address, + LPDWORD Displacement, + PIMAGEHLP_SYMBOL Symbol); + + static BOOL WINAPI symGetLineFromAddr( + HANDLE hProcess, + DWORD dwAddr, + PDWORD pdwDisplacement, + PIMAGEHLP_LINE Line); + + static DWORD WINAPI symSetOptions( + DWORD SymOptions); + + static LPVOID WINAPI symFunctionTableAccess( + HANDLE hProcess, + DWORD AddrBase); + + static BOOL WINAPI stackWalk( + DWORD MachineType, + HANDLE hProcess, + HANDLE hThread, + LPSTACKFRAME StackFrame, + LPVOID ContextRecord, + PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine, + PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine, + PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine, + PTRANSLATE_ADDRESS_ROUTINE TranslateAddress); private: - typedef BOOL (WINAPI *SymInitialize_t) ( - HANDLE hProcess, - LPSTR UserSearchPath, - BOOL fInvadeProcess); - - typedef BOOL (WINAPI *SymCleanup_t) ( - HANDLE hProcess); - - typedef BOOL (WINAPI *SymLoadModule_t) ( - HANDLE hProcess, - HANDLE hFile, - LPSTR ImageName, - LPSTR ModuleName, - DWORD BaseOfDll, - DWORD SizeOfDll); - - typedef DWORD (WINAPI *SymGetModuleBase_t) ( - HANDLE hProcess, - DWORD dwAddr); - - typedef BOOL (WINAPI *SymUnloadModule_t) ( - HANDLE hProcess, - DWORD BaseOfDll); - - typedef BOOL (WINAPI *SymGetSymFromAddr_t) ( - HANDLE hProcess, - DWORD Address, - LPDWORD Displacement, - PIMAGEHLP_SYMBOL Symbol); - - typedef BOOL (WINAPI* SymGetLineFromAddr_t) ( - HANDLE hProcess, - DWORD dwAddr, - PDWORD pdwDisplacement, - PIMAGEHLP_LINE Line); - - typedef DWORD (WINAPI *SymSetOptions_t) ( - DWORD SymOptions); - - typedef LPVOID (WINAPI *SymFunctionTableAccess_t) ( - HANDLE hProcess, - DWORD AddrBase); - - typedef BOOL (WINAPI *StackWalk_t) ( - DWORD MachineType, - HANDLE hProcess, - HANDLE hThread, - LPSTACKFRAME StackFrame, - LPVOID ContextRecord, - PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine, - PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine, - PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine, - PTRANSLATE_ADDRESS_ROUTINE TranslateAddress); - - SymInitialize_t m_symInitialize; - SymCleanup_t m_symCleanup; - SymLoadModule_t m_symLoadModule; - SymUnloadModule_t m_symUnloadModule; - SymGetModuleBase_t m_symGetModuleBase; - SymGetSymFromAddr_t m_symGetSymFromAddr; - SymGetLineFromAddr_t m_symGetLineFromAddr; - SymSetOptions_t m_symSetOptions; - SymFunctionTableAccess_t m_symFunctionTableAccess; - StackWalk_t m_stackWalk; - - typedef std::set, stl::malloc_allocator > Processes; - - Processes m_initializedProcesses; - HMODULE m_dllModule; - bool m_failed; - bool m_loadedFromSystem; + typedef BOOL (WINAPI *SymInitialize_t) ( + HANDLE hProcess, + LPSTR UserSearchPath, + BOOL fInvadeProcess); + + typedef BOOL (WINAPI *SymCleanup_t) ( + HANDLE hProcess); + + typedef BOOL (WINAPI *SymLoadModule_t) ( + HANDLE hProcess, + HANDLE hFile, + LPSTR ImageName, + LPSTR ModuleName, + DWORD BaseOfDll, + DWORD SizeOfDll); + + typedef DWORD (WINAPI *SymGetModuleBase_t) ( + HANDLE hProcess, + DWORD dwAddr); + + typedef BOOL (WINAPI *SymUnloadModule_t) ( + HANDLE hProcess, + DWORD BaseOfDll); + + typedef BOOL (WINAPI *SymGetSymFromAddr_t) ( + HANDLE hProcess, + DWORD Address, + LPDWORD Displacement, + PIMAGEHLP_SYMBOL Symbol); + + typedef BOOL (WINAPI* SymGetLineFromAddr_t) ( + HANDLE hProcess, + DWORD dwAddr, + PDWORD pdwDisplacement, + PIMAGEHLP_LINE Line); + + typedef DWORD (WINAPI *SymSetOptions_t) ( + DWORD SymOptions); + + typedef LPVOID (WINAPI *SymFunctionTableAccess_t) ( + HANDLE hProcess, + DWORD AddrBase); + + typedef BOOL (WINAPI *StackWalk_t) ( + DWORD MachineType, + HANDLE hProcess, + HANDLE hThread, + LPSTACKFRAME StackFrame, + LPVOID ContextRecord, + PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine, + PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine, + PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine, + PTRANSLATE_ADDRESS_ROUTINE TranslateAddress); + + SymInitialize_t m_symInitialize; + SymCleanup_t m_symCleanup; + SymLoadModule_t m_symLoadModule; + SymUnloadModule_t m_symUnloadModule; + SymGetModuleBase_t m_symGetModuleBase; + SymGetSymFromAddr_t m_symGetSymFromAddr; + SymGetLineFromAddr_t m_symGetLineFromAddr; + SymSetOptions_t m_symSetOptions; + SymFunctionTableAccess_t m_symFunctionTableAccess; + StackWalk_t m_stackWalk; + + typedef std::set, stl::malloc_allocator > Processes; + + Processes m_initializedProcesses; + HMODULE m_dllModule; + bool m_failed; + bool m_loadedFromSystem; }; diff --git a/Core/Libraries/Source/WWVegas/WWLib/MallocAllocator.h b/Core/Libraries/Source/WWVegas/WWLib/MallocAllocator.h index e465b0ad5d1..c56c955508c 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/MallocAllocator.h +++ b/Core/Libraries/Source/WWVegas/WWLib/MallocAllocator.h @@ -33,75 +33,75 @@ class malloc_allocator { public: - typedef T value_type; - typedef T* pointer; - typedef const T* const_pointer; - typedef T& reference; - typedef const T& const_reference; - typedef std::size_t size_type; - typedef std::ptrdiff_t difference_type; - - template - struct rebind - { - typedef malloc_allocator other; - }; - - malloc_allocator() throw() {} + typedef T value_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + template + struct rebind + { + typedef malloc_allocator other; + }; + + malloc_allocator() throw() {} #if !(defined(_MSC_VER) && _MSC_VER < 1300) - malloc_allocator(const malloc_allocator&) throw() {} + malloc_allocator(const malloc_allocator&) throw() {} #endif - template - malloc_allocator(const malloc_allocator&) throw() {} + template + malloc_allocator(const malloc_allocator&) throw() {} - ~malloc_allocator() throw() {} + ~malloc_allocator() throw() {} - pointer address(reference x) const { return &x; } - const_pointer address(const_reference x) const { return &x; } + pointer address(reference x) const { return &x; } + const_pointer address(const_reference x) const { return &x; } - pointer allocate(size_type n, const void* = 0) - { - if (n > max_size()) - throw std::bad_alloc(); + pointer allocate(size_type n, const void* = 0) + { + if (n > max_size()) + throw std::bad_alloc(); - void* p = ::malloc(n * sizeof(T)); - if (!p) - throw std::bad_alloc(); - return static_cast(p); - } + void* p = ::malloc(n * sizeof(T)); + if (!p) + throw std::bad_alloc(); + return static_cast(p); + } - void deallocate(pointer p, size_type) - { - ::free(p); - } + void deallocate(pointer p, size_type) + { + ::free(p); + } - void construct(pointer p, const T& val) - { - new (static_cast(p)) T(val); - } + void construct(pointer p, const T& val) + { + new (static_cast(p)) T(val); + } - void destroy(pointer p) - { - p->~T(); - } + void destroy(pointer p) + { + p->~T(); + } - size_type max_size() const throw() - { - return ~size_type(0) / sizeof(T); - } + size_type max_size() const throw() + { + return ~size_type(0) / sizeof(T); + } }; // Allocators of same type are always equal template bool operator==(const malloc_allocator&, const malloc_allocator&) throw() { - return true; + return true; } template bool operator!=(const malloc_allocator&, const malloc_allocator&) throw() { - return false; + return false; } } // namespace stl @@ -112,18 +112,18 @@ bool operator!=(const malloc_allocator&, const malloc_allocator&) throw( // This tells STLport how to rebind malloc_allocator namespace std { - template - struct __stl_alloc_rebind_helper; - - template - inline stl::malloc_allocator& __stl_alloc_rebind(stl::malloc_allocator& a, const Tp2*) { - return *reinterpret_cast*>(&a); - } - - template - inline const stl::malloc_allocator& __stl_alloc_rebind(const stl::malloc_allocator& a, const Tp2*) { - return *reinterpret_cast*>(&a); - } + template + struct __stl_alloc_rebind_helper; + + template + inline stl::malloc_allocator& __stl_alloc_rebind(stl::malloc_allocator& a, const Tp2*) { + return *reinterpret_cast*>(&a); + } + + template + inline const stl::malloc_allocator& __stl_alloc_rebind(const stl::malloc_allocator& a, const Tp2*) { + return *reinterpret_cast*>(&a); + } } #endif From 04007497dca06fb20cdf0e11731332c147a1b76d Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Wed, 8 Oct 2025 19:54:57 +0200 Subject: [PATCH 06/20] Use strlcat --- Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp index 31e8fa82e86..0ec68c4f39e 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp +++ b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp @@ -68,7 +68,7 @@ bool DbgHelpLoader::load() // Try load dbghelp.dll from the system directory first. char dllFilename[MAX_PATH]; ::GetSystemDirectoryA(dllFilename, ARRAY_SIZE(dllFilename)); - strcat(dllFilename, "\\dbghelp.dll"); + strlcat(dllFilename, "\\dbghelp.dll", ARRAY_SIZE(dllFilename)); Inst->m_dllModule = ::LoadLibraryA(dllFilename); if (Inst->m_dllModule == HMODULE(0)) From 9a40fb7ac67f7db992ee6185824f43e63e372d21 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Wed, 8 Oct 2025 19:55:26 +0200 Subject: [PATCH 07/20] Use stl::find_and_erase --- Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp index 0ec68c4f39e..b1eed2d5fc7 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp +++ b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp @@ -163,10 +163,7 @@ BOOL DbgHelpLoader::symCleanup( if (Inst == NULL) return FALSE; - // @todo stl::find_and_erase - Processes::iterator it = Inst->m_initializedProcesses.find(hProcess); - if (it != Inst->m_initializedProcesses.end()) - Inst->m_initializedProcesses.erase(it); + stl::find_and_erase(Inst->m_initializedProcesses, hProcess); if (Inst->m_symCleanup) return Inst->m_symCleanup(hProcess); From c101568f46970f21315a8e830513121acc05582c Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Wed, 8 Oct 2025 20:02:00 +0200 Subject: [PATCH 08/20] Improve DbgHelpLoader --- .../Source/WWVegas/WWLib/DbgHelpLoader.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp index b1eed2d5fc7..d1bcef2e3c4 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp +++ b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp @@ -143,12 +143,16 @@ BOOL DbgHelpLoader::symInitialize( return FALSE; if (Inst->m_initializedProcesses.find(hProcess) != Inst->m_initializedProcesses.end()) - return FALSE; + { + // Was already initialized. + return TRUE; + } if (Inst->m_symInitialize) { if (Inst->m_symInitialize(hProcess, UserSearchPath, fInvadeProcess) != FALSE) { + // Is now initialized. Inst->m_initializedProcesses.insert(hProcess); return TRUE; } @@ -163,10 +167,13 @@ BOOL DbgHelpLoader::symCleanup( if (Inst == NULL) return FALSE; - stl::find_and_erase(Inst->m_initializedProcesses, hProcess); - - if (Inst->m_symCleanup) - return Inst->m_symCleanup(hProcess); + if (stl::find_and_erase(Inst->m_initializedProcesses, hProcess)) + { + if (Inst->m_symCleanup) + { + return Inst->m_symCleanup(hProcess); + } + } return FALSE; } From e7a99e600ac4a29cac7b2e36f55f96452be30e23 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Wed, 8 Oct 2025 20:06:53 +0200 Subject: [PATCH 09/20] Fix trailing whitespace --- Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp | 2 +- GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 0b012124bfd..03c498e7920 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -578,7 +578,7 @@ bool DX8Wrapper::Create_Device(void) _Hwnd, Vertex_Processing_Behavior, &_PresentParameters, - &D3DDevice + &D3DDevice ); } diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 16d085081bc..548fa59ec9c 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -610,7 +610,7 @@ bool DX8Wrapper::Create_Device(void) _Hwnd, Vertex_Processing_Behavior, &_PresentParameters, - &D3DDevice + &D3DDevice ); } From 753790632f7ec3f058a29873a413f8ae5df89d9b Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Thu, 9 Oct 2025 21:09:10 +0200 Subject: [PATCH 10/20] Simplify lib load with LOAD_LIBRARY_SEARCH_SYSTEM32 --- Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp index d1bcef2e3c4..650304573af 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp +++ b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp @@ -66,14 +66,10 @@ bool DbgHelpLoader::load() return false; // Try load dbghelp.dll from the system directory first. - char dllFilename[MAX_PATH]; - ::GetSystemDirectoryA(dllFilename, ARRAY_SIZE(dllFilename)); - strlcat(dllFilename, "\\dbghelp.dll", ARRAY_SIZE(dllFilename)); - - Inst->m_dllModule = ::LoadLibraryA(dllFilename); + Inst->m_dllModule = ::LoadLibraryExA("dbghelp.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); if (Inst->m_dllModule == HMODULE(0)) { - // Not found. Try load dbghelp.dll from the work directory. + // Not found. Try load dbghelp.dll from the work directory or wherever else it will be looking. Inst->m_dllModule = ::LoadLibraryA("dbghelp.dll"); if (Inst->m_dllModule == HMODULE(0)) { From d362366d7ed131a40c501ef43c236b8a36685621 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Fri, 10 Oct 2025 19:58:47 +0200 Subject: [PATCH 11/20] Replace MallocAllocator with SystemAllocator --- Core/GameEngine/CMakeLists.txt | 1 + Core/GameEngine/Include/Common/GameMemory.h | 15 +++ .../Source/Common/System/GameMemory.cpp | 95 +------------- .../Source/Common/System/GameMemoryCommon.cpp | 121 ++++++++++++++++++ .../Source/WWVegas/WWLib/CMakeLists.txt | 2 +- .../Source/WWVegas/WWLib/DbgHelpLoader.cpp | 4 +- .../Source/WWVegas/WWLib/DbgHelpLoader.h | 4 +- .../{MallocAllocator.h => SystemAllocator.h} | 32 ++--- Core/Libraries/Source/WWVegas/WWLib/always.h | 3 + 9 files changed, 166 insertions(+), 111 deletions(-) create mode 100644 Core/GameEngine/Source/Common/System/GameMemoryCommon.cpp rename Core/Libraries/Source/WWVegas/WWLib/{MallocAllocator.h => SystemAllocator.h} (69%) diff --git a/Core/GameEngine/CMakeLists.txt b/Core/GameEngine/CMakeLists.txt index 0a58dfc4315..362c5be8f86 100644 --- a/Core/GameEngine/CMakeLists.txt +++ b/Core/GameEngine/CMakeLists.txt @@ -651,6 +651,7 @@ set(GAMEENGINE_SRC # Source/Common/System/FunctionLexicon.cpp # Source/Common/System/GameCommon.cpp #Source/Common/System/GameMemory.cpp # is conditionally appended + Source/Common/System/GameMemoryCommon.cpp #Source/Common/System/GameMemoryInit.cpp # is conditionally appended # Source/Common/System/GameType.cpp # Source/Common/System/Geometry.cpp diff --git a/Core/GameEngine/Include/Common/GameMemory.h b/Core/GameEngine/Include/Common/GameMemory.h index 65b1732e527..92f1ea2a911 100644 --- a/Core/GameEngine/Include/Common/GameMemory.h +++ b/Core/GameEngine/Include/Common/GameMemory.h @@ -177,8 +177,23 @@ }; +#define USE_FILLER_VALUE + #endif // MEMORYPOOL_DEBUG +extern Int thePeakSystemAllocationInBytes; + +// TheSuperHackers @tweak The system allocator functions are now global. +// Use this to bypass Game Memory Pools in exceptional circumstances. +extern void* sysAllocateDoNotZero(size_t numBytes); +extern void sysFree(void* p); +extern void memset32(void* ptr, Int value, size_t bytesToFill); + +#ifdef USE_FILLER_VALUE +extern UnsignedInt s_initFillerValue; +extern void calcFillerValue(Int index); +#endif + // TheSuperHackers @build xezon 30/03/2025 Define DISABLE_GAMEMEMORY to use a null implementations for Game Memory. // Useful for address sanitizer checks and other investigations. // Is included below the macros so that memory pool debug code can still be used. diff --git a/Core/GameEngine/Source/Common/System/GameMemory.cpp b/Core/GameEngine/Source/Common/System/GameMemory.cpp index 8fcf71b1388..123ce33b31d 100644 --- a/Core/GameEngine/Source/Common/System/GameMemory.cpp +++ b/Core/GameEngine/Source/Common/System/GameMemory.cpp @@ -114,21 +114,7 @@ DECLARE_PERF_TIMER(MemoryPoolInitFilling) #define MEMORYPOOL_SINGLEBLOCK_GETS_STACKTRACE #endif - #define USE_FILLER_VALUE - const Int MAX_INIT_FILLER_COUNT = 8; - #ifdef USE_FILLER_VALUE - static UnsignedInt s_initFillerValue = 0xf00dcafe; // will be replaced, should never be this value at runtime - static void calcFillerValue(Int index) - { - s_initFillerValue = (index & 3) << 1; - s_initFillerValue |= 0x01; - s_initFillerValue |= (~(s_initFillerValue << 4)) & 0xf0; - s_initFillerValue |= (s_initFillerValue << 8); - s_initFillerValue |= (s_initFillerValue << 16); - //DEBUG_LOG(("Setting MemoryPool initFillerValue to %08x (index %d)",s_initFillerValue,index)); - } - #endif #endif @@ -169,8 +155,6 @@ DECLARE_PERF_TIMER(MemoryPoolInitFilling) #ifdef MEMORYPOOL_DEBUG - static Int theTotalSystemAllocationInBytes = 0; - static Int thePeakSystemAllocationInBytes = 0; static Int theTotalLargeBlocks = 0; static Int thePeakLargeBlocks = 0; Int theTotalDMA = 0; @@ -203,9 +187,7 @@ static Bool theMainInitFlag = false; #define MEM_BOUND_ALIGNMENT 4 static Int roundUpMemBound(Int i); -static void *sysAllocateDoNotZero(Int numBytes); -static void sysFree(void* p); -static void memset32(void* ptr, Int value, Int bytesToFill); + #ifdef MEMORYPOOL_STACKTRACE static void doStackDumpOutput(const char* m); static void doStackDump(void **stacktrace, int size); @@ -223,73 +205,6 @@ static Int roundUpMemBound(Int i) return (i + (MEM_BOUND_ALIGNMENT-1)) & ~(MEM_BOUND_ALIGNMENT-1); } -//----------------------------------------------------------------------------- -/** - this is the low-level allocator that we use to request memory from the OS. - all (repeat, all) memory allocations in this module should ultimately - go thru this routine (or sysAllocate). - - note: throws ERROR_OUT_OF_MEMORY on failure; never returns null -*/ -static void* sysAllocateDoNotZero(Int numBytes) -{ - void* p = ::GlobalAlloc(GMEM_FIXED, numBytes); - if (!p) - throw ERROR_OUT_OF_MEMORY; -#ifdef MEMORYPOOL_DEBUG - { - USE_PERF_TIMER(MemoryPoolDebugging) - #ifdef USE_FILLER_VALUE - { - USE_PERF_TIMER(MemoryPoolInitFilling) - ::memset32(p, s_initFillerValue, ::GlobalSize(p)); - } - #endif - theTotalSystemAllocationInBytes += ::GlobalSize(p); - if (thePeakSystemAllocationInBytes < theTotalSystemAllocationInBytes) - thePeakSystemAllocationInBytes = theTotalSystemAllocationInBytes; - } -#endif - return p; -} - -//----------------------------------------------------------------------------- -/** - the counterpart to sysAllocate / sysAllocateDoNotZero; used to free blocks - allocated by them. it is OK to pass null here (it will just be ignored). -*/ -static void sysFree(void* p) -{ - if (p) - { -#ifdef MEMORYPOOL_DEBUG - { - USE_PERF_TIMER(MemoryPoolDebugging) - ::memset32(p, GARBAGE_FILL_VALUE, ::GlobalSize(p)); - theTotalSystemAllocationInBytes -= ::GlobalSize(p); - } -#endif - ::GlobalFree(p); - } -} - -// ---------------------------------------------------------------------------- -/** - fills memory with a 32-bit value (note: assumes the ptr is 4-byte-aligned) -*/ -static void memset32(void* ptr, Int value, Int bytesToFill) -{ - Int wordsToFill = bytesToFill>>2; - bytesToFill -= (wordsToFill<<2); - - Int *p = (Int*)ptr; - for (++wordsToFill; --wordsToFill; ) - *p++ = value; - - Byte *b = (Byte *)p; - for (++bytesToFill; --bytesToFill; ) - *b++ = (Byte)value; -} #ifdef MEMORYPOOL_STACKTRACE // ---------------------------------------------------------------------------- @@ -1633,7 +1548,7 @@ void* MemoryPool::allocateBlockDoNotZeroImplementation(DECLARE_LITERALSTRING_ARG if (m_firstBlobWithFreeBlocks != NULL && !m_firstBlobWithFreeBlocks->hasAnyFreeBlocks()) { // hmm... the current 'free' blob has nothing available. look and see if there - // are any other existing blobs with freespace. + // are any other existing blobs with free space. MemoryPoolBlob *blob = m_firstBlob; for (; blob != NULL; blob = blob->getNextInList()) { @@ -1641,12 +1556,12 @@ void* MemoryPool::allocateBlockDoNotZeroImplementation(DECLARE_LITERALSTRING_ARG break; } - // note that if we walk thru the list without finding anything, this will - // reset m_firstBlobWithFreeBlocks to null and fall thru. + // note that if we walk through the list without finding anything, this will + // reset m_firstBlobWithFreeBlocks to null and fall through. m_firstBlobWithFreeBlocks = blob; } - // OK, if we are here then we have no blobs with freespace... darn. + // OK, if we are here then we have no blobs with free space... darn. // allocate an overflow block. if (m_firstBlobWithFreeBlocks == NULL) { diff --git a/Core/GameEngine/Source/Common/System/GameMemoryCommon.cpp b/Core/GameEngine/Source/Common/System/GameMemoryCommon.cpp new file mode 100644 index 00000000000..5f05219be6c --- /dev/null +++ b/Core/GameEngine/Source/Common/System/GameMemoryCommon.cpp @@ -0,0 +1,121 @@ +/* +** Command & Conquer Generals Zero Hour(tm) +** Copyright 2025 TheSuperHackers +** +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +*/ + +#include "PreRTS.h" + +#include "Common/GameMemory.h" +#include "Common/PerfTimer.h" + +#ifdef MEMORYPOOL_DEBUG + +static Int theTotalSystemAllocationInBytes = 0; +Int thePeakSystemAllocationInBytes = 0; + +constexpr const Int GARBAGE_FILL_VALUE = 0xdeadbeef; + +DECLARE_PERF_TIMER(SysMemoryDebugging) +DECLARE_PERF_TIMER(SysMemoryInitFilling) + +#endif // MEMORYPOOL_DEBUG + +//----------------------------------------------------------------------------- +/** + this is the low-level allocator that we use to request memory from the OS. + all (repeat, all) memory allocations in this module should ultimately + go through this routine (or sysAllocateDoNotZero). + + note: throws ERROR_OUT_OF_MEMORY on failure; never returns null +*/ +void* sysAllocateDoNotZero(size_t numBytes) +{ + void* p = ::GlobalAlloc(GMEM_FIXED, numBytes); + if (!p) + throw ERROR_OUT_OF_MEMORY; + +#ifdef MEMORYPOOL_DEBUG + { + USE_PERF_TIMER(SysMemoryDebugging) + #ifdef USE_FILLER_VALUE + { + USE_PERF_TIMER(SysMemoryInitFilling) + ::memset32(p, s_initFillerValue, ::GlobalSize(p)); + } + #endif + theTotalSystemAllocationInBytes += ::GlobalSize(p); + if (thePeakSystemAllocationInBytes < theTotalSystemAllocationInBytes) + thePeakSystemAllocationInBytes = theTotalSystemAllocationInBytes; + } +#endif + + return p; +} + +//----------------------------------------------------------------------------- +/** + the counterpart to sysAllocate / sysAllocateDoNotZero; used to free blocks + allocated by them. it is OK to pass null here (it will just be ignored). +*/ +void sysFree(void* p) +{ + if (p) + { +#ifdef MEMORYPOOL_DEBUG + { + USE_PERF_TIMER(MemoryPoolDebugging) + ::memset32(p, GARBAGE_FILL_VALUE, ::GlobalSize(p)); + theTotalSystemAllocationInBytes -= ::GlobalSize(p); + } +#endif + + ::GlobalFree(p); + } +} + +// ---------------------------------------------------------------------------- +/** + fills memory with a 32-bit value (note: assumes the ptr is 4-byte-aligned) +*/ +void memset32(void* ptr, Int value, size_t bytesToFill) +{ + Int wordsToFill = bytesToFill>>2; + bytesToFill -= (wordsToFill<<2); + + Int *p = (Int*)ptr; + for (++wordsToFill; --wordsToFill; ) + *p++ = value; + + Byte *b = (Byte *)p; + for (++bytesToFill; --bytesToFill; ) + *b++ = (Byte)value; +} + +#ifdef USE_FILLER_VALUE + +UnsignedInt s_initFillerValue = 0xf00dcafe; // will be replaced, should never be this value at runtime + +void calcFillerValue(Int index) +{ + s_initFillerValue = (index & 3) << 1; + s_initFillerValue |= 0x01; + s_initFillerValue |= (~(s_initFillerValue << 4)) & 0xf0; + s_initFillerValue |= (s_initFillerValue << 8); + s_initFillerValue |= (s_initFillerValue << 16); + //DEBUG_LOG(("Setting MemoryPool initFillerValue to %08x (index %d)",s_initFillerValue,index)); +} + +#endif // USE_FILLER_VALUE diff --git a/Core/Libraries/Source/WWVegas/WWLib/CMakeLists.txt b/Core/Libraries/Source/WWVegas/WWLib/CMakeLists.txt index 81579754a38..9a5ff2df350 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/CMakeLists.txt +++ b/Core/Libraries/Source/WWVegas/WWLib/CMakeLists.txt @@ -70,7 +70,6 @@ set(WWLIB_SRC #lzostraw.cpp #lzostraw.h #lzo_conf.h - MallocAllocator.h #md5.cpp #md5.h mempool.h @@ -118,6 +117,7 @@ set(WWLIB_SRC strtok_r.cpp strtok_r.h #swap.h + SystemAllocator.h systimer.cpp systimer.h TARGA.CPP diff --git a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp index 650304573af..cbca3ea9c6c 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp +++ b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp @@ -57,7 +57,7 @@ bool DbgHelpLoader::load() if (Inst == NULL) { // Cannot use new/delete here when this is loaded during game memory initialization. - void* p = ::malloc(sizeof(DbgHelpLoader)); + void* p = sysAllocateDoNotZero(sizeof(DbgHelpLoader)); Inst = new (p) DbgHelpLoader(); } @@ -126,7 +126,7 @@ void DbgHelpLoader::unload() } Inst->~DbgHelpLoader(); - ::free(Inst); + sysFree(Inst); Inst = NULL; } diff --git a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.h b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.h index ab5780b96c9..7d83da31e5b 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.h +++ b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.h @@ -24,7 +24,7 @@ #include // Must be included after Windows.h #include -#include "MallocAllocator.h" +#include "SystemAllocator.h" // This static class can load and unload dbghelp.dll // Internally it must not use new and delete because it can be created during game memory initialization. @@ -171,7 +171,7 @@ class DbgHelpLoader SymFunctionTableAccess_t m_symFunctionTableAccess; StackWalk_t m_stackWalk; - typedef std::set, stl::malloc_allocator > Processes; + typedef std::set, stl::system_allocator > Processes; Processes m_initializedProcesses; HMODULE m_dllModule; diff --git a/Core/Libraries/Source/WWVegas/WWLib/MallocAllocator.h b/Core/Libraries/Source/WWVegas/WWLib/SystemAllocator.h similarity index 69% rename from Core/Libraries/Source/WWVegas/WWLib/MallocAllocator.h rename to Core/Libraries/Source/WWVegas/WWLib/SystemAllocator.h index c56c955508c..c0b399a17f4 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/MallocAllocator.h +++ b/Core/Libraries/Source/WWVegas/WWLib/SystemAllocator.h @@ -26,10 +26,10 @@ namespace stl { -// STL allocator that uses malloc and free. Useful if allocations are meant to bypass new and delete. +// STL allocator that uses the Operating System allocator functions. Useful if allocations are meant to bypass new and delete, malloc and free. template -class malloc_allocator +class system_allocator { public: @@ -44,19 +44,19 @@ class malloc_allocator template struct rebind { - typedef malloc_allocator other; + typedef system_allocator other; }; - malloc_allocator() throw() {} + system_allocator() throw() {} #if !(defined(_MSC_VER) && _MSC_VER < 1300) - malloc_allocator(const malloc_allocator&) throw() {} + system_allocator(const system_allocator&) throw() {} #endif template - malloc_allocator(const malloc_allocator&) throw() {} + system_allocator(const system_allocator&) throw() {} - ~malloc_allocator() throw() {} + ~system_allocator() throw() {} pointer address(reference x) const { return &x; } const_pointer address(const_reference x) const { return &x; } @@ -66,7 +66,7 @@ class malloc_allocator if (n > max_size()) throw std::bad_alloc(); - void* p = ::malloc(n * sizeof(T)); + void* p = sysAllocateDoNotZero(n * sizeof(T)); if (!p) throw std::bad_alloc(); return static_cast(p); @@ -74,7 +74,7 @@ class malloc_allocator void deallocate(pointer p, size_type) { - ::free(p); + sysFree(p); } void construct(pointer p, const T& val) @@ -95,12 +95,12 @@ class malloc_allocator // Allocators of same type are always equal template -bool operator==(const malloc_allocator&, const malloc_allocator&) throw() { +bool operator==(const system_allocator&, const system_allocator&) throw() { return true; } template -bool operator!=(const malloc_allocator&, const malloc_allocator&) throw() { +bool operator!=(const system_allocator&, const system_allocator&) throw() { return false; } @@ -109,20 +109,20 @@ bool operator!=(const malloc_allocator&, const malloc_allocator&) throw( #if defined(USING_STLPORT) -// This tells STLport how to rebind malloc_allocator +// This tells STLport how to rebind system_allocator namespace std { template struct __stl_alloc_rebind_helper; template - inline stl::malloc_allocator& __stl_alloc_rebind(stl::malloc_allocator& a, const Tp2*) { - return *reinterpret_cast*>(&a); + inline stl::system_allocator& __stl_alloc_rebind(stl::system_allocator& a, const Tp2*) { + return *reinterpret_cast*>(&a); } template - inline const stl::malloc_allocator& __stl_alloc_rebind(const stl::malloc_allocator& a, const Tp2*) { - return *reinterpret_cast*>(&a); + inline const stl::system_allocator& __stl_alloc_rebind(const stl::system_allocator& a, const Tp2*) { + return *reinterpret_cast*>(&a); } } diff --git a/Core/Libraries/Source/WWVegas/WWLib/always.h b/Core/Libraries/Source/WWVegas/WWLib/always.h index 3f7ab140549..4b46bd1a75d 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/always.h +++ b/Core/Libraries/Source/WWVegas/WWLib/always.h @@ -79,6 +79,9 @@ #endif //_MSC_VER #endif //RTS_DEBUG +extern void* sysAllocateDoNotZero(size_t numBytes); +extern void sysFree(void* p); + #if !defined(DISABLE_GAMEMEMORY) // (gth) killing the Generals Memory Manager! #ifndef _OPERATOR_NEW_DEFINED_ From 3acad388b3184f16fb1fdf481d26a2f6e6c67b6d Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Fri, 10 Oct 2025 20:06:25 +0200 Subject: [PATCH 12/20] Fix compile error --- Core/GameEngine/Include/Common/GameMemory.h | 1 + Core/GameEngine/Source/Common/System/GameMemoryCommon.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Core/GameEngine/Include/Common/GameMemory.h b/Core/GameEngine/Include/Common/GameMemory.h index 92f1ea2a911..33922776abf 100644 --- a/Core/GameEngine/Include/Common/GameMemory.h +++ b/Core/GameEngine/Include/Common/GameMemory.h @@ -181,6 +181,7 @@ #endif // MEMORYPOOL_DEBUG +extern Int theTotalSystemAllocationInBytes; extern Int thePeakSystemAllocationInBytes; // TheSuperHackers @tweak The system allocator functions are now global. diff --git a/Core/GameEngine/Source/Common/System/GameMemoryCommon.cpp b/Core/GameEngine/Source/Common/System/GameMemoryCommon.cpp index 5f05219be6c..48ec20febc6 100644 --- a/Core/GameEngine/Source/Common/System/GameMemoryCommon.cpp +++ b/Core/GameEngine/Source/Common/System/GameMemoryCommon.cpp @@ -23,7 +23,7 @@ #ifdef MEMORYPOOL_DEBUG -static Int theTotalSystemAllocationInBytes = 0; +Int theTotalSystemAllocationInBytes = 0; Int thePeakSystemAllocationInBytes = 0; constexpr const Int GARBAGE_FILL_VALUE = 0xdeadbeef; From f828b945d7b0a109baa78f9421267e607f7c9ff3 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Fri, 10 Oct 2025 20:08:46 +0200 Subject: [PATCH 13/20] Revert "Simplify lib load with LOAD_LIBRARY_SEARCH_SYSTEM32" This reverts commit 00c93ddbb1fe2f9a9e5111a0470101e71a0b7e0a. --- Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp index cbca3ea9c6c..6c538ac6b48 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp +++ b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp @@ -66,10 +66,14 @@ bool DbgHelpLoader::load() return false; // Try load dbghelp.dll from the system directory first. - Inst->m_dllModule = ::LoadLibraryExA("dbghelp.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + char dllFilename[MAX_PATH]; + ::GetSystemDirectoryA(dllFilename, ARRAY_SIZE(dllFilename)); + strlcat(dllFilename, "\\dbghelp.dll", ARRAY_SIZE(dllFilename)); + + Inst->m_dllModule = ::LoadLibraryA(dllFilename); if (Inst->m_dllModule == HMODULE(0)) { - // Not found. Try load dbghelp.dll from the work directory or wherever else it will be looking. + // Not found. Try load dbghelp.dll from the work directory. Inst->m_dllModule = ::LoadLibraryA("dbghelp.dll"); if (Inst->m_dllModule == HMODULE(0)) { From b267afb62ceb9fae931340435aba43f0d50a7eea Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Fri, 10 Oct 2025 20:14:27 +0200 Subject: [PATCH 14/20] Update comment --- .../Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 548fa59ec9c..2d9f5c0e269 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -333,8 +333,8 @@ bool DX8Wrapper::Init(void * hwnd, bool lite) */ WWDEBUG_SAY(("Create Direct3D8")); { - // TheSuperHackers @bugfix xezon 13/06/2025 Front load the system dbghelp.dll - // to prevent the graphics driver from potentially loading the old game dbghelp.dll. + // TheSuperHackers @bugfix xezon 13/06/2025 Front load the system dbghelp.dll to prevent + // the graphics driver from potentially loading the old game dbghelp.dll and then crashing the game process. DbgHelpGuard dbgHelpGuard; D3DInterface = Direct3DCreate8Ptr(D3D_SDK_VERSION); // TODO: handle failure cases... @@ -599,8 +599,8 @@ bool DX8Wrapper::Create_Device(void) HRESULT hr; { - // TheSuperHackers @bugfix xezon 13/06/2025 Front load the system dbghelp.dll - // to prevent the graphics driver from potentially loading the old game dbghelp.dll. + // TheSuperHackers @bugfix xezon 13/06/2025 Front load the system dbghelp.dll to prevent + // the graphics driver from potentially loading the old game dbghelp.dll and then crashing the game process. DbgHelpGuard dbgHelpGuard; hr=D3DInterface->CreateDevice From b341518a0c141ab586a3f6e4e62dc75c4a543f22 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Fri, 10 Oct 2025 20:34:05 +0200 Subject: [PATCH 15/20] Fix W3DView compile error --- Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp | 4 ++-- Core/Libraries/Source/WWVegas/WWLib/SystemAllocator.h | 5 ++--- Core/Libraries/Source/WWVegas/WWLib/always.h | 3 --- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp index 6c538ac6b48..b5bcef62f48 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp +++ b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp @@ -57,7 +57,7 @@ bool DbgHelpLoader::load() if (Inst == NULL) { // Cannot use new/delete here when this is loaded during game memory initialization. - void* p = sysAllocateDoNotZero(sizeof(DbgHelpLoader)); + void* p = GlobalAlloc(GMEM_FIXED, sizeof(DbgHelpLoader)); Inst = new (p) DbgHelpLoader(); } @@ -130,7 +130,7 @@ void DbgHelpLoader::unload() } Inst->~DbgHelpLoader(); - sysFree(Inst); + GlobalFree(Inst); Inst = NULL; } diff --git a/Core/Libraries/Source/WWVegas/WWLib/SystemAllocator.h b/Core/Libraries/Source/WWVegas/WWLib/SystemAllocator.h index c0b399a17f4..00f65a79123 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/SystemAllocator.h +++ b/Core/Libraries/Source/WWVegas/WWLib/SystemAllocator.h @@ -18,7 +18,6 @@ #pragma once -#include // malloc, free #include // std::size_t, std::ptrdiff_t #include // std::bad_alloc @@ -66,7 +65,7 @@ class system_allocator if (n > max_size()) throw std::bad_alloc(); - void* p = sysAllocateDoNotZero(n * sizeof(T)); + void* p = GlobalAlloc(GMEM_FIXED, n * sizeof(T)); if (!p) throw std::bad_alloc(); return static_cast(p); @@ -74,7 +73,7 @@ class system_allocator void deallocate(pointer p, size_type) { - sysFree(p); + GlobalFree(p); } void construct(pointer p, const T& val) diff --git a/Core/Libraries/Source/WWVegas/WWLib/always.h b/Core/Libraries/Source/WWVegas/WWLib/always.h index 4b46bd1a75d..3f7ab140549 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/always.h +++ b/Core/Libraries/Source/WWVegas/WWLib/always.h @@ -79,9 +79,6 @@ #endif //_MSC_VER #endif //RTS_DEBUG -extern void* sysAllocateDoNotZero(size_t numBytes); -extern void sysFree(void* p); - #if !defined(DISABLE_GAMEMEMORY) // (gth) killing the Generals Memory Manager! #ifndef _OPERATOR_NEW_DEFINED_ From 3648be636fede6362bd31b121935e2cded56e614 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Mon, 20 Oct 2025 18:18:06 +0200 Subject: [PATCH 16/20] Revert "Replace MallocAllocator with SystemAllocator" This reverts commit de2f8b5a7b05f242712af7eab76a40a66f973c17. # Conflicts: # Core/GameEngine/Include/Common/GameMemory.h # Core/GameEngine/Source/Common/System/GameMemoryCommon.cpp # Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.cpp # Core/Libraries/Source/WWVegas/WWLib/MallocAllocator.h --- Core/GameEngine/CMakeLists.txt | 1 - Core/GameEngine/Include/Common/GameMemory.h | 16 --- .../Source/Common/System/GameMemory.cpp | 95 +++++++++++++- .../Source/Common/System/GameMemoryCommon.cpp | 121 ------------------ 4 files changed, 90 insertions(+), 143 deletions(-) delete mode 100644 Core/GameEngine/Source/Common/System/GameMemoryCommon.cpp diff --git a/Core/GameEngine/CMakeLists.txt b/Core/GameEngine/CMakeLists.txt index 362c5be8f86..0a58dfc4315 100644 --- a/Core/GameEngine/CMakeLists.txt +++ b/Core/GameEngine/CMakeLists.txt @@ -651,7 +651,6 @@ set(GAMEENGINE_SRC # Source/Common/System/FunctionLexicon.cpp # Source/Common/System/GameCommon.cpp #Source/Common/System/GameMemory.cpp # is conditionally appended - Source/Common/System/GameMemoryCommon.cpp #Source/Common/System/GameMemoryInit.cpp # is conditionally appended # Source/Common/System/GameType.cpp # Source/Common/System/Geometry.cpp diff --git a/Core/GameEngine/Include/Common/GameMemory.h b/Core/GameEngine/Include/Common/GameMemory.h index 33922776abf..65b1732e527 100644 --- a/Core/GameEngine/Include/Common/GameMemory.h +++ b/Core/GameEngine/Include/Common/GameMemory.h @@ -177,24 +177,8 @@ }; -#define USE_FILLER_VALUE - #endif // MEMORYPOOL_DEBUG -extern Int theTotalSystemAllocationInBytes; -extern Int thePeakSystemAllocationInBytes; - -// TheSuperHackers @tweak The system allocator functions are now global. -// Use this to bypass Game Memory Pools in exceptional circumstances. -extern void* sysAllocateDoNotZero(size_t numBytes); -extern void sysFree(void* p); -extern void memset32(void* ptr, Int value, size_t bytesToFill); - -#ifdef USE_FILLER_VALUE -extern UnsignedInt s_initFillerValue; -extern void calcFillerValue(Int index); -#endif - // TheSuperHackers @build xezon 30/03/2025 Define DISABLE_GAMEMEMORY to use a null implementations for Game Memory. // Useful for address sanitizer checks and other investigations. // Is included below the macros so that memory pool debug code can still be used. diff --git a/Core/GameEngine/Source/Common/System/GameMemory.cpp b/Core/GameEngine/Source/Common/System/GameMemory.cpp index 123ce33b31d..8fcf71b1388 100644 --- a/Core/GameEngine/Source/Common/System/GameMemory.cpp +++ b/Core/GameEngine/Source/Common/System/GameMemory.cpp @@ -114,7 +114,21 @@ DECLARE_PERF_TIMER(MemoryPoolInitFilling) #define MEMORYPOOL_SINGLEBLOCK_GETS_STACKTRACE #endif + #define USE_FILLER_VALUE + const Int MAX_INIT_FILLER_COUNT = 8; + #ifdef USE_FILLER_VALUE + static UnsignedInt s_initFillerValue = 0xf00dcafe; // will be replaced, should never be this value at runtime + static void calcFillerValue(Int index) + { + s_initFillerValue = (index & 3) << 1; + s_initFillerValue |= 0x01; + s_initFillerValue |= (~(s_initFillerValue << 4)) & 0xf0; + s_initFillerValue |= (s_initFillerValue << 8); + s_initFillerValue |= (s_initFillerValue << 16); + //DEBUG_LOG(("Setting MemoryPool initFillerValue to %08x (index %d)",s_initFillerValue,index)); + } + #endif #endif @@ -155,6 +169,8 @@ DECLARE_PERF_TIMER(MemoryPoolInitFilling) #ifdef MEMORYPOOL_DEBUG + static Int theTotalSystemAllocationInBytes = 0; + static Int thePeakSystemAllocationInBytes = 0; static Int theTotalLargeBlocks = 0; static Int thePeakLargeBlocks = 0; Int theTotalDMA = 0; @@ -187,7 +203,9 @@ static Bool theMainInitFlag = false; #define MEM_BOUND_ALIGNMENT 4 static Int roundUpMemBound(Int i); - +static void *sysAllocateDoNotZero(Int numBytes); +static void sysFree(void* p); +static void memset32(void* ptr, Int value, Int bytesToFill); #ifdef MEMORYPOOL_STACKTRACE static void doStackDumpOutput(const char* m); static void doStackDump(void **stacktrace, int size); @@ -205,6 +223,73 @@ static Int roundUpMemBound(Int i) return (i + (MEM_BOUND_ALIGNMENT-1)) & ~(MEM_BOUND_ALIGNMENT-1); } +//----------------------------------------------------------------------------- +/** + this is the low-level allocator that we use to request memory from the OS. + all (repeat, all) memory allocations in this module should ultimately + go thru this routine (or sysAllocate). + + note: throws ERROR_OUT_OF_MEMORY on failure; never returns null +*/ +static void* sysAllocateDoNotZero(Int numBytes) +{ + void* p = ::GlobalAlloc(GMEM_FIXED, numBytes); + if (!p) + throw ERROR_OUT_OF_MEMORY; +#ifdef MEMORYPOOL_DEBUG + { + USE_PERF_TIMER(MemoryPoolDebugging) + #ifdef USE_FILLER_VALUE + { + USE_PERF_TIMER(MemoryPoolInitFilling) + ::memset32(p, s_initFillerValue, ::GlobalSize(p)); + } + #endif + theTotalSystemAllocationInBytes += ::GlobalSize(p); + if (thePeakSystemAllocationInBytes < theTotalSystemAllocationInBytes) + thePeakSystemAllocationInBytes = theTotalSystemAllocationInBytes; + } +#endif + return p; +} + +//----------------------------------------------------------------------------- +/** + the counterpart to sysAllocate / sysAllocateDoNotZero; used to free blocks + allocated by them. it is OK to pass null here (it will just be ignored). +*/ +static void sysFree(void* p) +{ + if (p) + { +#ifdef MEMORYPOOL_DEBUG + { + USE_PERF_TIMER(MemoryPoolDebugging) + ::memset32(p, GARBAGE_FILL_VALUE, ::GlobalSize(p)); + theTotalSystemAllocationInBytes -= ::GlobalSize(p); + } +#endif + ::GlobalFree(p); + } +} + +// ---------------------------------------------------------------------------- +/** + fills memory with a 32-bit value (note: assumes the ptr is 4-byte-aligned) +*/ +static void memset32(void* ptr, Int value, Int bytesToFill) +{ + Int wordsToFill = bytesToFill>>2; + bytesToFill -= (wordsToFill<<2); + + Int *p = (Int*)ptr; + for (++wordsToFill; --wordsToFill; ) + *p++ = value; + + Byte *b = (Byte *)p; + for (++bytesToFill; --bytesToFill; ) + *b++ = (Byte)value; +} #ifdef MEMORYPOOL_STACKTRACE // ---------------------------------------------------------------------------- @@ -1548,7 +1633,7 @@ void* MemoryPool::allocateBlockDoNotZeroImplementation(DECLARE_LITERALSTRING_ARG if (m_firstBlobWithFreeBlocks != NULL && !m_firstBlobWithFreeBlocks->hasAnyFreeBlocks()) { // hmm... the current 'free' blob has nothing available. look and see if there - // are any other existing blobs with free space. + // are any other existing blobs with freespace. MemoryPoolBlob *blob = m_firstBlob; for (; blob != NULL; blob = blob->getNextInList()) { @@ -1556,12 +1641,12 @@ void* MemoryPool::allocateBlockDoNotZeroImplementation(DECLARE_LITERALSTRING_ARG break; } - // note that if we walk through the list without finding anything, this will - // reset m_firstBlobWithFreeBlocks to null and fall through. + // note that if we walk thru the list without finding anything, this will + // reset m_firstBlobWithFreeBlocks to null and fall thru. m_firstBlobWithFreeBlocks = blob; } - // OK, if we are here then we have no blobs with free space... darn. + // OK, if we are here then we have no blobs with freespace... darn. // allocate an overflow block. if (m_firstBlobWithFreeBlocks == NULL) { diff --git a/Core/GameEngine/Source/Common/System/GameMemoryCommon.cpp b/Core/GameEngine/Source/Common/System/GameMemoryCommon.cpp deleted file mode 100644 index 48ec20febc6..00000000000 --- a/Core/GameEngine/Source/Common/System/GameMemoryCommon.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/* -** Command & Conquer Generals Zero Hour(tm) -** Copyright 2025 TheSuperHackers -** -** This program is free software: you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation, either version 3 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program. If not, see . -*/ - -#include "PreRTS.h" - -#include "Common/GameMemory.h" -#include "Common/PerfTimer.h" - -#ifdef MEMORYPOOL_DEBUG - -Int theTotalSystemAllocationInBytes = 0; -Int thePeakSystemAllocationInBytes = 0; - -constexpr const Int GARBAGE_FILL_VALUE = 0xdeadbeef; - -DECLARE_PERF_TIMER(SysMemoryDebugging) -DECLARE_PERF_TIMER(SysMemoryInitFilling) - -#endif // MEMORYPOOL_DEBUG - -//----------------------------------------------------------------------------- -/** - this is the low-level allocator that we use to request memory from the OS. - all (repeat, all) memory allocations in this module should ultimately - go through this routine (or sysAllocateDoNotZero). - - note: throws ERROR_OUT_OF_MEMORY on failure; never returns null -*/ -void* sysAllocateDoNotZero(size_t numBytes) -{ - void* p = ::GlobalAlloc(GMEM_FIXED, numBytes); - if (!p) - throw ERROR_OUT_OF_MEMORY; - -#ifdef MEMORYPOOL_DEBUG - { - USE_PERF_TIMER(SysMemoryDebugging) - #ifdef USE_FILLER_VALUE - { - USE_PERF_TIMER(SysMemoryInitFilling) - ::memset32(p, s_initFillerValue, ::GlobalSize(p)); - } - #endif - theTotalSystemAllocationInBytes += ::GlobalSize(p); - if (thePeakSystemAllocationInBytes < theTotalSystemAllocationInBytes) - thePeakSystemAllocationInBytes = theTotalSystemAllocationInBytes; - } -#endif - - return p; -} - -//----------------------------------------------------------------------------- -/** - the counterpart to sysAllocate / sysAllocateDoNotZero; used to free blocks - allocated by them. it is OK to pass null here (it will just be ignored). -*/ -void sysFree(void* p) -{ - if (p) - { -#ifdef MEMORYPOOL_DEBUG - { - USE_PERF_TIMER(MemoryPoolDebugging) - ::memset32(p, GARBAGE_FILL_VALUE, ::GlobalSize(p)); - theTotalSystemAllocationInBytes -= ::GlobalSize(p); - } -#endif - - ::GlobalFree(p); - } -} - -// ---------------------------------------------------------------------------- -/** - fills memory with a 32-bit value (note: assumes the ptr is 4-byte-aligned) -*/ -void memset32(void* ptr, Int value, size_t bytesToFill) -{ - Int wordsToFill = bytesToFill>>2; - bytesToFill -= (wordsToFill<<2); - - Int *p = (Int*)ptr; - for (++wordsToFill; --wordsToFill; ) - *p++ = value; - - Byte *b = (Byte *)p; - for (++bytesToFill; --bytesToFill; ) - *b++ = (Byte)value; -} - -#ifdef USE_FILLER_VALUE - -UnsignedInt s_initFillerValue = 0xf00dcafe; // will be replaced, should never be this value at runtime - -void calcFillerValue(Int index) -{ - s_initFillerValue = (index & 3) << 1; - s_initFillerValue |= 0x01; - s_initFillerValue |= (~(s_initFillerValue << 4)) & 0xf0; - s_initFillerValue |= (s_initFillerValue << 8); - s_initFillerValue |= (s_initFillerValue << 16); - //DEBUG_LOG(("Setting MemoryPool initFillerValue to %08x (index %d)",s_initFillerValue,index)); -} - -#endif // USE_FILLER_VALUE From 15eb10124487ae806746c4aaffb6631ce3530a05 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sat, 1 Nov 2025 12:38:50 +0100 Subject: [PATCH 17/20] Update comment in Generals --- .../Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 03c498e7920..32f44bd9bd7 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -314,8 +314,8 @@ bool DX8Wrapper::Init(void * hwnd, bool lite) */ WWDEBUG_SAY(("Create Direct3D8")); { - // TheSuperHackers @bugfix xezon 13/06/2025 Front load the system dbghelp.dll - // to prevent the graphics driver from potentially loading the old game dbghelp.dll. + // TheSuperHackers @bugfix xezon 13/06/2025 Front load the system dbghelp.dll to prevent + // the graphics driver from potentially loading the old game dbghelp.dll and then crashing the game process. DbgHelpGuard dbgHelpGuard; D3DInterface = Direct3DCreate8Ptr(D3D_SDK_VERSION); // TODO: handle failure cases... @@ -567,8 +567,8 @@ bool DX8Wrapper::Create_Device(void) HRESULT hr; { - // TheSuperHackers @bugfix xezon 13/06/2025 Front load the system dbghelp.dll - // to prevent the graphics driver from potentially loading the old game dbghelp.dll. + // TheSuperHackers @bugfix xezon 13/06/2025 Front load the system dbghelp.dll to prevent + // the graphics driver from potentially loading the old game dbghelp.dll and then crashing the game process. DbgHelpGuard dbgHelpGuard; hr=D3DInterface->CreateDevice From 1ffa737da30b394c2b25dda3c04547212f5c19c7 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sat, 1 Nov 2025 12:43:11 +0100 Subject: [PATCH 18/20] Add one more dbghelp guard in Zero Hour --- .../Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 2d9f5c0e269..ba2942972bd 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -627,6 +627,11 @@ bool DX8Wrapper::Create_Device(void) _PresentParameters.AutoDepthStencilFormat==D3DFMT_D24X8)) { _PresentParameters.AutoDepthStencilFormat=D3DFMT_D16; + + // TheSuperHackers @bugfix xezon 13/06/2025 Front load the system dbghelp.dll to prevent + // the graphics driver from potentially loading the old game dbghelp.dll and then crashing the game process. + DbgHelpGuard dbgHelpGuard; + hr = D3DInterface->CreateDevice ( CurRenderDevice, From 4d7fb465addd54a5ac11027c88f99255caea1e12 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sat, 1 Nov 2025 12:46:17 +0100 Subject: [PATCH 19/20] Simplify new code --- .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 27 +++++++--------- .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 32 +++++++------------ 2 files changed, 24 insertions(+), 35 deletions(-) diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 32f44bd9bd7..760ac9a6976 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -565,22 +565,19 @@ bool DX8Wrapper::Create_Device(void) Vertex_Processing_Behavior|=D3DCREATE_FPU_PRESERVE; #endif - HRESULT hr; - { - // TheSuperHackers @bugfix xezon 13/06/2025 Front load the system dbghelp.dll to prevent - // the graphics driver from potentially loading the old game dbghelp.dll and then crashing the game process. - DbgHelpGuard dbgHelpGuard; + // TheSuperHackers @bugfix xezon 13/06/2025 Front load the system dbghelp.dll to prevent + // the graphics driver from potentially loading the old game dbghelp.dll and then crashing the game process. + DbgHelpGuard dbgHelpGuard; - hr=D3DInterface->CreateDevice - ( - CurRenderDevice, - WW3D_DEVTYPE, - _Hwnd, - Vertex_Processing_Behavior, - &_PresentParameters, - &D3DDevice - ); - } + HRESULT hr=D3DInterface->CreateDevice + ( + CurRenderDevice, + WW3D_DEVTYPE, + _Hwnd, + Vertex_Processing_Behavior, + &_PresentParameters, + &D3DDevice + ); if (FAILED(hr)) { diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index ba2942972bd..e5077aaafa8 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -597,22 +597,19 @@ bool DX8Wrapper::Create_Device(void) Vertex_Processing_Behavior|=D3DCREATE_FPU_PRESERVE; #endif - HRESULT hr; - { - // TheSuperHackers @bugfix xezon 13/06/2025 Front load the system dbghelp.dll to prevent - // the graphics driver from potentially loading the old game dbghelp.dll and then crashing the game process. - DbgHelpGuard dbgHelpGuard; + // TheSuperHackers @bugfix xezon 13/06/2025 Front load the system dbghelp.dll to prevent + // the graphics driver from potentially loading the old game dbghelp.dll and then crashing the game process. + DbgHelpGuard dbgHelpGuard; - hr=D3DInterface->CreateDevice - ( - CurRenderDevice, - WW3D_DEVTYPE, - _Hwnd, - Vertex_Processing_Behavior, - &_PresentParameters, - &D3DDevice - ); - } + HRESULT hr=D3DInterface->CreateDevice + ( + CurRenderDevice, + WW3D_DEVTYPE, + _Hwnd, + Vertex_Processing_Behavior, + &_PresentParameters, + &D3DDevice + ); if (FAILED(hr)) { @@ -627,11 +624,6 @@ bool DX8Wrapper::Create_Device(void) _PresentParameters.AutoDepthStencilFormat==D3DFMT_D24X8)) { _PresentParameters.AutoDepthStencilFormat=D3DFMT_D16; - - // TheSuperHackers @bugfix xezon 13/06/2025 Front load the system dbghelp.dll to prevent - // the graphics driver from potentially loading the old game dbghelp.dll and then crashing the game process. - DbgHelpGuard dbgHelpGuard; - hr = D3DInterface->CreateDevice ( CurRenderDevice, From d12b41fe87e84f599e062516116135cce9dc7637 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sat, 1 Nov 2025 12:51:57 +0100 Subject: [PATCH 20/20] Unload dbghelp.dll sooner after call to CreateDevice --- Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp | 2 ++ GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 760ac9a6976..e413eec2b1a 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -584,6 +584,8 @@ bool DX8Wrapper::Create_Device(void) return false; } + dbgHelpGuard.deactivate(); + /* ** Initialize all subsystems */ diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index e5077aaafa8..d631b5f39b7 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -645,6 +645,8 @@ bool DX8Wrapper::Create_Device(void) } } + dbgHelpGuard.deactivate(); + /* ** Initialize all subsystems */