/* Fast Memory Manager: BCB support 2.04 Description: FastMM support unit for C++ Builder. Loads FastMM4 on startup of the Borland C++ Builder application or DLL. Usage: 1) Copy FastMM4BCB.cpp, FastMM4.pas, FastMM4Message.pas, FastMM4Options.inc, and FastMM_FullDebugMode.lib to your source folder. 2) Copy FastMM_FullDebugMode.dll to your application's .exe directory (if you intend to use FullDebugMode). 3) To your project, add FastMM4Messages.pas first, then FastMM4.pas, then FastMM4BCB.cpp. On compiling the .pas files, .hpp files are created and imported by the subsequent files. 4) Add USEOBJ("FastMM4BCB.cpp") to your project file, BEFORE any other USEFORM directives. 5) Under the Project -> Options -> Linker menu uncheck "Use Dynamic RTL" (sorry, won't work with the RTL DLL). FastMM will now install itself on startup and replace the RTL memory manager. Acknowledgements: - Jarek Karciarz, Vladimir Ulchenko (Vavan) and Bob Gonder for their help in implementing the initial BCB support. - JiYuan Xie for doing an entire rewrite of this unit to allow leak reporting, etc. under BCB. - Remy Lebeau for some bugfixes. - James Nachbar and Albert Wiersch for improved usage instructions and bugfixes. Change log: Version 1.00 (15 June 2005): - Initial release. Due to limitations of BCB it cannot be uninstalled (thus no leak checking and not useable in DLLs unless the DLL always shares the main application's MM). Thanks to Jarek Karciarz, Vladimir Ulchenko and Bob Gonder for their help. Version 1.01 (6 August 2005): - Fixed a regression bug (Thanks to Omar Zelaya). Version 2.00 (22 April 2008): - Rewritten by JiYuan Xie to implement leak reporting, etc. (Thank you!) Version 2.01 (9 December 2008): - Fixed a compiler error when 'STRICT' is defined Version 2.02 (24 January 2009): - JiYuan Xie fixed the BCB compatibility. (Thanks!) Version 2.03 (03 March 2009): - Changes for BCB2009 in "TCHAR = wchar_t" mode Version 2.04 (10 January 2010): - Fixed a compilation error in BCB6 (Thanks to Remy Lebeau) */ //#ifndef _NO_VCL #pragma option push #pragma option -k- -d -vi- -O2 -b- -3 -a8 -pc -RT- -x -xd -r -AT -vG- -vG0- -vG1- -vG2- -vG3- -vGc- -vGt- -vGd- #pragma hdrstop #include "FastMM4Messages.hpp" #include "FastMM4.hpp" //BCB6 support #include #ifdef __cplusplus extern "C" { #endif #ifdef PatchBCBTerminate #ifdef FullDebugMode #ifndef LoadDebugDLLDynamically #pragma link "FastMM_FullDebugMode.lib" #if defined(RawStackTraces) __declspec(dllimport) void __fastcall GetRawStackTrace(unsigned * AReturnAddresses, unsigned AMaxDepth, unsigned ASkipFrames); #else __declspec(dllimport) void __fastcall GetFrameBasedStackTrace(unsigned * AReturnAddresses, unsigned AMaxDepth, unsigned ASkipFrames); #endif __declspec(dllimport) void __fastcall LogStackTrace(unsigned * AReturnAddresses, unsigned AMaxDepth, char *ABuffer); #endif #endif #pragma pack(push,1) typedef struct { unsigned char JmpInst; //E9 int Offset; } TRelativeJmp32, * PRelativeJmp32; typedef struct { unsigned short JmpInst; //FF 25 void * * DestPtr; } TIndirectJmp32, * PIndirectJmp32; #pragma pack(pop) //Return true if write OK bool __fastcall WriteMem(void * Location, void * Data, unsigned int DataSize) { unsigned long OldProtect; if (VirtualProtect(Location, DataSize, PAGE_EXECUTE_READWRITE, &OldProtect)) { memmove(Location, Data, DataSize); FlushInstructionCache(GetCurrentProcess(), Location, sizeof(DataSize)); VirtualProtect(Location, DataSize, OldProtect, &OldProtect); return true; } else { return false; } } #define RelativeJmp32Inst (0xE9) //Return true if patch OK bool __fastcall PatchProc(void * OldProc, void * NewProc, TRelativeJmp32 * Backup) { if (OldProc && NewProc) { TRelativeJmp32 JmpData; JmpData.JmpInst = RelativeJmp32Inst; JmpData.Offset = (int)NewProc - ((int)OldProc + sizeof(JmpData)); if (Backup) { *Backup = *((PRelativeJmp32)OldProc); } return WriteMem(OldProc, &JmpData, sizeof(JmpData)); } else { return false; } }; //Return true if unpatch OK bool __fastcall UnPatchProc(void * OldProc, void * NewProc, TRelativeJmp32 * Backup) { if (OldProc && NewProc && Backup) { int Offset = (int)NewProc - ((int)OldProc + sizeof(TRelativeJmp32)); if ((((PRelativeJmp32)OldProc)->JmpInst == RelativeJmp32Inst) && (((PRelativeJmp32)OldProc)->Offset == Offset)) { return WriteMem(OldProc, &Backup, sizeof(*Backup)); } } return false; }; typedef void * (__fastcall * GetMemFunc)(int Size); typedef int (__fastcall * FreeMemFunc)(void * P); typedef void * (__fastcall * ReallocMemFunc)(void * P, int Size); #if __BORLANDC__ >= 0x582 //>= BDS2006 ? typedef void * (__fastcall * AllocMemFunc)(unsigned Size); #endif #ifndef _RTLDLL //Not using Dynamic RTL extern void _terminate(int code); #endif #ifndef FullDebugMode #define InternalGetMem FastGetMem #define InternalFreeMem FastFreeMem #define InternalReallocMem FastReallocMem #if __BORLANDC__ >= 0x582 //>= BDS2006 ? #define InternalAllocMem FastAllocMem #endif #else #define InternalGetMem DebugGetMem #define InternalFreeMem DebugFreeMem #define InternalReallocMem DebugReallocMem #if __BORLANDC__ >= 0x582 //>= BDS2006 ? #define InternalAllocMem DebugAllocMem #endif #endif //FullDebugMode #ifdef CheckCppObjectTypeEnabled void __fastcall FinalizeModuleCodeDataRanges(void); #endif void __fastcall FinalizeHeapRedirectorStoreList(void); extern bool IsBorlandMMDLL; #if defined(__DLL__) && defined(FullDebugMode) && defined(LoadDebugDLLDynamically) void __fastcall CallOldFullDebugModeDllEntry(void); #endif void * StockGetMemPtr = NULL; void New_terminate(int code) { //FasttMM4.pas need export a "FinalizeMemoryManager" routine which contain //codes of original "finalization" section FinalizeMemoryManager(); #ifdef CheckCppObjectTypeEnabled GetCppVirtObjSizeByTypeIdPtrFunc = NULL; GetCppVirtObjTypeIdPtrFunc = NULL; GetCppVirtObjTypeNameFunc = NULL; GetCppVirtObjTypeNameByTypeIdPtrFunc = NULL; GetCppVirtObjTypeNameByVTablePtrFunc = NULL; FinalizeModuleCodeDataRanges(); #endif #ifdef DetectMMOperationsAfterUninstall //Do nothing #endif if (IsBorlandMMDLL) { FinalizeHeapRedirectorStoreList(); } #if defined(__DLL__) && defined(FullDebugMode) && defined(LoadDebugDLLDynamically) CallOldFullDebugModeDllEntry(); #endif ExitProcess(code); } void * PatchLocation = NULL; #if defined(__DLL__) && defined(FullDebugMode) && defined(LoadDebugDLLDynamically) #pragma pack(push,1) typedef struct { unsigned char PushEbp; //0x55 unsigned short MovEbpEsp; //0x8B 0xEC unsigned char SubEsp[3]; //0x83 0xC4 0xC4 } DelphiDllEntryInsts, *DelphiDllEntryInstsPtr; typedef struct { DelphiDllEntryInsts OldInsts; TRelativeJmp32 JmpToRemainInsts; } FullDebugModeDllEntryThunk; #pragma pack(pop) FullDebugModeDllEntryThunk OldFullDebugModeDllEntryThunk; bool ExecuteOldFullDebugModeDllEntry = false; bool FullDebugModeDllEntryHooked = false; bool __fastcall PrepareFullDebugModeDllEntryThunk(FullDebugModeDllEntryThunk *Thunk, void *OldEntry) { DelphiDllEntryInstsPtr OldInstsPtr = (DelphiDllEntryInstsPtr)OldEntry; if ((OldInstsPtr->PushEbp == 0x55) && (OldInstsPtr->MovEbpEsp == 0xEC8B) && (OldInstsPtr->SubEsp[0] == 0x83) && (OldInstsPtr->SubEsp[1] == 0xC4)) { unsigned long OldProtect; if (VirtualProtect((void *)Thunk, sizeof(*Thunk), PAGE_EXECUTE_READWRITE, &OldProtect)) { Thunk->OldInsts = *OldInstsPtr; //jump to (OldEntry + sizeof(*OldInstsPtr)) from Thunk->JmpToRemainInsts Thunk->JmpToRemainInsts.JmpInst = RelativeJmp32Inst; Thunk->JmpToRemainInsts.Offset = ((int)OldInstsPtr + sizeof(*OldInstsPtr)) - ((int)&Thunk->JmpToRemainInsts + sizeof(Thunk->JmpToRemainInsts)); return true; } } return false; } #if defined(PURE_CPLUSPLUS) //__BORLANDC__ < 0x0560 typedef BOOL WINAPI (*DllEntryFunc)( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved); BOOL WINAPI NewFullDebugModeDllEntry( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { //[ESP + 4] hinstDLL //[ESP + 8] fdwReason //[ESP + 12] lpvReserved if (fdwReason != DLL_PROCESS_DETACH) { DllEntryFunc OldDllEntry = (DllEntryFunc)(&OldFullDebugModeDllEntryThunk); return (*OldDllEntry)(hinstDLL, fdwReason, lpvReserved); } else { if (ExecuteOldFullDebugModeDllEntry) { ExecuteOldFullDebugModeDllEntry = 0; DllEntryFunc OldDllEntry = (DllEntryFunc)(&OldFullDebugModeDllEntryThunk); return (*OldDllEntry)(hinstDLL, fdwReason, lpvReserved); } else { return true; } } } #else //#pragma warn -8002 //"W8002: Restarting compile using assembly" #pragma option -w-asc //#pragma warn -8070 //"W8070 Function should return a value" #pragma option -w-rvl //the same as above __declspec(naked) BOOL WINAPI NewFullDebugModeDllEntry( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { //[ESP + 4] hinstDLL //[ESP + 8] fdwReason //[ESP + 12] lpvReserved /* if (fdwReason != DLL_PROCESS_DETACH) { DllEntryFunc OldDllEntry = (DllEntryFunc)(&OldFullDebugModeDllEntryThunk); return (*OldDllEntry)(hinstDLL, fdwReason, lpvReserved); } else { if (ExecuteOldFullDebugModeDllEntry) { ExecuteOldFullDebugModeDllEntry = 0; DllEntryFunc OldDllEntry = (DllEntryFunc)(&OldFullDebugModeDllEntryThunk); return (*OldDllEntry)(hinstDLL, fdwReason, lpvReserved); } else { return true; } } */ asm { mov eax, [esp + 8] //fdwReason test eax, eax //is DLL_PROCESS_DETACH ? jz ProcessDetech #if __BORLANDC__ < 0x0560 lea eax, OldFullDebugModeDllEntryThunk //not DLL_PROCESS_DETACH, call original entry jmp eax #else jmp OldFullDebugModeDllEntryThunk //not DLL_PROCESS_DETACH, call original entry #endif ProcessDetech: movzx eax, ExecuteOldFullDebugModeDllEntry test eax, eax jz Exit //do nothing if ExecuteOldFullDebugModeDllEntry flag not set xor eax, eax mov ExecuteOldFullDebugModeDllEntry, al //reset ExecuteOldDebugModeDllEntry flag #if __BORLANDC__ < 0x0560 lea eax, OldFullDebugModeDllEntryThunk jmp eax #else jmp OldFullDebugModeDllEntryThunk #endif Exit: setz al ret } } #endif void * __fastcall GetModuleEntryPoint(HMODULE AModule) { if (AModule) { PIMAGE_NT_HEADERS ntheader = (PIMAGE_NT_HEADERS)((unsigned)AModule + ((PIMAGE_DOS_HEADER)AModule)->e_lfanew); return (void *)(ntheader->OptionalHeader.AddressOfEntryPoint + (unsigned)AModule); } else { return NULL; } } bool __fastcall TryHookFullDebugModeDllEntry(void) { HMODULE AModule = GetModuleHandle(FullDebugModeLibraryName); if (AModule) { void *Entry = GetModuleEntryPoint(AModule); if (Entry) { if (PrepareFullDebugModeDllEntryThunk(&OldFullDebugModeDllEntryThunk, Entry)) { FullDebugModeDllEntryHooked = PatchProc(Entry, &NewFullDebugModeDllEntry, NULL); return FullDebugModeDllEntryHooked; } } } return false; } void __fastcall CallOldFullDebugModeDllEntry(void) { if (FullDebugModeDllEntryHooked) { HMODULE AModule = GetModuleHandle(FullDebugModeLibraryName); if (AModule) { ExecuteOldFullDebugModeDllEntry = 1; NewFullDebugModeDllEntry((HINSTANCE)AModule, DLL_PROCESS_DETACH, NULL); } } } #endif #define DVCLALResName _TEXT("DVCLAL") #define _terminateExport "_terminate" //Return true if patched OK bool __fastcall Patch_terminate(void) { if (!PatchLocation) { #ifndef _RTLDLL //Not uses Dynamic RTL PatchLocation = &_terminate; #else //Get module handle of RTL dll PIndirectJmp32 P = (PIndirectJmp32)&exit; if ((!IsBadReadPtr(P, sizeof(TIndirectJmp32))) && (P->JmpInst == 0x25FF) && (P->DestPtr) && (!IsBadReadPtr(P->DestPtr, sizeof(void *)))) { PatchLocation = *(P->DestPtr); } else { PatchLocation = P; } PatchLocation = (void *)System::FindHInstance(PatchLocation); if (PatchLocation) { //Get real patch location PatchLocation = GetProcAddress((HMODULE)PatchLocation, _terminateExport); if (!PatchLocation) { return false; } } else { return false; } #endif //_RTLDLL if ((((PRelativeJmp32)PatchLocation)->JmpInst == RelativeJmp32Inst) || (!PatchProc(PatchLocation, &New_terminate, NULL))) { PatchLocation = NULL; return false; } else { return true; } } else { return true; } } extern int __CPPdebugHook; bool IsMMInstalled = false; bool IsInDLL = false; bool IsBorlandMMDLL = false; bool terminatePatched = false; #define CPPdebugHookExport "___CPPdebugHook" //#ifndef _RTLDLL #if (__BORLANDC__ < 0x0560) || (__BORLANDC__ > 0x0711) #if defined(PURE_CPLUSPLUS) || defined(__clang__) void * _RTLENTRY Cpp_malloc_Stub(size_t size) { if (size) return InternalGetMem(size); else return NULL; } void _RTLENTRY Cpp_free_Stub(void *block) { if (block) InternalFreeMem(block); } void * _RTLENTRY Cpp_realloc_Stub(void *block, size_t size) { if (!block) { if (size) return InternalGetMem(size); else return NULL; } else { if (!size) { InternalFreeMem(block); return NULL; } else return InternalReallocMem(block, size); } } void _RTLENTRY Cpp_terminate_Stub(void) { } #else GetMemFunc GetMemPtr; FreeMemFunc FreeMemPtr; ReallocMemFunc ReallocMemPtr; //#pragma warn -8002 //"W8002: Restarting compile using assembly" #pragma option -w-asc //#pragma warn -8070 //"W8070 Function should return a value" #pragma option -w-rvl //the same as above __declspec(naked) void * _RTLENTRY Cpp_malloc_Stub(size_t size) { asm { mov eax, [esp + 4] //size test eax, eax jz malloc_Exit //#if __BORLANDC__ >= 0x564 // jmp GetMemPtr // nop //#else call GetMemPtr ret //#endif nop malloc_Exit: ret } } __declspec(naked) void _RTLENTRY Cpp_free_Stub(void *block) { asm { mov eax, [esp + 4] //block test eax, eax jz free_Exit //#if __BORLANDC__ >= 0x564 // jmp FreeMemPtr // nop //#else call FreeMemPtr ret //#endif nop free_Exit: ret } } __declspec(naked) void * _RTLENTRY Cpp_realloc_Stub(void *block, size_t size) { asm { mov eax, [esp + 4] //block test eax, eax jnz realloc_Realloc realloc_Alloc: mov eax, [esp + 8] //size test eax, eax jz realloc_Exit2 //realloc_Exit1 //#if __BORLANDC__ >= 0x564 // jmp GetMemPtr // nop //#else call GetMemPtr ret //#endif nop ////realloc_Exit1: // //ret realloc_Realloc: mov edx, [esp + 8] //size test edx, edx jnz realloc_DoRealloc call FreeMemPtr realloc_ReturnNULL: xor eax, eax realloc_Exit2: ret nop nop nop realloc_DoRealloc: //#if __BORLANDC__ >= 0x564 // jmp ReallocMemPtr // //ret //#else call ReallocMemPtr ret //#endif } } __declspec(naked) void _RTLENTRY Cpp_terminate_Stub(void) { //Do nothing asm ret; } #endif #else //#pragma warn -8070 //"W8070 Function should return a value" #pragma option -w-rvl //the same as above __declspec(naked) void * _RTLENTRY Cpp_malloc_Stub(size_t size) { //if (size) //return InternalGetMem(size); //else //return NULL; asm { mov eax, [esp + 4] //size test eax, eax jz malloc_Exit #if __BORLANDC__ >= 0x564 jmp InternalGetMem nop #else call InternalGetMem ret #endif nop nop malloc_Exit: ret } } __declspec(naked) void _RTLENTRY Cpp_free_Stub(void *block) { //if (block) //InternalFreeMem(block); asm { mov eax, [esp + 4] //block test eax, eax jz free_Exit #if __BORLANDC__ >= 0x564 jmp InternalFreeMem nop #else call InternalFreeMem ret #endif nop nop free_Exit: ret } } __declspec(naked) void * _RTLENTRY Cpp_realloc_Stub(void *block, size_t size) { /* if (!block) { if (size) return InternalGetMem(size); else return NULL; } else { if (!size) { InternalFreeMem(block); return NULL; } else return InternalReallocMem(block, size); } */ asm { mov eax, [esp + 4] //block test eax, eax jnz realloc_Realloc realloc_Alloc: mov eax, [esp + 8] //size test eax, eax jz realloc_Exit2 //realloc_Exit1 #if __BORLANDC__ >= 0x564 jmp InternalGetMem nop #else call InternalGetMem ret #endif nop nop //realloc_Exit1: //ret realloc_Realloc: mov edx, [esp + 8] //size test edx, edx jnz realloc_DoRealloc call InternalFreeMem realloc_ReturnNULL: xor eax, eax realloc_Exit2: ret realloc_DoRealloc: #if __BORLANDC__ >= 0x564 jmp InternalReallocMem //ret #else call InternalReallocMem ret #endif } } __declspec(naked) void _RTLENTRY Cpp_terminate_Stub(void) { //Do nothing asm ret; } #endif #ifdef DetectMMOperationsAfterUninstall GetMemFunc InvalidGetMemPtr; FreeMemFunc InvalidFreeMemPtr; ReallocMemFunc InvalidReallocMemPtr; #if defined(PURE_CPLUSPLUS) //__BORLANDC__ < 0x0560 void * _RTLENTRY Cpp_Invalid_malloc_Stub(size_t size) { if (size) return (*InvalidGetMemPtr)(size); else return NULL; } void _RTLENTRY Cpp_Invalid_free_Stub(void *block) { if (block) (*InvalidFreeMemPtr)(block); } void * _RTLENTRY Cpp_Invalid_realloc_Stub(void *block, size_t size) { if (!block) { if (size) return (*InvalidGetMemPtr)(size); else return NULL; } else { if (!size) { (*InvalidFreeMemPtr)(block); return NULL; } else return (*InvalidReallocMemPtr)(block, size); } } #else //#pragma warn -8002 //"W8002: Restarting compile using assembly" #pragma option -w-asc //#pragma warn -8070 //"W8070 Function should return a value" #pragma option -w-rvl //the same as above __declspec(naked) void * _RTLENTRY Cpp_Invalid_malloc_Stub(size_t size) { asm { mov eax, [esp + 4] //size test eax, eax jz Invalid_malloc_Exit #if __BORLANDC__ >= 0x564 jmp InvalidGetMemPtr nop #else call InvalidGetMemPtr ret #endif nop Invalid_malloc_Exit: ret } } __declspec(naked) void _RTLENTRY Cpp_Invalid_free_Stub(void *block) { asm { mov eax, [esp + 4] //block test eax, eax jz Invalid_free_Exit #if __BORLANDC__ >= 0x564 jmp InvalidFreeMemPtr nop #else call InvalidFreeMemPtr ret #endif nop Invalid_free_Exit: ret } } __declspec(naked) void * _RTLENTRY Cpp_Invalid_realloc_Stub(void *block, size_t size) { asm { mov eax, [esp + 4] //block test eax, eax jnz Invalid_realloc_Realloc Invalid_realloc_Alloc: mov eax, [esp + 8] //size test eax, eax jz Invalid_realloc_Exit2 //Invalid_realloc_Exit1 #if __BORLANDC__ >= 0x564 jmp InvalidGetMemPtr nop #else call InvalidGetMemPtr ret #endif nop //Invalid_realloc_Exit1: //ret Invalid_realloc_Realloc: mov edx, [esp + 8] //size test edx, edx jnz Invalid_realloc_DoRealloc call InvalidFreeMemPtr Invalid_realloc_ReturnNULL: xor eax, eax Invalid_realloc_Exit2: ret nop nop nop Invalid_realloc_DoRealloc: #if __BORLANDC__ >= 0x564 jmp InvalidReallocMemPtr //ret #else call InvalidReallocMemPtr ret #endif } } #endif #endif //DetectMMOperationsAfterUninstall #pragma option push -b -a8 typedef void (_RTLENTRY *HeapRedirect_free) (void *); typedef void * (_RTLENTRY *HeapRedirect_malloc) (size_t); typedef void * (_RTLENTRY *HeapRedirect_realloc) (void *, size_t); typedef void (_RTLENTRY *HeapRedirect_terminate) (void); typedef enum { hrfVirgin, hrfInternal, hrfBorlndmm, hrfOldBorlndmm, hrfVCLSystem, hrfDgbAlloc, hrfOther } HeapRedirectFlag; typedef struct { size_t size; unsigned int allocated; HeapRedirectFlag flags; HeapRedirect_free free; HeapRedirect_malloc malloc; HeapRedirect_realloc realloc; HeapRedirect_terminate terminate; } HeapRedirector; typedef struct HeapRedirectorStoreStruct { HeapRedirector Data; HMODULE Module; void * PatchAddress; TRelativeJmp32 PatchBackup; struct HeapRedirectorStoreStruct *Next; } HeapRedirectorStore, *HeapRedirectorStorePtr; extern HeapRedirector * _RTLENTRY _EXPFUNC _get_heap_redirector_info(void); typedef HeapRedirector * _RTLENTRY _EXPFUNC (* rtl_get_heap_redirector_info_func)(void); #pragma option pop HeapRedirector * pHRDir = NULL; HeapRedirector Old_heap_redirector; HeapRedirectorStorePtr HeapRedirectorStoreListHeader = NULL; //#endif //!_RTLDLL #define UseHeap #ifdef UseHeap HANDLE ProcessHeapHandle = NULL; #endif void __fastcall InitFinalMemMgr(void) { #ifdef UseHeap if (!ProcessHeapHandle) { ProcessHeapHandle = GetProcessHeap(); } #endif } void * __fastcall FinalGetMem(unsigned ASize) { #ifdef UseHeap return HeapAlloc(ProcessHeapHandle, HEAP_GENERATE_EXCEPTIONS, ASize); #else return malloc(ASize); #endif } void __fastcall FinalFreeMem(void * ABlock) { #ifdef UseHeap HeapFree(ProcessHeapHandle, 0, ABlock); #else free(ABlock); #endif } void * __fastcall FinalReallocMem(void * ABlock, unsigned ANewSize) { #ifdef UseHeap return HeapReAlloc(ProcessHeapHandle, HEAP_GENERATE_EXCEPTIONS, ABlock, ANewSize); #else return realloc(ABlock, ANewSize); #endif } void __fastcall FinalizeHeapRedirectorStoreList(void) { if (HeapRedirectorStoreListHeader) { HeapRedirectorStorePtr next, ptr = HeapRedirectorStoreListHeader; HeapRedirectorStoreListHeader = NULL; while (ptr) { next = ptr->Next; FinalFreeMem(ptr); ptr = next; } } } typedef bool __fastcall (* EnumModuleCallback)(HMODULE AModule, void *AParam); #define PSAPI _TEXT("psapi") bool __fastcall EnumModulesWinNT(EnumModuleCallback ACallback, void *AParam) { typedef BOOL (__stdcall * EnumProcessModulesType)(HANDLE hProcess, HMODULE* lphModule, DWORD cb, LPDWORD lpcbNeeded ); if (!ACallback) { return false; } EnumProcessModulesType EnumProcessModules; bool DynamicLoaded; HMODULE PsapiLib = GetModuleHandle(PSAPI); if (!PsapiLib) { PsapiLib = LoadLibrary(PSAPI); if (!PsapiLib) { return false; } DynamicLoaded = true; } else { DynamicLoaded = false; } InitFinalMemMgr(); bool ret = false; try { EnumProcessModules = (EnumProcessModulesType)GetProcAddress(PsapiLib, "EnumProcessModules"); if (EnumProcessModules) { HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, GetCurrentProcessId()); if (hProcess) { try { DWORD cbNeeded = 0; if (EnumProcessModules(hProcess, NULL, 0, &cbNeeded)) { HMODULE * hMod = (HMODULE *)FinalGetMem(cbNeeded); try { if (EnumProcessModules(hProcess, hMod, cbNeeded, &cbNeeded)) { for (unsigned int i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) { if (!ACallback(hMod[i], AParam)) { break; } } ret = true; } } __finally { FinalFreeMem(hMod); } } } __finally { CloseHandle(hProcess); } } } } __finally { if (DynamicLoaded) { FreeLibrary(PsapiLib); } } return ret; } #define KERNEL32 _TEXT("kernel32") bool __fastcall EnumModulesWin9x(EnumModuleCallback ACallback, void *AParam) { #define MAX_MODULE_NAME32 255 #define TH32CS_SNAPMODULE 0x00000008 typedef struct tagMODULEENTRY32 { DWORD dwSize; DWORD th32ModuleID; DWORD th32ProcessID; DWORD GlblcntUsage; DWORD ProccntUsage; BYTE * modBaseAddr; DWORD modBaseSize; HMODULE hModule; char szModule[MAX_MODULE_NAME32 + 1]; char szExePath[MAX_PATH]; } MODULEENTRY32; typedef MODULEENTRY32 * PMODULEENTRY32; typedef MODULEENTRY32 * LPMODULEENTRY32; typedef HANDLE (__stdcall * CreateToolhelp32SnapshotType)(DWORD dwFlags, DWORD th32ProcessID); typedef BOOL (__stdcall * Module32FirstType)(HANDLE hSnapshot, LPMODULEENTRY32 lpme); typedef BOOL (__stdcall * Module32NextType)(HANDLE hSnapshot, LPMODULEENTRY32 lpme); if (!ACallback) { return false; } HMODULE Kernel32Lib; HANDLE hSnapshot; CreateToolhelp32SnapshotType CreateToolhelp32Snapshot; Module32FirstType Module32First; Module32NextType Module32Next; bool ret = false; Kernel32Lib = GetModuleHandle(KERNEL32); if (Kernel32Lib) { CreateToolhelp32Snapshot = (CreateToolhelp32SnapshotType)GetProcAddress(Kernel32Lib, "CreateToolhelp32Snapshot"); Module32First = (Module32FirstType)GetProcAddress(Kernel32Lib, "Module32First"); Module32Next = (Module32NextType)GetProcAddress(Kernel32Lib, "Module32Next"); if ((CreateToolhelp32Snapshot) && (Module32First) && (Module32Next)) { hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId()); if (hSnapshot != INVALID_HANDLE_VALUE) { try { MODULEENTRY32 ModuleInfo = {0}; ModuleInfo.dwSize = sizeof(ModuleInfo); while (Module32First(hSnapshot, &ModuleInfo)) { if (!ACallback(ModuleInfo.hModule, AParam)) break; } ret = true; } __finally { CloseHandle(hSnapshot); } } } } return ret; } bool __fastcall EnumModules(EnumModuleCallback ACallback, void *AParam) { if (ACallback) { OSVERSIONINFO OSVersionInfo; OSVersionInfo.dwOSVersionInfoSize = sizeof(OSVersionInfo); if (GetVersionEx(&OSVersionInfo)) { if (OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) { return EnumModulesWinNT(ACallback, AParam); } else { return EnumModulesWin9x(ACallback, AParam); } } } return false; } #ifdef CheckCppObjectTypeEnabled typedef struct { DWORD CodeSecStart; DWORD DataSecStart; DWORD DataSecEnd; } ModuleCodeDataRanges, * PModuleCodeDataRanges; int ModuleCodeDataRangesCount = 0; int ModuleCodeDataRangesCapacity = 0; PModuleCodeDataRanges gpModuleCodeDataRanges = NULL; unsigned LowestDataAddr = NULL; unsigned HighestDataAddr = NULL; bool __fastcall FindCodeDataRangeByDataAddr(DWORD ADataAddr, int * Index, PModuleCodeDataRanges * ARange) { bool ret = false; int L, H, I; L = 0; H = ModuleCodeDataRangesCount - 1; while (L <= H) { I = (L + H) / 2; DWORD AStart = gpModuleCodeDataRanges[I].DataSecStart; DWORD AEnd = gpModuleCodeDataRanges[I].DataSecEnd; if (ADataAddr < AStart) { H = I - 1; } else if (ADataAddr >= AEnd) { L = I + 1; } else { if (ARange) { *ARange = &(gpModuleCodeDataRanges[I]); } L = I; ret = true; break; } } if (Index) { *Index = L; } return ret; } bool __fastcall FindCodeDataRangeByCodeAddr(DWORD ACodeAddr, int * Index, PModuleCodeDataRanges * ARange) { bool ret = false; int L, H, I; L = 0; H = ModuleCodeDataRangesCount - 1; while (L <= H) { I = (L + H) / 2; DWORD AStart = gpModuleCodeDataRanges[I].CodeSecStart; DWORD AEnd = gpModuleCodeDataRanges[I].DataSecStart; if (ACodeAddr < AStart) { H = I - 1; } else if (ACodeAddr >= AEnd) { L = I + 1; } else { if (ARange) { *ARange = &(gpModuleCodeDataRanges[I]); } L = I; ret = true; break; } } if (Index) { *Index = L; } return ret; } PIMAGE_SECTION_HEADER __fastcall GetImageFirstSection(PIMAGE_NT_HEADERS ntheader) { return (PIMAGE_SECTION_HEADER)((unsigned)&(ntheader->OptionalHeader) + ntheader->FileHeader.SizeOfOptionalHeader); } #define DefaultCodeSectionName _TEXT(".text") #define DefaultDataSectionName _TEXT(".data") bool __fastcall AddModuleCodeDataRange(HMODULE AModule, void *AParam) { if ((FindResource(AModule, DVCLALResName, RT_RCDATA)) /*&& (GetProcAddress(AModule, CPPdebugHookExport))*/) { PIMAGE_NT_HEADERS ntheader = (PIMAGE_NT_HEADERS)((unsigned)AModule + ((PIMAGE_DOS_HEADER)AModule)->e_lfanew); PIMAGE_SECTION_HEADER CodeSecHeader = GetImageFirstSection(ntheader); //= IMAGE_FIRST_SECTION(ntheader); PIMAGE_SECTION_HEADER DataSecHeader = CodeSecHeader + 1; if (((memcmp(DefaultCodeSectionName, CodeSecHeader->Name, 5)) == 0) && (CodeSecHeader->Characteristics == (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE)) && ((memcmp(DefaultDataSectionName, DataSecHeader->Name, 5)) == 0) && (DataSecHeader->Characteristics == (IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA))) { int Index; if (!FindCodeDataRangeByDataAddr((unsigned)AModule + DataSecHeader->VirtualAddress, &Index, NULL)) { int NewCount = ModuleCodeDataRangesCount + 1; if (NewCount >= ModuleCodeDataRangesCapacity) { //Realloc int NewCapacity = ModuleCodeDataRangesCapacity + (ModuleCodeDataRangesCapacity / 4); gpModuleCodeDataRanges = (PModuleCodeDataRanges)FinalReallocMem(gpModuleCodeDataRanges, sizeof(ModuleCodeDataRanges) * NewCapacity); ModuleCodeDataRangesCapacity = NewCapacity; } ModuleCodeDataRangesCount = NewCount; gpModuleCodeDataRanges[Index].CodeSecStart = (unsigned)AModule + CodeSecHeader->VirtualAddress; gpModuleCodeDataRanges[Index].DataSecStart = (unsigned)AModule + DataSecHeader->VirtualAddress; gpModuleCodeDataRanges[Index].DataSecEnd = (unsigned)AModule + DataSecHeader->VirtualAddress + DataSecHeader->Misc.VirtualSize; } } } return true; } void __fastcall FinalizeModuleCodeDataRanges(void) { if ((unsigned)gpModuleCodeDataRanges > 1) { FinalFreeMem(gpModuleCodeDataRanges); gpModuleCodeDataRanges = NULL; ModuleCodeDataRangesCount = 0; ModuleCodeDataRangesCapacity = NULL; } } #define InitialCodeDataRangeCount 256 bool __fastcall FillModuleCodeDataRanges(void) { if (!gpModuleCodeDataRanges) { InitFinalMemMgr(); gpModuleCodeDataRanges = (PModuleCodeDataRanges)FinalGetMem(sizeof(ModuleCodeDataRanges) * InitialCodeDataRangeCount); ModuleCodeDataRangesCapacity = InitialCodeDataRangeCount; bool ret = EnumModules(AddModuleCodeDataRange, NULL); if ((!ret) || (!ModuleCodeDataRangesCount)) { FinalizeModuleCodeDataRanges(); gpModuleCodeDataRanges = (PModuleCodeDataRanges)1; return false; } if (ret) { LowestDataAddr = gpModuleCodeDataRanges->DataSecStart; HighestDataAddr = gpModuleCodeDataRanges[ModuleCodeDataRangesCount - 1].DataSecEnd - sizeof(void *); } return ret; } else { return false; } } #pragma option push -a1 struct TypeDescriptor; typedef TypeDescriptor * TypeDescriptorPtr; struct TypeDescriptor { unsigned Size; unsigned short Mask; unsigned short Name; union { struct { unsigned VTablePtrOffset; unsigned Flags; } Class; }; }; //TypeDescriptor.Mask flags #define TYPE_MASK_IS_STRUCT 0x0001 #define TYPE_MASK_IS_CLASS 0x0002 #define CLASS_FLAG_HAS_VTABPTR 0x00000010 #define CLASS_FLAG_HAS_RTTI 0x00000040 #pragma option pop TypeDescriptorPtr __fastcall GetCppVirtualObjectTypeIdPtrByVTablePtr(void * AVTablePtr, unsigned AVTablePtrOffset) { if (AVTablePtr) { if ((!((unsigned)AVTablePtr & (sizeof(void *) - 1))) && (!((unsigned)AVTablePtrOffset & (sizeof(void *) - 1)))) { if (!gpModuleCodeDataRanges) { if (!FillModuleCodeDataRanges()) { return NULL; } } if (((unsigned)AVTablePtr >= LowestDataAddr) && ((unsigned)AVTablePtr <= HighestDataAddr)) { PModuleCodeDataRanges ADataRange, ACodeRange; if (FindCodeDataRangeByDataAddr((unsigned)AVTablePtr - (sizeof(unsigned) * 4), NULL, &ADataRange)) { //maybe vtableptr unsigned * vftPtr = (unsigned *)AVTablePtr; unsigned VMFuncAddr = *vftPtr; if (((VMFuncAddr >= ADataRange->CodeSecStart) && (VMFuncAddr < ADataRange->DataSecStart)) || (FindCodeDataRangeByCodeAddr(VMFuncAddr, NULL, &ACodeRange))) { //address of virtual member function is valid unsigned varOffset = vftPtr[-2]; unsigned rttiPtrOffset = vftPtr[-1]; if (varOffset <= AVTablePtrOffset) { unsigned rttiPtr = (unsigned)((char *)vftPtr - rttiPtrOffset); if ((rttiPtr >= ADataRange->DataSecStart) && (((unsigned *)rttiPtr)[-1] == 0)) { //rtti Ptr is valid TypeDescriptorPtr mdtpidPtr = *((TypeDescriptorPtr *)((unsigned *)rttiPtr - 2) - 1); if (((unsigned)mdtpidPtr > ADataRange->CodeSecStart) && (((unsigned)mdtpidPtr + (sizeof(TypeDescriptor) - sizeof(GUID))) < ADataRange->DataSecStart)) { //tpid data in code section if ((mdtpidPtr->Size >= (AVTablePtrOffset + sizeof(void *))) && (mdtpidPtr->Class.VTablePtrOffset == AVTablePtrOffset) && (mdtpidPtr->Mask & (TYPE_MASK_IS_STRUCT | TYPE_MASK_IS_CLASS)) && (mdtpidPtr->Class.Flags & (CLASS_FLAG_HAS_VTABPTR | CLASS_FLAG_HAS_RTTI))) { //tpid data valid ? unsigned char * TypeName = (unsigned char *)mdtpidPtr + mdtpidPtr->Name; if ((((unsigned)TypeName + sizeof(unsigned char) * 2) < ADataRange->DataSecStart) && (*TypeName <= 'z')) { return mdtpidPtr; } } } } } } } } } } return NULL; } //#define CheckVirtualRootBaseFirst //Returned may not be the most derived type TypeDescriptorPtr __fastcall GetCppVirtualObjectTypeIdPtr(void * APointer, unsigned ASize) { if ((APointer) && (ASize >= sizeof(void *))) { if (!((unsigned)APointer & (sizeof(void *) - 1))) { if (!gpModuleCodeDataRanges) { if (!FillModuleCodeDataRanges()) { return NULL; } } #ifdef CheckVirtualRootBaseFirst TypeDescriptorPtr ret = GetCppVirtualObjectTypeIdPtrByVTablePtr(*((void **)APointer), 0); if (ret) { return ret; } #endif PModuleCodeDataRanges ADataRange, ACodeRange; unsigned ObjectSize = ASize; ASize = ASize - (ASize & (sizeof(void *) - 1)) - sizeof(void *); unsigned * DataPtr = (unsigned *)((char *)APointer + ASize); #ifdef CheckVirtualRootBaseFirst while (DataPtr > (unsigned *)APointer) #else while (DataPtr >= (unsigned *)APointer) #endif { unsigned Data = *DataPtr; if ((Data >= LowestDataAddr) && (Data <= HighestDataAddr)) { if (FindCodeDataRangeByDataAddr(Data - (sizeof(unsigned) * 4), NULL, &ADataRange)) { //maybe vtableptr unsigned * vftPtr = (unsigned *)Data; unsigned VMFuncAddr = *vftPtr; if (((VMFuncAddr >= ADataRange->CodeSecStart) && (VMFuncAddr < ADataRange->DataSecStart)) || (FindCodeDataRangeByCodeAddr(VMFuncAddr, NULL, &ACodeRange))) { //address of virtual member function is valid unsigned varOffset = vftPtr[-2]; unsigned rttiPtrOffset = vftPtr[-1]; unsigned vftPtrOffset = (char *)DataPtr - (char *)APointer; if (varOffset <= vftPtrOffset) { unsigned rttiPtr = (unsigned)((char *)vftPtr - rttiPtrOffset); if ((rttiPtr >= ADataRange->DataSecStart) && (((unsigned *)rttiPtr)[-1] == 0)) { //rtti Ptr is valid TypeDescriptorPtr mdtpidPtr = *((TypeDescriptorPtr *)((unsigned *)rttiPtr - 2) - 1); if (((unsigned)mdtpidPtr > ADataRange->CodeSecStart) && (((unsigned)mdtpidPtr + (sizeof(TypeDescriptor) - sizeof(GUID))) < ADataRange->DataSecStart)) { //tpid data in code section if ((mdtpidPtr->Size <= ObjectSize) && (mdtpidPtr->Class.VTablePtrOffset == vftPtrOffset) && (mdtpidPtr->Mask & (TYPE_MASK_IS_STRUCT | TYPE_MASK_IS_CLASS)) && (mdtpidPtr->Class.Flags & (CLASS_FLAG_HAS_VTABPTR | CLASS_FLAG_HAS_RTTI))) { //tpid data valid ? unsigned char * TypeName = (unsigned char *)mdtpidPtr + mdtpidPtr->Name; if ((((unsigned)TypeName + sizeof(unsigned char) * 2) < ADataRange->DataSecStart) && (*TypeName <= 'z')) { return mdtpidPtr; } } } } } } } } DataPtr--; } } } return NULL; } char * __fastcall GetCppVirtualObjectTypeName(void * APointer, unsigned ASize) { TypeDescriptorPtr AtpidPtr = GetCppVirtualObjectTypeIdPtr(APointer, ASize); if (AtpidPtr) { return (char *)AtpidPtr + AtpidPtr->Name; } else { return NULL; } } char * __fastcall GetCppVirtualObjectTypeNameByVTablePtr(void * AVTablePtr, unsigned AVTablePtrOffset) { TypeDescriptorPtr AtpidPtr = GetCppVirtualObjectTypeIdPtrByVTablePtr(AVTablePtr, AVTablePtrOffset); if (AtpidPtr) { return (char *)AtpidPtr + AtpidPtr->Name; } else { return NULL; } } unsigned __fastcall GetCppVirtualObjectSizeByTypeIdPtr(TypeDescriptorPtr AtpidPtr) { if ((AtpidPtr) && (AtpidPtr->Mask & (TYPE_MASK_IS_STRUCT | TYPE_MASK_IS_CLASS)) && (AtpidPtr->Class.Flags & (CLASS_FLAG_HAS_VTABPTR | CLASS_FLAG_HAS_RTTI))) { return AtpidPtr->Size; } else { return 0; } } char * __fastcall GetCppVirtualObjectTypeNameByTypeIdPtr(TypeDescriptorPtr AtpidPtr) { if (AtpidPtr) { return (char *)AtpidPtr + AtpidPtr->Name; } else { return NULL; } } #endif //CheckCppObjectTypeEnabled #define BORLANDMM _TEXT("borlndmm") #define CRTL_MEM_SIGNATURE_EXPORT "___CRTL_MEM_GetBorMemPtrs" #define CRTL_GET_HEAP_REDIRECTOR_INFO "__get_heap_redirector_info" bool __fastcall TryHookRTLHeapRedirector(HMODULE AModule, void *AParam) { if ((FindResource(AModule, DVCLALResName, RT_RCDATA)) /*&& (GetProcAddress(AModule, CPPdebugHookExport))*/ && (GetProcAddress(AModule, CRTL_MEM_SIGNATURE_EXPORT))) { rtl_get_heap_redirector_info_func rtl_get_heap_redirector_info; rtl_get_heap_redirector_info = (rtl_get_heap_redirector_info_func)GetProcAddress(AModule, CRTL_GET_HEAP_REDIRECTOR_INFO); if (rtl_get_heap_redirector_info) { HeapRedirector * pHRDir = (*rtl_get_heap_redirector_info)(); if (pHRDir) { if ((pHRDir->flags < hrfBorlndmm) || (pHRDir->flags == hrfVCLSystem)) { void * PatchAddr; HeapRedirectorStorePtr node = (HeapRedirectorStorePtr)FinalGetMem(sizeof(HeapRedirectorStore)); node->Data = *pHRDir; node->Module = AModule; //insert node into store list node->Next = HeapRedirectorStoreListHeader; HeapRedirectorStoreListHeader = node; pHRDir->malloc = &Cpp_malloc_Stub; pHRDir->free = &Cpp_free_Stub; pHRDir->realloc = &Cpp_realloc_Stub; pHRDir->terminate = &Cpp_terminate_Stub; pHRDir->flags = hrfOther; pHRDir->allocated = 1; //patch RTL _terminate of this module PatchAddr = GetProcAddress(AModule, _terminateExport); if ((PatchAddr) && (((PRelativeJmp32)PatchAddr)->JmpInst != RelativeJmp32Inst) && (!PatchProc(PatchAddr, &New_terminate, &node->PatchBackup))) { node->PatchAddress = PatchAddr; } else { node->PatchAddress = NULL; } } } } } return true; } bool __fastcall TryUnhookRTLHeapRedirector(HMODULE AModule, void *AParam) { if ((FindResource(AModule, DVCLALResName, RT_RCDATA)) /*&& (GetProcAddress(AModule, CPPdebugHookExport))*/ && (GetProcAddress(AModule, CRTL_MEM_SIGNATURE_EXPORT))) { rtl_get_heap_redirector_info_func rtl_get_heap_redirector_info; rtl_get_heap_redirector_info = (rtl_get_heap_redirector_info_func)GetProcAddress(AModule, CRTL_GET_HEAP_REDIRECTOR_INFO); if (rtl_get_heap_redirector_info) { HeapRedirector * pHRDir = (*rtl_get_heap_redirector_info)(); if (pHRDir) { //restore and remove store node { HeapRedirectorStorePtr prev, node; prev = NULL; node = HeapRedirectorStoreListHeader; while (node) { if (node->Module == AModule) { //restore original heap redirector if ((pHRDir->flags == hrfOther) && (pHRDir->malloc == &Cpp_malloc_Stub) && (pHRDir->free == &Cpp_free_Stub) && (pHRDir->realloc == &Cpp_realloc_Stub) && (pHRDir->terminate == &Cpp_terminate_Stub) ) { #ifdef DetectMMOperationsAfterUninstall if ((bool)AParam) { pHRDir->malloc = &Cpp_Invalid_malloc_Stub; pHRDir->free = &Cpp_Invalid_free_Stub; pHRDir->realloc = &Cpp_Invalid_realloc_Stub; } else #endif *pHRDir = node->Data; } //restore RTL _terminate of this module if (node->PatchAddress) { UnPatchProc(node->PatchAddress, &New_terminate, &node->PatchBackup); } //remove node from store list if (prev) { prev->Next = node->Next; } else { HeapRedirectorStoreListHeader = node->Next; } FinalFreeMem(node); break; } else { prev = node; node = node->Next; } } } } } } return true; } #endif //PatchBCBTerminate void BCBInstallFastMM() { //#ifdef __DLL__ //not defined even with -tWD ? //#endif //#if ((!defined(_NO_VCL)) && defined(__DLL__) && defined(_RTLDLL)) //borlndmm.dll will linked in //#else InitializeMemoryManager(); #if __BORLANDC__ >= 0x582 //>= BDS2006 ? //CheckCanInstallMemoryManager will finally call System.GetHeapStatus which is the //internal shipped copy of FastGetHeapStatus routine, but the InitializeMemoryManager //routine of that copy is not called yet at this point, and thus System.GetHeapStatus //will generate an access violation exception. //Currently avoid this exception by skip the check #ifndef _NO_VCL if (CheckCanInstallMemoryManager()) #endif //!_NO_VCL #else if (CheckCanInstallMemoryManager()) #endif //< BDS2006 { #ifdef PatchBCBTerminate #if defined(__DLL__) && defined(FullDebugMode) && defined(LoadDebugDLLDynamically) //if FastMM_FullDebugMode.dll receive DLL_PROCESS_DETACH before //calling FinalizeMemoryManager, exception will occur when calling //LogStackTrace in FastMM_FullDebugMode.dll, the following call //will delay the processing of DLL_PROCESS_DETACH in DllMain of //FastMM_FullDebugMode.dll if (!TryHookFullDebugModeDllEntry()) { return; } #endif #endif #ifdef FullDebugMode #ifdef ClearLogFileOnStartup DeleteEventLog(); #endif //ClearLogFileOnStartup #endif //FullDebugMode #ifdef PatchBCBTerminate #if __BORLANDC__ >= 0x582 //>= BDS2006 ? System::TMemoryManagerEx AMemoryManager; #else System::TMemoryManager AMemoryManager; #endif System::GetMemoryManager(AMemoryManager); StockGetMemPtr = AMemoryManager.GetMem; #endif InstallMemoryManager(); #if __BORLANDC__ < 0x0560 #if !defined(PURE_CPLUSPLUS) #if !defined(PatchBCBTerminate) #if __BORLANDC__ >= 0x582 //>= BDS2006 ? System::TMemoryManagerEx AMemoryManager; #else System::TMemoryManager AMemoryManager; #endif #endif System::GetMemoryManager(AMemoryManager); GetMemPtr = AMemoryManager.GetMem; FreeMemPtr = AMemoryManager.FreeMem; ReallocMemPtr = AMemoryManager.ReallocMem; #endif #endif #ifdef PatchBCBTerminate IsMMInstalled = true; #endif #ifdef PatchBCBTerminate HMODULE ThisModule = (HMODULE)System::FindHInstance(&BCBInstallFastMM); HMODULE MainModule = GetModuleHandle(0); //#ifndef _RTLDLL HMODULE BorlandMM_Module = GetModuleHandle(BORLANDMM); if (!BorlandMM_Module) { pHRDir = _get_heap_redirector_info(); if (pHRDir) { if ((pHRDir->flags < hrfBorlndmm) || (pHRDir->flags == hrfVCLSystem)) { Old_heap_redirector = *pHRDir; pHRDir->malloc = &Cpp_malloc_Stub; pHRDir->free = &Cpp_free_Stub; pHRDir->realloc = &Cpp_realloc_Stub; pHRDir->terminate = &Cpp_terminate_Stub; pHRDir->flags = hrfOther; pHRDir->allocated = 1; } else { pHRDir = NULL; } } } else { if (BorlandMM_Module == ThisModule) { IsBorlandMMDLL = true; //Try hook heap redirector of RTL modules EnumModules(TryHookRTLHeapRedirector, NULL); } } //#endif //!_RTLDLL pCppDebugHook = (int *)(GetProcAddress(MainModule, CPPdebugHookExport)); if (!pCppDebugHook) { pCppDebugHook = &__CPPdebugHook; } #ifdef CheckCppObjectTypeEnabled GetCppVirtObjSizeByTypeIdPtrFunc = (TGetCppVirtObjSizeByTypeIdPtrFunc)&GetCppVirtualObjectSizeByTypeIdPtr; GetCppVirtObjTypeIdPtrFunc = (TGetCppVirtObjTypeIdPtrFunc)&GetCppVirtualObjectTypeIdPtr; GetCppVirtObjTypeNameFunc = (TGetCppVirtObjTypeNameFunc)&GetCppVirtualObjectTypeName; GetCppVirtObjTypeNameByTypeIdPtrFunc = (TGetCppVirtObjTypeNameByTypeIdPtrFunc)&GetCppVirtualObjectTypeNameByTypeIdPtr; GetCppVirtObjTypeNameByVTablePtrFunc = (TGetCppVirtObjTypeNameByVTablePtrFunc)&GetCppVirtualObjectTypeNameByVTablePtr; #endif IsInDLL = (MainModule != ThisModule); if (!IsInDLL) { if (Patch_terminate()) { terminatePatched = true; #ifdef EnableMemoryLeakReporting #if __BORLANDC__ >= 0x582 //>= BDS2006 ? //"ios.cpp", line 136, ios_base::_Init(), "locale" leaks RegisterExpectedMemoryLeak(20, 8); //"locale0.cpp", line 167, locale::_Init(), "_Locimp" leak due to above leaks RegisterExpectedMemoryLeak(68, 1); #endif #endif } } #ifndef _RTLDLL else { #ifdef EnableMemoryLeakReporting #if __BORLANDC__ >= 0x582 //>= BDS2006 ? //"ios.cpp", line 136, ios_base::_Init(), "locale" leaks RegisterExpectedMemoryLeak(20, 8); //"locale0.cpp", line 167, locale::_Init(), "_Locimp" leak due to above leaks RegisterExpectedMemoryLeak(68, 1); RegisterExpectedMemoryLeak(228, 1); #endif #endif } #endif //_RTLDLL #endif //PatchBCBTerminate } //#endif } #pragma startup BCBInstallFastMM 0 #ifdef PatchBCBTerminate void BCBUninstallFastMM() { //Sadly we cannot uninstall here since there are still live pointers. //#if ((!defined(_NO_VCL)) && defined(__DLL__) && defined(_RTLDLL)) //#else if (IsMMInstalled && (!terminatePatched)) { //Delphi MemoryManager already installed here FinalizeMemoryManager(); #if __BORLANDC__ >= 0x582 //>= BDS2006 ? System::TMemoryManagerEx AMemoryManager; #else System::TMemoryManager AMemoryManager; #endif System::GetMemoryManager(AMemoryManager); //MemoryManager uninstalled ? bool DelphiMMUninstalled = (AMemoryManager.GetMem != InternalGetMem); #ifdef DetectMMOperationsAfterUninstall //InvalidMemoryManager get set as Delphi MemoryManager ? bool InvalidMMSet = (AMemoryManager.GetMem != StockGetMemPtr); #endif #if __BORLANDC__ < 0x0560 #if !defined(PURE_CPLUSPLUS) GetMemPtr = NULL; FreeMemPtr = NULL; ReallocMemPtr = NULL; #endif #endif #ifdef CheckCppObjectTypeEnabled GetCppVirtObjSizeByTypeIdPtrFunc = NULL; GetCppVirtObjTypeIdPtrFunc = NULL; GetCppVirtObjTypeNameFunc = NULL; GetCppVirtObjTypeNameByTypeIdPtrFunc = NULL; GetCppVirtObjTypeNameByVTablePtrFunc = NULL; FinalizeModuleCodeDataRanges(); #endif if (DelphiMMUninstalled) { if (pHRDir) { #ifdef DetectMMOperationsAfterUninstall if (InvalidMMSet) { InvalidGetMemPtr = AMemoryManager.GetMem; InvalidFreeMemPtr = AMemoryManager.FreeMem; InvalidReallocMemPtr = AMemoryManager.ReallocMem; pHRDir->malloc = Cpp_Invalid_malloc_Stub; pHRDir->free = Cpp_Invalid_free_Stub; pHRDir->realloc = Cpp_Invalid_realloc_Stub; } else #endif *pHRDir = Old_heap_redirector; pHRDir = NULL; } else { if (IsBorlandMMDLL) { //Try unhook heap redirector of RTL modules #ifdef DetectMMOperationsAfterUninstall EnumModules(TryUnhookRTLHeapRedirector, (void *)InvalidMMSet); #else EnumModules(TryUnhookRTLHeapRedirector, NULL); #endif FinalizeHeapRedirectorStoreList(); } } } #if defined(__DLL__) && defined(FullDebugMode) && defined(LoadDebugDLLDynamically) CallOldFullDebugModeDllEntry(); #endif } //#endif } #pragma exit BCBUninstallFastMM 0 #endif //PatchBCBTerminate #ifdef __cplusplus } // extern "C" #endif #pragma option pop //#endif //!_NO_VCL