⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fastmm4bcb.cpp.svn-base

📁 Memory Manager for delphi 5-2007. Usefully to find the memory leaks and help for optimalize your mem
💻 SVN-BASE
📖 第 1 页 / 共 3 页
字号:
/*

Fast Memory Manager: BCB support 2.0

Description:
 FastMM support unit for BCB6 1.0. Loads FastMM4 on startup of the Borland C++
 Builder application or DLL.

Usage:
 1) Under the Project -> Options -> Linker menu uncheck "Use Dynamic RTL"
    (sorry, won't work with the RTL DLL).
 2) Add FastMM4.pas to your project and build it so that FastMM4.hpp is
    created.
 3) Add FastMM4BCB.cpp to your project.
 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.

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!)

*/

//#ifndef _NO_VCL

#pragma hdrstop
#include "FastMM4Messages.hpp"
#include "FastMM4.hpp"

#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-

#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;
};

#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;
}

//#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)
	 //return OldFullDebugModeEntry(hinstDLL, fdwReason, lpvReserved);
  //else
	//return true;
  asm
  {
	mov   eax, [esp + 8]  //fdwReason
	test  eax, eax        //is DLL_PROCESS_DETACH ?
	jz   ProcessDetech
	jmp   OldFullDebugModeDllEntryThunk  //not DLL_PROCESS_DETACH, call original entry

  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

	jmp   OldFullDebugModeDllEntryThunk
  Exit:
	setz al
	ret
  }
}

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 "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

//#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   Exit
  #if __BORLANDC__ >= 0x564
    jmp  InternalGetMem
    nop
  #else
    call InternalGetMem
    ret
  #endif
    nop
    nop
  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   Exit
  #if __BORLANDC__ >= 0x564
    jmp  InternalFreeMem
    nop
  #else
    call InternalFreeMem
    ret
  #endif
    nop
    nop
  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
  Alloc:
    mov  eax, [esp + 8] //size
    test eax, eax
    jz   Exit2 //Exit1
  #if __BORLANDC__ >= 0x564
    jmp  InternalGetMem
    nop
  #else
    call InternalGetMem
    ret
  #endif
    nop
    nop
  //Exit1:
    //ret
  Realloc:
    mov  edx, [esp + 8] //size
    test edx, edx
    jnz  DoRealloc
    call InternalFreeMem
  ReturnNULL:
    xor  eax, eax
  Exit2:
    ret
  DoRealloc:
  #if __BORLANDC__ >= 0x564
    jmp  InternalReallocMem
    //ret
  #else
    call InternalReallocMem
    ret
  #endif
  }
}

__declspec(naked) void _RTLENTRY Cpp_terminate_Stub(void)
{
  //Do nothing 
  asm ret;
}

#ifdef DetectMMOperationsAfterUninstall

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

GetMemFunc InvalidGetMemPtr;
FreeMemFunc InvalidFreeMemPtr;
ReallocMemFunc InvalidReallocMemPtr;

__declspec(naked) void * _RTLENTRY Cpp_Invalid_malloc_Stub(size_t size)
{
  asm
  {
    mov  eax, [esp + 4] //size
    test eax, eax
    jz   Exit
  #if __BORLANDC__ >= 0x564
    jmp  InvalidGetMemPtr
    nop
  #else
    call InvalidGetMemPtr
    ret
  #endif
    nop
  Exit:
    ret
  }
}

__declspec(naked) void _RTLENTRY Cpp_Invalid_free_Stub(void *block)
{
  asm
  {
    mov  eax, [esp + 4] //block
    test eax, eax
    jz   Exit
  #if __BORLANDC__ >= 0x564
    jmp  InvalidFreeMemPtr
    nop
  #else
    call InvalidFreeMemPtr
    ret
  #endif
    nop
  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  Realloc
  Alloc:
    mov  eax, [esp + 8] //size

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -