xtool/contrib/FastMM4-AVX/CPP Builder Support/FastMM4BCB.cpp

2070 lines
51 KiB
C++

/*
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 <tchar.h>
#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