Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1745 lines
40 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. GuardAlloc.h
  5. Abstract:
  6. Author:
  7. Hakki T. Bostanci (hakkib) 06-Apr-2000
  8. Revision History:
  9. --*/
  10. #ifndef _GUARDALLOC_H_
  11. #define _GUARDALLOC_H_
  12. #include <dbghelp.h>
  13. #include <malloc.h>
  14. //////////////////////////////////////////////////////////////////////////
  15. //
  16. //
  17. //
  18. #ifdef _WIN32
  19. #undef ALIGNMENT
  20. #define ALIGNMENT 8
  21. #endif //WIN32
  22. #ifdef _WIN64
  23. #undef ALIGNMENT
  24. #define ALIGNMENT 16
  25. #endif //WIN64
  26. //////////////////////////////////////////////////////////////////////////
  27. //
  28. //
  29. //
  30. inline size_t Align(size_t nDataSize, size_t nBlockSize)
  31. {
  32. return (nDataSize + (nBlockSize-1)) & ~(nBlockSize-1);
  33. }
  34. //////////////////////////////////////////////////////////////////////////
  35. //
  36. //
  37. //
  38. #define MAX_STACK_DEPTH 32
  39. #define MAX_SYMBOL_LENGTH 256
  40. template <int N>
  41. struct CImagehlpSymbol : public IMAGEHLP_SYMBOL
  42. {
  43. CImagehlpSymbol()
  44. {
  45. ZeroMemory(this, sizeof(*this));
  46. SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
  47. MaxNameLength = N;
  48. }
  49. private:
  50. CHAR NameData[N-1];
  51. };
  52. struct CImagehlpLine : public IMAGEHLP_LINE
  53. {
  54. CImagehlpLine()
  55. {
  56. ZeroMemory(this, sizeof(*this));
  57. SizeOfStruct = sizeof(IMAGEHLP_LINE);
  58. }
  59. };
  60. struct CImagehlpModule : public IMAGEHLP_MODULE
  61. {
  62. CImagehlpModule()
  63. {
  64. ZeroMemory(this, sizeof(*this));
  65. SizeOfStruct = sizeof(IMAGEHLP_MODULE);
  66. }
  67. };
  68. //////////////////////////////////////////////////////////////////////////
  69. //
  70. //
  71. //
  72. inline PSTR GetFileNameA(PCSTR pPathName)
  73. {
  74. PCSTR pFileName = pPathName ? strrchr(pPathName, '\\') : 0;
  75. return (PSTR) (pFileName ? pFileName + 1 : pPathName);
  76. }
  77. //////////////////////////////////////////////////////////////////////////
  78. //
  79. //
  80. //
  81. inline void GetExceptionContext(LPEXCEPTION_POINTERS pExceptionPointers, CONTEXT *pContext)
  82. {
  83. *pContext = *pExceptionPointers->ContextRecord;
  84. }
  85. //////////////////////////////////////////////////////////////////////////
  86. //
  87. //
  88. //
  89. inline DWORD GetCurrentMachineType()
  90. {
  91. #if defined(_X86_)
  92. return IMAGE_FILE_MACHINE_I386;
  93. #elif defined(_MIPS_)
  94. return IMAGE_FILE_MACHINE_R4000;
  95. #elif defined(_ALPHA_)
  96. return IMAGE_FILE_MACHINE_ALPHA;
  97. #elif defined(_PPC_)
  98. return IMAGE_FILE_MACHINE_POWERPC;
  99. #elif defined(_IA64_)
  100. return IMAGE_FILE_MACHINE_IA64;
  101. #elif defined(_AXP64_)
  102. return IMAGE_FILE_MACHINE_AXP64;
  103. #else
  104. return 0;
  105. #endif
  106. }
  107. //////////////////////////////////////////////////////////////////////////
  108. //
  109. //
  110. //
  111. class CStackFrame : public STACKFRAME
  112. {
  113. public:
  114. CStackFrame()
  115. {
  116. }
  117. CStackFrame(CONTEXT *pContext)
  118. {
  119. ZeroMemory(this, sizeof(*this));
  120. #if defined(_X86_)
  121. AddrPC.Offset = pContext->Eip;
  122. AddrFrame.Offset = pContext->Ebp;
  123. AddrStack.Offset = pContext->Esp;
  124. #elif defined(_MIPS_)
  125. AddrPC.Offset = pContext->Fir;
  126. AddrFrame.Offset = pContext->IntS6;
  127. AddrStack.Offset = pContext->IntSp;
  128. #elif defined(_ALPHA_)
  129. AddrPC.Offset = pContext->Fir;
  130. AddrFrame.Offset = pContext->IntFp;
  131. AddrStack.Offset = pContext->IntSp;
  132. #elif defined(_PPC_)
  133. AddrPC.Offset = pContext->Iar;
  134. AddrFrame.Offset = pContext->IntFp;
  135. AddrStack.Offset = pContext->Gpr1;
  136. #endif
  137. AddrPC.Mode = AddrModeFlat;
  138. AddrFrame.Mode = AddrModeFlat;
  139. AddrStack.Mode = AddrModeFlat;
  140. }
  141. BOOL
  142. Walk(
  143. DWORD MachineType = GetCurrentMachineType(),
  144. HANDLE hProcess = GetCurrentProcess(),
  145. HANDLE hThread = GetCurrentThread(),
  146. PVOID ContextRecord = 0,
  147. PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine = 0,
  148. PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine = SymFunctionTableAccess,
  149. PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine = SymGetModuleBase,
  150. PTRANSLATE_ADDRESS_ROUTINE TranslateAddress = 0
  151. )
  152. {
  153. return StackWalk(
  154. MachineType,
  155. hProcess,
  156. hThread,
  157. this,
  158. ContextRecord,
  159. ReadMemoryRoutine,
  160. FunctionTableAccessRoutine,
  161. GetModuleBaseRoutine,
  162. TranslateAddress
  163. );
  164. }
  165. int Dump(HANDLE hProcess, PSTR pBuffer, int nBufferSize)
  166. {
  167. int nLength = 0;
  168. CImagehlpModule Module;
  169. SymGetModuleInfo(hProcess, AddrPC.Offset, &Module);
  170. ULONG_PTR dwDisplacement = 0;
  171. CImagehlpSymbol<MAX_SYMBOL_LENGTH> Symbol;
  172. SymGetSymFromAddr(hProcess, AddrPC.Offset, &dwDisplacement, &Symbol);
  173. CHAR szUnDSymbol[MAX_SYMBOL_LENGTH] = "";
  174. SymUnDName(&Symbol, szUnDSymbol, sizeof(szUnDSymbol));
  175. DWORD dwLineDisplacement = 0;
  176. CImagehlpLine Line;
  177. SymGetLineFromAddr(hProcess, AddrPC.Offset, &dwLineDisplacement, &Line);
  178. if (IsDebuggerPresent())
  179. {
  180. nLength = _snprintf(
  181. pBuffer,
  182. nBufferSize,
  183. "%s(%d) : %s!%s+0x%x (%p, %p, %p, %p)\n",
  184. Line.FileName,
  185. Line.LineNumber,
  186. Module.ModuleName,
  187. szUnDSymbol,
  188. dwDisplacement,
  189. Params[0],
  190. Params[1],
  191. Params[2],
  192. Params[3]
  193. );
  194. }
  195. else
  196. {
  197. nLength = _snprintf(
  198. pBuffer,
  199. nBufferSize,
  200. Line.FileName ? "%p %p %p %p %s!%s+0x%x (%s:%d)\n" : "%p %p %p %p %s!%s+0x%x\n",
  201. Params[0],
  202. Params[1],
  203. Params[2],
  204. Params[3],
  205. Module.ModuleName,
  206. szUnDSymbol,
  207. dwDisplacement,
  208. GetFileNameA(Line.FileName),
  209. Line.LineNumber
  210. );
  211. }
  212. return nLength;
  213. }
  214. };
  215. //////////////////////////////////////////////////////////////////////////
  216. //
  217. //
  218. //
  219. class CGuardAllocator
  220. {
  221. public:
  222. typedef enum
  223. {
  224. GUARD_NONE = 0,
  225. GUARD_TAIL = 1,
  226. GUARD_HEAD = 2,
  227. GUARD_FLAGS = GUARD_NONE | GUARD_TAIL | GUARD_HEAD,
  228. SAVE_STACK_FRAMES = 4
  229. } GUARD_TYPE;
  230. CGuardAllocator(LONG lFlags = GUARD_NONE)
  231. {
  232. Create(lFlags);
  233. }
  234. ~CGuardAllocator()
  235. {
  236. Destroy();
  237. }
  238. void Create(LONG lFlags = GUARD_NONE);
  239. void Destroy();
  240. void SetGuardType(LONG lFlags);
  241. void Walk(FILE *fout);
  242. HANDLE TakeSnapShot();
  243. void DeleteSnapShot(HANDLE hSnapShot);
  244. void Diff(HANDLE hSnapShot, FILE *fout);
  245. void *Alloc(DWORD dwFlags, size_t nSize);
  246. BOOL Free(DWORD dwFlags, void *pMem);
  247. size_t Size(DWORD dwFlags, const void *pMem);
  248. void *Realloc(DWORD dwFlags, void *pMem, size_t nSize);
  249. BOOL Validate(DWORD dwFlags, const void *pMem);
  250. private:
  251. void *(CGuardAllocator::*pfnAlloc)(size_t nSize);
  252. BOOL (CGuardAllocator::*pfnFree)(void *pMem);
  253. void *AllocGuardNone(size_t nSize);
  254. BOOL FreeGuardNone(void *pMem);
  255. void *AllocGuardTail(size_t nSize);
  256. BOOL FreeGuardTail(void *pMem);
  257. void *AllocGuardHead(size_t nSize);
  258. BOOL FreeGuardHead(void *pMem);
  259. private:
  260. struct CAllocation
  261. {
  262. DWORD m_dwMagic1;
  263. BOOL (CGuardAllocator::*pfnFree)(void *pMem);
  264. CAllocation *m_pPrev;
  265. CAllocation *m_pNext;
  266. size_t m_nSize;
  267. UINT m_nStackFrames;
  268. UINT m_nID;
  269. DWORD m_dwMagic2;
  270. int Dump(HANDLE hProcess, PSTR pBuffer, int nBufferSize) const;
  271. bool IsValid() const
  272. {
  273. return m_dwMagic1 == '>>>>' && m_dwMagic2 == '<<<<';
  274. }
  275. };
  276. private:
  277. LONG m_nInitCount;
  278. LONG m_lFlags;
  279. size_t m_nPageSize;
  280. HANDLE m_hProcess;
  281. HANDLE m_hProcessHeap;
  282. DWORD m_dwOsVersion;
  283. CAllocation m_Head;
  284. UINT m_nAllocations;
  285. UINT m_nNextID;
  286. CRITICAL_SECTION m_HeapLock;
  287. PCSTR m_pLeaksFileName;
  288. };
  289. //////////////////////////////////////////////////////////////////////////
  290. //
  291. //
  292. //
  293. extern CGuardAllocator g_GuardAllocator;
  294. //////////////////////////////////////////////////////////////////////////
  295. //
  296. //
  297. //
  298. #ifdef IMPLEMENT_GUARDALLOC
  299. //////////////////////////////////////////////////////////////////////////
  300. //
  301. //
  302. //
  303. #include <pshpack1.h>
  304. struct CRelativeJmp
  305. {
  306. CRelativeJmp(PBYTE pFromAddr, PBYTE pToAddr)
  307. {
  308. jmp = 0xE9;
  309. addr = pToAddr - (pFromAddr + 5);
  310. }
  311. BYTE jmp;
  312. INT_PTR addr;
  313. };
  314. #include <poppack.h>
  315. BOOL ReplaceProc(FARPROC pOldProc, FARPROC pNewProc)
  316. {
  317. CRelativeJmp Code((PBYTE) pOldProc, (PBYTE) pNewProc);
  318. DWORD dwNumberOfBytesWritten;
  319. return WriteProcessMemory(
  320. GetCurrentProcess(),
  321. pOldProc,
  322. &Code,
  323. sizeof(Code),
  324. &dwNumberOfBytesWritten
  325. );
  326. }
  327. inline PVOID FindPtr(PVOID pBase, UINT_PTR pOffset, PIMAGE_SECTION_HEADER psh)
  328. {
  329. //*** return (PBYTE) pBase + pOffset - psh->VirtualAddress + psh->PointerToRawData;
  330. return (PBYTE) pBase + pOffset;
  331. }
  332. PIMAGE_FILE_HEADER FindImageFileHeader(PVOID pBase)
  333. {
  334. WORD wMagic = *(WORD *) pBase;
  335. if (wMagic == IMAGE_DOS_SIGNATURE)
  336. {
  337. PIMAGE_DOS_HEADER pdh = (PIMAGE_DOS_HEADER) pBase;
  338. if (pdh->e_lfanew)
  339. {
  340. DWORD dwMagic = *(DWORD *) ((PBYTE) pBase + pdh->e_lfanew);
  341. if (dwMagic == IMAGE_NT_SIGNATURE)
  342. {
  343. return (PIMAGE_FILE_HEADER) ((PBYTE) pBase + pdh->e_lfanew + sizeof(DWORD));
  344. }
  345. }
  346. }
  347. return 0;
  348. }
  349. PVOID
  350. FindImageDirectoryEntry(
  351. PVOID pBase,
  352. int nDirectory,
  353. PIMAGE_SECTION_HEADER &psh
  354. )
  355. {
  356. PIMAGE_FILE_HEADER pfh = FindImageFileHeader(pBase);
  357. if (pfh && pfh->SizeOfOptionalHeader)
  358. {
  359. PIMAGE_OPTIONAL_HEADER poh = (PIMAGE_OPTIONAL_HEADER)(pfh + 1);
  360. if (poh->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
  361. {
  362. DWORD VADirectory = poh->DataDirectory[nDirectory].VirtualAddress;
  363. if (VADirectory)
  364. {
  365. psh = (PIMAGE_SECTION_HEADER) ((PBYTE) poh + pfh->SizeOfOptionalHeader);
  366. for (int nSection = 0; nSection < pfh->NumberOfSections; ++nSection)
  367. {
  368. if (
  369. psh->VirtualAddress <= VADirectory &&
  370. psh->VirtualAddress + psh->SizeOfRawData > VADirectory
  371. )
  372. {
  373. return FindPtr(pBase, VADirectory, psh);
  374. }
  375. ++psh;
  376. }
  377. }
  378. }
  379. }
  380. return 0;
  381. }
  382. FARPROC *FindImport(PBYTE pBase, PCSTR pDllName, PCSTR pProcName)
  383. {
  384. PIMAGE_SECTION_HEADER psh;
  385. PIMAGE_IMPORT_DESCRIPTOR pImportDir =
  386. (PIMAGE_IMPORT_DESCRIPTOR) FindImageDirectoryEntry(pBase, IMAGE_DIRECTORY_ENTRY_IMPORT, psh);
  387. if (pImportDir)
  388. {
  389. while (pImportDir->Name)
  390. {
  391. PCSTR pName = (PCSTR) FindPtr(pBase, pImportDir->Name, psh);
  392. if (stricmp(pName, pDllName) == 0)
  393. {
  394. PINT_PTR pHintNameArray = (PINT_PTR) FindPtr(pBase, pImportDir->Characteristics, psh);
  395. PINT_PTR ppImportByName = pHintNameArray;
  396. while (*ppImportByName)
  397. {
  398. if (*ppImportByName > 0)
  399. {
  400. PIMAGE_IMPORT_BY_NAME pImportByName = (PIMAGE_IMPORT_BY_NAME) FindPtr(pBase, *ppImportByName, psh);
  401. if (strcmp((PCSTR) pImportByName->Name, pProcName) == 0)
  402. {
  403. FARPROC *pImportAddressTable = (FARPROC *) FindPtr(pBase, pImportDir->FirstThunk, psh);
  404. return pImportAddressTable + (ppImportByName - pHintNameArray);
  405. }
  406. }
  407. ++ppImportByName;
  408. }
  409. }
  410. ++pImportDir;
  411. }
  412. }
  413. return 0;
  414. }
  415. BOOL ReplaceImport(HMODULE hModule, PCSTR pDllName, PCSTR pProcName, FARPROC pNewProc, FARPROC pExpected)
  416. {
  417. FARPROC *pImport = FindImport((PBYTE) hModule, pDllName, pProcName);
  418. if (pImport == 0)
  419. {
  420. return FALSE;
  421. }
  422. if (*pImport != pExpected)
  423. {
  424. //DebugBreak();
  425. }
  426. DWORD dwNumberOfBytesWritten;
  427. return WriteProcessMemory(
  428. GetCurrentProcess(),
  429. pImport,
  430. &pNewProc,
  431. sizeof(pNewProc),
  432. &dwNumberOfBytesWritten
  433. );
  434. }
  435. class CModules
  436. {
  437. public:
  438. CModules()
  439. {
  440. m_nModules = 0;
  441. InitializeCriticalSection(&m_LoadLibraryLock);
  442. }
  443. ~CModules()
  444. {
  445. DeleteCriticalSection(&m_LoadLibraryLock);
  446. }
  447. BOOL Add(PCSTR pName, HMODULE hModule)
  448. {
  449. EnterCriticalSection(&m_LoadLibraryLock);
  450. int nModule = Find(hModule);
  451. if (nModule == -1)
  452. {
  453. PCSTR pModuleName = GetFileNameA(pName);
  454. strcpy(m_Modules[m_nModules].szName, pModuleName);
  455. if (strchr(pModuleName, '.') == 0)
  456. {
  457. strcat(m_Modules[m_nModules].szName, ".dll");
  458. }
  459. m_Modules[m_nModules].hModule = hModule;
  460. m_Modules[m_nModules].nRefs = 1;
  461. ++m_nModules;
  462. }
  463. else
  464. {
  465. ++m_Modules[nModule].nRefs;
  466. }
  467. LeaveCriticalSection(&m_LoadLibraryLock);
  468. return nModule == -1;
  469. }
  470. void Free(HMODULE hModule)
  471. {
  472. EnterCriticalSection(&m_LoadLibraryLock);
  473. int nModule = Find(hModule);
  474. if (nModule == -1)
  475. {
  476. OutputDebugStringA("*** Trying to free unloaded dll\n");
  477. DebugBreak();
  478. }
  479. else
  480. {
  481. if (--m_Modules[nModule].nRefs == 0)
  482. {
  483. --m_nModules;
  484. for (int i = nModule; i < m_nModules; ++i)
  485. {
  486. m_Modules[i] = m_Modules[i + 1];
  487. }
  488. }
  489. }
  490. LeaveCriticalSection(&m_LoadLibraryLock);
  491. }
  492. private:
  493. int Find(PCSTR pName)
  494. {
  495. for (int i = 0; i < m_nModules; ++i)
  496. {
  497. if (stricmp(m_Modules[i].szName, pName) == 0)
  498. {
  499. return i;
  500. }
  501. }
  502. return -1;
  503. }
  504. int Find(HMODULE hModule)
  505. {
  506. for (int i = 0; i < m_nModules; ++i)
  507. {
  508. if (m_Modules[i].hModule == hModule)
  509. {
  510. return i;
  511. }
  512. }
  513. return -1;
  514. }
  515. private:
  516. struct CModule
  517. {
  518. CHAR szName[32];
  519. HMODULE hModule;
  520. int nRefs;
  521. };
  522. private:
  523. int m_nModules;
  524. CModule m_Modules[1000]; //bugbug
  525. CRITICAL_SECTION m_LoadLibraryLock;
  526. };
  527. typedef BOOL (*PFNENUMIMAGEMODULESPROC)(PCSTR pName, HMODULE pBase);
  528. VOID EnumImageModules(PCSTR pName, HMODULE pBase, PFNENUMIMAGEMODULESPROC pfnCallback)
  529. {
  530. if (pfnCallback(pName, pBase))
  531. {
  532. PIMAGE_SECTION_HEADER psh;
  533. PIMAGE_IMPORT_DESCRIPTOR pImportDir =
  534. (PIMAGE_IMPORT_DESCRIPTOR) FindImageDirectoryEntry((PBYTE) pBase, IMAGE_DIRECTORY_ENTRY_IMPORT, psh);
  535. if (pImportDir)
  536. {
  537. while (pImportDir->Name)
  538. {
  539. PSTR pModuleName = (PSTR) FindPtr((PBYTE) pBase, pImportDir->Name, psh);
  540. HMODULE hModuleBase = GetModuleHandleA(pModuleName);
  541. EnumImageModules(pModuleName, hModuleBase, pfnCallback);
  542. ++pImportDir;
  543. }
  544. }
  545. }
  546. }
  547. //////////////////////////////////////////////////////////////////////////
  548. //
  549. //
  550. //
  551. PVOID (WINAPI *g_pfnHeapAlloc)(HANDLE hHeap, DWORD dwFlags, SIZE_T nSize);
  552. PVOID WINAPI SysHeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T nSize)
  553. {
  554. return g_pfnHeapAlloc(hHeap, dwFlags, nSize);
  555. }
  556. BOOL (WINAPI *g_pfnHeapFree)(HANDLE hHeap, DWORD dwFlags, PVOID pMem);
  557. BOOL WINAPI SysHeapFree(HANDLE hHeap, DWORD dwFlags, PVOID pMem)
  558. {
  559. return g_pfnHeapFree(hHeap, dwFlags, pMem);
  560. }
  561. SIZE_T (WINAPI *g_pfnHeapSize)(HANDLE hHeap, DWORD dwFlags, LPCVOID pMem);
  562. SIZE_T WINAPI SysHeapSize(HANDLE hHeap, DWORD dwFlags, LPCVOID pMem)
  563. {
  564. return g_pfnHeapSize(hHeap, dwFlags, pMem);
  565. }
  566. PVOID (WINAPI *g_pfnHeapReAlloc)(HANDLE hHeap, DWORD dwFlags, LPVOID pMem, SIZE_T nSize);
  567. PVOID WINAPI SysHeapReAlloc(HANDLE hHeap, DWORD dwFlags, LPVOID pMem, SIZE_T nSize)
  568. {
  569. return g_pfnHeapReAlloc(hHeap, dwFlags, pMem, nSize);
  570. }
  571. BOOL (WINAPI *g_pfnHeapValidate)(HANDLE hHeap, DWORD dwFlags, LPCVOID pMem);
  572. BOOL WINAPI SysHeapValidate(HANDLE hHeap, DWORD dwFlags, LPCVOID pMem)
  573. {
  574. return g_pfnHeapValidate(hHeap, dwFlags, pMem);
  575. }
  576. //////////////////////////////////////////////////////////////////////////
  577. //
  578. //
  579. //
  580. __declspec(thread) static g_bDisable = FALSE;
  581. LPVOID WINAPI MyHeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T nSize)
  582. {
  583. return g_GuardAllocator.Alloc(dwFlags, nSize);
  584. }
  585. BOOL WINAPI MyHeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID pMem)
  586. {
  587. return g_GuardAllocator.Free(dwFlags, pMem);
  588. }
  589. SIZE_T WINAPI MyHeapSize(HANDLE hHeap, DWORD dwFlags, LPCVOID pMem)
  590. {
  591. return g_GuardAllocator.Size(dwFlags, pMem);
  592. }
  593. LPVOID WINAPI MyHeapReAlloc(HANDLE hHeap, DWORD dwFlags, LPVOID pMem, SIZE_T nSize)
  594. {
  595. return g_GuardAllocator.Realloc(dwFlags, pMem, nSize);
  596. }
  597. BOOL WINAPI MyHeapValidate(HANDLE hHeap, DWORD dwFlags, LPCVOID pMem)
  598. {
  599. return g_GuardAllocator.Validate(dwFlags, pMem);
  600. }
  601. //////////////////////////////////////////////////////////////////////////
  602. //
  603. //
  604. //
  605. CModules *g_pModules = 0;
  606. BOOL EnumImageModulesProc(PCSTR pName, HMODULE pBase);
  607. HMODULE (WINAPI *g_pfnLoadLibraryA)(LPCSTR lpLibFileName);
  608. HMODULE WINAPI MyLoadLibraryA(LPCSTR lpLibFileNameA)
  609. {
  610. HMODULE hModule = g_pfnLoadLibraryA(lpLibFileNameA);
  611. EnumImageModules(lpLibFileNameA, hModule, EnumImageModulesProc);
  612. return hModule;
  613. }
  614. HMODULE (WINAPI *g_pfnLoadLibraryW)(LPCWSTR lpLibFileName);
  615. HMODULE WINAPI MyLoadLibraryW(LPCWSTR lpLibFileNameW)
  616. {
  617. HMODULE hModule = g_pfnLoadLibraryW(lpLibFileNameW);
  618. int nSize = WideCharToMultiByte(CP_ACP, 0, lpLibFileNameW, -1, 0, 0, 0, 0);
  619. PSTR lpLibFileNameA = (PSTR) _alloca(nSize);
  620. WideCharToMultiByte(CP_ACP, 0, lpLibFileNameW, -1, lpLibFileNameA, nSize, 0, 0);
  621. EnumImageModules(lpLibFileNameA, hModule, EnumImageModulesProc);
  622. return hModule;
  623. }
  624. HMODULE (WINAPI *g_pfnLoadLibraryExA)(LPCSTR lpLibFileNameA, HANDLE hFile, DWORD dwFlags);
  625. HMODULE WINAPI MyLoadLibraryExA(LPCSTR lpLibFileNameA, HANDLE hFile, DWORD dwFlags)
  626. {
  627. HMODULE hModule = g_pfnLoadLibraryExA(lpLibFileNameA, hFile, dwFlags);
  628. EnumImageModules(lpLibFileNameA, hModule, EnumImageModulesProc);
  629. return hModule;
  630. }
  631. HMODULE (WINAPI *g_pfnLoadLibraryExW)(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags);
  632. HMODULE WINAPI MyLoadLibraryExW(LPCWSTR lpLibFileNameW, HANDLE hFile, DWORD dwFlags)
  633. {
  634. HMODULE hModule = g_pfnLoadLibraryExW(lpLibFileNameW, hFile, dwFlags);
  635. int nSize = WideCharToMultiByte(CP_ACP, 0, lpLibFileNameW, -1, 0, 0, 0, 0);
  636. PSTR lpLibFileNameA = (PSTR) _alloca(nSize);
  637. WideCharToMultiByte(CP_ACP, 0, lpLibFileNameW, -1, lpLibFileNameA, nSize, 0, 0);
  638. EnumImageModules(lpLibFileNameA, hModule, EnumImageModulesProc);
  639. return hModule;
  640. }
  641. BOOL (WINAPI *g_pfnFreeLibrary)(HMODULE hLibModule);
  642. BOOL WINAPI MyFreeLibrary(HMODULE hLibModule)
  643. {
  644. g_pModules->Free(hLibModule);
  645. return g_pfnFreeLibrary(hLibModule);
  646. }
  647. BOOL EnumImageModulesProc(PCSTR pName, HMODULE pBase)
  648. {
  649. if (!pBase || !g_pModules->Add(pName, pBase))
  650. {
  651. return FALSE;
  652. }
  653. //if (stricmp(pName, "user32.dll") == 0 || stricmp(pName, "user32") == 0)//***
  654. //{
  655. // return TRUE;
  656. //}
  657. OutputDebugStringA("Patching "); //***
  658. OutputDebugStringA(pName); //***
  659. OutputDebugStringA("\n"); //***
  660. ReplaceImport(pBase, "kernel32.dll", "LoadLibraryA", (FARPROC) MyLoadLibraryA, (FARPROC) g_pfnLoadLibraryA);
  661. ReplaceImport(pBase, "kernel32.dll", "LoadLibraryW", (FARPROC) MyLoadLibraryW, (FARPROC) g_pfnLoadLibraryW);
  662. ReplaceImport(pBase, "kernel32.dll", "LoadLibraryExA", (FARPROC) MyLoadLibraryExA, (FARPROC) g_pfnLoadLibraryExA);
  663. ReplaceImport(pBase, "kernel32.dll", "LoadLibraryExW", (FARPROC) MyLoadLibraryExW, (FARPROC) g_pfnLoadLibraryExW);
  664. ReplaceImport(pBase, "kernel32.dll", "FreeLibrary", (FARPROC) MyFreeLibrary, (FARPROC) g_pfnFreeLibrary);
  665. ReplaceImport(pBase, "kernel32.dll", "HeapAlloc", (FARPROC) MyHeapAlloc, (FARPROC) g_pfnHeapAlloc);
  666. ReplaceImport(pBase, "kernel32.dll", "HeapReAlloc", (FARPROC) MyHeapReAlloc, (FARPROC) g_pfnHeapReAlloc);
  667. ReplaceImport(pBase, "kernel32.dll", "HeapFree", (FARPROC) MyHeapFree, (FARPROC) g_pfnHeapFree);
  668. ReplaceImport(pBase, "kernel32.dll", "HeapSize", (FARPROC) MyHeapSize, (FARPROC) g_pfnHeapSize);
  669. ReplaceImport(pBase, "kernel32.dll", "HeapValidate", (FARPROC) MyHeapValidate, (FARPROC) g_pfnHeapValidate);
  670. return TRUE;
  671. }
  672. void CGuardAllocator::Create(LONG lFlags)
  673. {
  674. SetGuardType(lFlags);
  675. if (m_nInitCount++ == 0)
  676. {
  677. OutputDebugStringA("Initializing debug heap\n");
  678. SYSTEM_INFO si;
  679. GetSystemInfo(&si);
  680. m_nPageSize = si.dwPageSize;
  681. m_Head.m_pNext = &m_Head;
  682. m_Head.m_pPrev = &m_Head;
  683. m_nAllocations = 0;
  684. m_nNextID = 0;
  685. InitializeCriticalSection(&m_HeapLock);
  686. m_hProcess = GetCurrentProcess();
  687. m_hProcessHeap = GetProcessHeap();
  688. m_dwOsVersion = GetVersion();
  689. HMODULE hKernel32 = GetModuleHandle(TEXT("kernel32.dll"));
  690. *(FARPROC*)& g_pfnLoadLibraryA = GetProcAddress(hKernel32, "LoadLibraryA");
  691. *(FARPROC*)& g_pfnLoadLibraryW = GetProcAddress(hKernel32, "LoadLibraryW");
  692. *(FARPROC*)& g_pfnLoadLibraryExA = GetProcAddress(hKernel32, "LoadLibraryExA");
  693. *(FARPROC*)& g_pfnLoadLibraryExW = GetProcAddress(hKernel32, "LoadLibraryExW");
  694. *(FARPROC*)& g_pfnFreeLibrary = GetProcAddress(hKernel32, "FreeLibrary");
  695. *(FARPROC*)& g_pfnHeapAlloc = GetProcAddress(hKernel32, "HeapAlloc");
  696. *(FARPROC*)& g_pfnHeapReAlloc = GetProcAddress(hKernel32, "HeapReAlloc");
  697. *(FARPROC*)& g_pfnHeapFree = GetProcAddress(hKernel32, "HeapFree");
  698. *(FARPROC*)& g_pfnHeapSize = GetProcAddress(hKernel32, "HeapSize");
  699. *(FARPROC*)& g_pfnHeapValidate = GetProcAddress(hKernel32, "HeapValidate");
  700. g_pModules = new CModules;
  701. if (m_dwOsVersion & 0x80000000 == 0)
  702. {
  703. CHAR szModuleName[MAX_PATH];
  704. GetModuleFileNameA(0, szModuleName, MAX_PATH);
  705. EnumImageModules(
  706. szModuleName,
  707. GetModuleHandle(0),
  708. EnumImageModulesProc
  709. );
  710. /*ReplaceProc((FARPROC) g_pfnHeapAlloc, (FARPROC) MyHeapAlloc);
  711. ReplaceProc((FARPROC) g_pfnHeapReAlloc, (FARPROC) MyHeapReAlloc);
  712. ReplaceProc((FARPROC) g_pfnHeapSize, (FARPROC) MyHeapSize);
  713. ReplaceProc((FARPROC) g_pfnHeapFree, (FARPROC) MyHeapFree);
  714. ReplaceProc((FARPROC) g_pfnHeapFree, (FARPROC) MyHeapValidate);*/
  715. }
  716. m_pLeaksFileName = 0;
  717. }
  718. }
  719. //////////////////////////////////////////////////////////////////////////
  720. //
  721. //
  722. //
  723. void CGuardAllocator::Destroy()
  724. {
  725. if (m_pLeaksFileName)
  726. {
  727. FILE *fout = fopen(m_pLeaksFileName, "wt");
  728. Walk(fout);
  729. fclose(fout);
  730. }
  731. if (--m_nInitCount == 0)
  732. {
  733. DeleteCriticalSection(&m_HeapLock);
  734. delete g_pModules;
  735. }
  736. }
  737. //////////////////////////////////////////////////////////////////////////
  738. //
  739. //
  740. //
  741. void CGuardAllocator::SetGuardType(LONG lFlags)
  742. {
  743. //bugbug: this is not MT safe
  744. m_lFlags = lFlags;
  745. switch (m_lFlags & GUARD_FLAGS)
  746. {
  747. case GUARD_NONE:
  748. pfnAlloc = AllocGuardNone;
  749. pfnFree = FreeGuardNone;
  750. break;
  751. case GUARD_TAIL:
  752. pfnAlloc = AllocGuardTail;
  753. pfnFree = FreeGuardTail;
  754. break;
  755. case GUARD_HEAD:
  756. pfnAlloc = AllocGuardHead;
  757. pfnFree = FreeGuardHead;
  758. break;
  759. }
  760. }
  761. //////////////////////////////////////////////////////////////////////////
  762. //
  763. //
  764. //
  765. void CGuardAllocator::Walk(FILE *fout)
  766. {
  767. g_bDisable = TRUE;
  768. SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES);
  769. SymInitialize(m_hProcess, 0, TRUE);
  770. const int nBufferSize = 16*1024;
  771. CHAR Buffer[nBufferSize];
  772. int nLeakedAllocs = 0;
  773. size_t nLeakedBytes = 0;
  774. EnterCriticalSection(&m_HeapLock);
  775. for (
  776. CAllocation *pAllocation = m_Head.m_pNext;
  777. pAllocation != &m_Head;
  778. pAllocation = pAllocation->m_pNext
  779. )
  780. {
  781. int nLength = pAllocation->Dump(m_hProcess, Buffer, nBufferSize);
  782. fwrite(Buffer, 1, nLength, fout);
  783. //OutputDebugStringA(Buffer);
  784. nLeakedAllocs += 1;
  785. nLeakedBytes += pAllocation->m_nSize;
  786. }
  787. if (nLeakedAllocs != 0)
  788. {
  789. int nLength = _snprintf(
  790. Buffer,
  791. nBufferSize,
  792. "\nLeaked %d bytes in %d allocations (%d total)\n",
  793. nLeakedBytes,
  794. nLeakedAllocs,
  795. m_nAllocations
  796. );
  797. fwrite(Buffer, 1, nLength, fout);
  798. //OutputDebugStringA(Buffer);
  799. }
  800. LeaveCriticalSection(&m_HeapLock);
  801. SymCleanup(m_hProcess);
  802. g_bDisable = FALSE;
  803. }
  804. //////////////////////////////////////////////////////////////////////////
  805. //
  806. //
  807. //
  808. int CGuardAllocator::CAllocation::Dump(HANDLE hProcess, PSTR pBuffer, int nBufferSize) const
  809. {
  810. int nLength = _snprintf(
  811. pBuffer,
  812. nBufferSize,
  813. "\nAllocation @%p, %d bytes\n",
  814. this,
  815. m_nSize
  816. );
  817. size_t nStackFramesSize = Align(m_nStackFrames * sizeof(CStackFrame), ALIGNMENT);
  818. CStackFrame *pStackFrame = (CStackFrame *) ((PBYTE) this - nStackFramesSize);
  819. for (UINT i = 0; i < m_nStackFrames; ++i, ++pStackFrame)
  820. {
  821. nLength += pStackFrame->Dump(
  822. hProcess,
  823. pBuffer + nLength,
  824. nBufferSize - nLength
  825. );
  826. }
  827. return nLength;
  828. }
  829. //////////////////////////////////////////////////////////////////////////
  830. //
  831. //
  832. //
  833. HANDLE CGuardAllocator::TakeSnapShot()
  834. {
  835. g_bDisable = TRUE;
  836. UINT *pSnapShot = (UINT *) Alloc(0, m_nAllocations * sizeof(UINT));
  837. int nAllocation = 0;
  838. for (
  839. CAllocation *pAllocation = m_Head.m_pNext;
  840. pAllocation != &m_Head;
  841. pAllocation = pAllocation->m_pNext
  842. )
  843. {
  844. pSnapShot[nAllocation++] = pAllocation->m_nID;
  845. }
  846. g_bDisable = FALSE;
  847. return (HANDLE) pSnapShot;
  848. }
  849. //////////////////////////////////////////////////////////////////////////
  850. //
  851. //
  852. //
  853. void CGuardAllocator::DeleteSnapShot(HANDLE hSnapShot)
  854. {
  855. g_bDisable = TRUE;
  856. Free(0, hSnapShot);
  857. g_bDisable = FALSE;
  858. }
  859. //////////////////////////////////////////////////////////////////////////
  860. //
  861. //
  862. //
  863. void CGuardAllocator::Diff(HANDLE hSnapShot, FILE *fout)
  864. {
  865. g_bDisable = TRUE;
  866. SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES);
  867. SymInitialize(m_hProcess, 0, TRUE);
  868. const int nBufferSize = 16*1024;
  869. CHAR Buffer[nBufferSize];
  870. UINT *pSnapShot = (UINT *) hSnapShot;
  871. int nAllocation = 0;
  872. for (
  873. CAllocation *pAllocation = m_Head.m_pNext;
  874. pAllocation != &m_Head;
  875. pAllocation = pAllocation->m_pNext
  876. )
  877. {
  878. while (pAllocation->m_nID < pSnapShot[nAllocation])
  879. {
  880. ++nAllocation;
  881. }
  882. if (pAllocation->m_nID != pSnapShot[nAllocation])
  883. {
  884. int nLength = pAllocation->Dump(m_hProcess, Buffer, nBufferSize);
  885. fwrite(Buffer, 1, nLength, fout);
  886. //OutputDebugStringA(Buffer);
  887. }
  888. }
  889. SymCleanup(m_hProcess);
  890. g_bDisable = FALSE;
  891. }
  892. //////////////////////////////////////////////////////////////////////////
  893. //
  894. //
  895. //
  896. template <int> struct static_assert { enum { is_non_zero }; };
  897. template <> struct static_assert<0> { enum { is_zero }; };
  898. void *CGuardAllocator::Alloc(DWORD dwFlags, size_t nSize)
  899. {
  900. if (m_nInitCount == 0)
  901. {
  902. OutputDebugStringA("Heap call before initialization\n");
  903. DebugBreak();
  904. }
  905. if (g_bDisable)
  906. {
  907. return SysHeapAlloc(m_hProcessHeap, dwFlags, nSize);
  908. }
  909. g_bDisable = TRUE;
  910. const int nMaxStackDepth = 20;
  911. CStackFrame StackFrames[nMaxStackDepth + 1];
  912. int nStackFrames = 0;
  913. if (m_lFlags & SAVE_STACK_FRAMES)
  914. {
  915. // get the context of the current thread
  916. CONTEXT Context;
  917. if (m_dwOsVersion & 0x80000000)
  918. {
  919. __try
  920. {
  921. RaiseException(0, 0, 0, 0);
  922. }
  923. __except(GetExceptionContext(GetExceptionInformation(), &Context))
  924. {
  925. }
  926. }
  927. else
  928. {
  929. Context.ContextFlags = CONTEXT_CONTROL;
  930. GetThreadContext(GetCurrentThread(), &Context);
  931. }
  932. // bugbug: putting the above block in a function like
  933. // GetCurrentThreadContext(&Context); doesn't seem to work
  934. // capture the stack frames
  935. CStackFrame StackFrame(&Context);
  936. while (nStackFrames < nMaxStackDepth && StackFrame.Walk())
  937. {
  938. StackFrames[nStackFrames++] = StackFrame;
  939. }
  940. }
  941. //static_assert<sizeof(CAllocation) % ALIGNMENT>::is_zero;
  942. size_t nStackFramesSize = Align(nStackFrames * sizeof(CStackFrame), ALIGNMENT);
  943. // allocate memory (large enough for the stack frames + allocation data size + requested size)
  944. // bugbug: putting CAllocation at front doesn't make sense for GUARD_HEAD
  945. void *pMem = (this->*pfnAlloc)(nStackFramesSize + sizeof(CAllocation) + nSize);
  946. g_bDisable = FALSE;
  947. if (pMem == 0)
  948. {
  949. OutputDebugStringA("*** Out of memory in alloc()\n");
  950. return 0;
  951. }
  952. // copy the stack frames first
  953. CopyMemory(pMem, StackFrames, nStackFramesSize);
  954. // next, fill in the allocation data
  955. CAllocation *pAllocation = (CAllocation *) ((PBYTE)pMem + nStackFramesSize);
  956. pAllocation->m_dwMagic1 = '>>>>';
  957. pAllocation->m_nSize = nSize;
  958. pAllocation->m_nStackFrames = nStackFrames;
  959. pAllocation->pfnFree = pfnFree;
  960. pAllocation->m_dwMagic2 = '<<<<';
  961. EnterCriticalSection(&m_HeapLock);
  962. pAllocation->m_pPrev = &m_Head;
  963. pAllocation->m_pNext = m_Head.m_pNext;
  964. pAllocation->m_pPrev->m_pNext = pAllocation;
  965. pAllocation->m_pNext->m_pPrev = pAllocation;
  966. pAllocation->m_nID = m_nNextID++;
  967. ++m_nAllocations;
  968. LeaveCriticalSection(&m_HeapLock);
  969. // return the end of allocation data struct as the allocated memory
  970. return pAllocation + 1;
  971. }
  972. //////////////////////////////////////////////////////////////////////////
  973. //
  974. //
  975. //
  976. BOOL CGuardAllocator::Free(DWORD dwFlags, void *pMem)
  977. {
  978. if (m_nInitCount == 0)
  979. {
  980. OutputDebugStringA("Heap call before initialization\n");
  981. DebugBreak();
  982. }
  983. if (g_bDisable)
  984. {
  985. return SysHeapFree(m_hProcessHeap, dwFlags, pMem);
  986. }
  987. if (pMem == 0)
  988. {
  989. return TRUE;
  990. }
  991. // get to the allocation data, it comes just before the pointer
  992. CAllocation *pAllocation = (CAllocation *) pMem - 1;
  993. if (!pAllocation->IsValid())
  994. {
  995. OutputDebugStringA("*** Invalid pointer passed to free()\n");
  996. //***DebugBreak();
  997. return FALSE;
  998. }
  999. // unlink this block
  1000. EnterCriticalSection(&m_HeapLock);
  1001. pAllocation->m_pPrev->m_pNext = pAllocation->m_pNext;
  1002. pAllocation->m_pNext->m_pPrev = pAllocation->m_pPrev;
  1003. --m_nAllocations;
  1004. LeaveCriticalSection(&m_HeapLock);
  1005. // get to head of the real allocated block and call the appropriate deallocator
  1006. size_t nStackFramesSize = Align(pAllocation->m_nStackFrames * sizeof(CStackFrame), ALIGNMENT);
  1007. return (this->*pAllocation->pfnFree)((PBYTE)pAllocation - nStackFramesSize);
  1008. }
  1009. //////////////////////////////////////////////////////////////////////////
  1010. //
  1011. //
  1012. //
  1013. size_t CGuardAllocator::Size(DWORD dwFlags, const void *pMem)
  1014. {
  1015. if (m_nInitCount == 0)
  1016. {
  1017. OutputDebugStringA("Heap call before initialization\n");
  1018. DebugBreak();
  1019. }
  1020. if (g_bDisable)
  1021. {
  1022. return SysHeapSize(m_hProcessHeap, dwFlags, pMem);
  1023. }
  1024. CAllocation *pAllocation = (CAllocation *) pMem - 1;
  1025. return pAllocation->m_nSize;
  1026. }
  1027. //////////////////////////////////////////////////////////////////////////
  1028. //
  1029. //
  1030. //
  1031. void *CGuardAllocator::Realloc(DWORD dwFlags, void *pMem, size_t nSize)
  1032. {
  1033. if (m_nInitCount == 0)
  1034. {
  1035. OutputDebugStringA("Heap call before initialization\n");
  1036. DebugBreak();
  1037. }
  1038. if (g_bDisable)
  1039. {
  1040. return SysHeapReAlloc(m_hProcessHeap, dwFlags, pMem, nSize);
  1041. }
  1042. CAllocation *pAllocation = (CAllocation *) pMem - 1;
  1043. if (!pAllocation->IsValid())
  1044. {
  1045. OutputDebugStringA("*** Invalid pointer passed to realloc()\n");
  1046. DebugBreak();
  1047. return 0;
  1048. }
  1049. void *pNewMem = Alloc(0, nSize);
  1050. CopyMemory(pNewMem, pMem, Size(0, pMem));
  1051. Free(0, pMem);
  1052. return pNewMem;
  1053. }
  1054. //////////////////////////////////////////////////////////////////////////
  1055. //
  1056. //
  1057. //
  1058. BOOL CGuardAllocator::Validate(DWORD dwFlags, const void *pMem)
  1059. {
  1060. if (m_nInitCount == 0)
  1061. {
  1062. OutputDebugStringA("Heap call before initialization\n");
  1063. DebugBreak();
  1064. }
  1065. if (g_bDisable)
  1066. {
  1067. return SysHeapValidate(m_hProcessHeap, dwFlags, pMem);
  1068. }
  1069. BOOL bValid = TRUE;
  1070. EnterCriticalSection(&m_HeapLock);
  1071. __try
  1072. {
  1073. if (pMem)
  1074. {
  1075. CAllocation *pAllocation = (CAllocation *) pMem - 1;
  1076. if (!pAllocation->IsValid())
  1077. {
  1078. bValid = FALSE;
  1079. }
  1080. }
  1081. else
  1082. {
  1083. for (
  1084. CAllocation *pAllocation = m_Head.m_pNext;
  1085. pAllocation != &m_Head && bValid;
  1086. pAllocation = pAllocation->m_pNext
  1087. )
  1088. {
  1089. if (!pAllocation->IsValid())
  1090. {
  1091. bValid = FALSE;
  1092. }
  1093. }
  1094. }
  1095. }
  1096. __except(EXCEPTION_EXECUTE_HANDLER)
  1097. {
  1098. bValid = FALSE;
  1099. }
  1100. LeaveCriticalSection(&m_HeapLock);
  1101. return bValid;
  1102. }
  1103. //////////////////////////////////////////////////////////////////////////
  1104. //
  1105. //
  1106. //
  1107. void *CGuardAllocator::AllocGuardNone(size_t nSize)
  1108. {
  1109. return SysHeapAlloc(m_hProcessHeap, HEAP_ZERO_MEMORY, nSize);
  1110. }
  1111. //////////////////////////////////////////////////////////////////////////
  1112. //
  1113. //
  1114. //
  1115. BOOL CGuardAllocator::FreeGuardNone(void *pMem)
  1116. {
  1117. return SysHeapFree(m_hProcessHeap, 0, pMem);
  1118. }
  1119. //////////////////////////////////////////////////////////////////////////
  1120. //
  1121. //
  1122. //
  1123. void *CGuardAllocator::AllocGuardTail(size_t nSize)
  1124. {
  1125. const size_t nAllocSize = Align(nSize, ALIGNMENT);
  1126. const size_t nTotalSize = Align(nAllocSize + m_nPageSize, m_nPageSize);
  1127. // reserve/allocate the memory
  1128. void *pBase = VirtualAlloc(
  1129. 0,
  1130. nTotalSize,
  1131. MEM_RESERVE,
  1132. PAGE_NOACCESS
  1133. );
  1134. if (!pBase)
  1135. {
  1136. return 0;
  1137. }
  1138. // commit the r/w memory
  1139. void *pAlloc = VirtualAlloc(
  1140. pBase,
  1141. nTotalSize - m_nPageSize,
  1142. MEM_COMMIT,
  1143. PAGE_EXECUTE_READWRITE
  1144. );
  1145. if (!pAlloc)
  1146. {
  1147. VirtualFree(pBase, 0, MEM_RELEASE);
  1148. return 0;
  1149. }
  1150. // commit the guard page
  1151. void *pGuard = VirtualAlloc(
  1152. (PBYTE) pBase + nTotalSize - m_nPageSize,
  1153. m_nPageSize,
  1154. MEM_COMMIT,
  1155. PAGE_NOACCESS
  1156. );
  1157. if (!pGuard)
  1158. {
  1159. VirtualFree(pAlloc, 0, MEM_DECOMMIT);
  1160. VirtualFree(pBase, 0, MEM_RELEASE);
  1161. return 0;
  1162. }
  1163. return (PBYTE) pBase + nTotalSize - m_nPageSize - nAllocSize;
  1164. }
  1165. //////////////////////////////////////////////////////////////////////////
  1166. //
  1167. //
  1168. //
  1169. BOOL CGuardAllocator::FreeGuardTail(void *pMem)
  1170. {
  1171. PVOID pBase = (PVOID) ((UINT_PTR) pMem & ~(m_nPageSize-1));
  1172. return VirtualFree(pBase, 0, MEM_RELEASE);
  1173. }
  1174. //////////////////////////////////////////////////////////////////////////
  1175. //
  1176. //
  1177. //
  1178. void *CGuardAllocator::AllocGuardHead(size_t nSize)
  1179. {
  1180. const size_t nAllocSize = Align(nSize, ALIGNMENT);
  1181. const size_t nTotalSize = Align(nAllocSize + m_nPageSize, m_nPageSize);
  1182. // reserve/allocate the memory
  1183. void *pBase = VirtualAlloc(
  1184. 0,
  1185. nTotalSize,
  1186. MEM_RESERVE,
  1187. PAGE_NOACCESS
  1188. );
  1189. if (!pBase)
  1190. {
  1191. return 0;
  1192. }
  1193. // commit the r/w memory
  1194. void *pAlloc = VirtualAlloc(
  1195. (PBYTE) pBase + m_nPageSize,
  1196. nTotalSize - m_nPageSize,
  1197. MEM_COMMIT,
  1198. PAGE_EXECUTE_READWRITE
  1199. );
  1200. if (!pAlloc)
  1201. {
  1202. VirtualFree(pBase, 0, MEM_RELEASE);
  1203. return 0;
  1204. }
  1205. // commit the guard page
  1206. void *pGuard = VirtualAlloc(
  1207. pBase,
  1208. m_nPageSize,
  1209. MEM_COMMIT,
  1210. PAGE_NOACCESS
  1211. );
  1212. if (!pGuard)
  1213. {
  1214. VirtualFree(pAlloc, 0, MEM_DECOMMIT);
  1215. VirtualFree(pBase, 0, MEM_RELEASE);
  1216. return 0;
  1217. }
  1218. return (PBYTE) pBase + m_nPageSize;
  1219. }
  1220. //////////////////////////////////////////////////////////////////////////
  1221. //
  1222. //
  1223. //
  1224. BOOL CGuardAllocator::FreeGuardHead(void *pMem)
  1225. {
  1226. PVOID pBase = (PVOID) ((UINT_PTR) pMem - m_nPageSize);
  1227. return VirtualFree(pBase, 0, MEM_RELEASE);
  1228. }
  1229. //////////////////////////////////////////////////////////////////////////
  1230. //
  1231. //
  1232. //
  1233. #ifdef _DLL
  1234. #pragma message("Need to link with static CRT libs to be able to replace malloc/free")
  1235. #else //_DLL
  1236. //////////////////////////////////////////////////////////////////////////
  1237. //
  1238. //
  1239. //
  1240. void * __cdecl ::operator new(size_t nSize)
  1241. {
  1242. return g_GuardAllocator.Alloc(0, nSize);
  1243. }
  1244. #ifdef _DEBUG
  1245. void* __cdecl operator new(size_t nSize, int, LPCSTR, int)
  1246. {
  1247. return g_GuardAllocator.Alloc(0, nSize);
  1248. }
  1249. #endif //_DEBUG
  1250. void __cdecl ::operator delete(void *pMem)
  1251. {
  1252. g_GuardAllocator.Free(0, pMem);
  1253. }
  1254. //////////////////////////////////////////////////////////////////////////
  1255. //
  1256. //
  1257. //
  1258. extern "C"
  1259. {
  1260. #undef _malloc_dbg
  1261. #undef _free_dbg
  1262. #undef _msize_dbg
  1263. #undef _realloc_dbg
  1264. #undef _expand_dbg
  1265. void * __cdecl malloc(size_t nSize)
  1266. {
  1267. return g_GuardAllocator.Alloc(0, nSize);
  1268. }
  1269. void * __cdecl _malloc_dbg(size_t nSize, int, const char *, int)
  1270. {
  1271. return g_GuardAllocator.Alloc(0, nSize);
  1272. }
  1273. void __cdecl free(void *pMem)
  1274. {
  1275. g_GuardAllocator.Free(0, pMem);
  1276. }
  1277. void __cdecl _free_dbg(void *pMem, int)
  1278. {
  1279. g_GuardAllocator.Free(0, pMem);
  1280. }
  1281. size_t __cdecl _msize(void *pMem)
  1282. {
  1283. return g_GuardAllocator.Size(0, pMem);
  1284. }
  1285. size_t __cdecl _msize_dbg(void *pMem, int)
  1286. {
  1287. return g_GuardAllocator.Size(0, pMem);
  1288. }
  1289. void * __cdecl realloc(void *pMem, size_t nSize)
  1290. {
  1291. return g_GuardAllocator.Realloc(0, pMem, nSize);
  1292. }
  1293. void * __cdecl _realloc_dbg(void *pMem, size_t nSize, int, const char *, int)
  1294. {
  1295. return g_GuardAllocator.Realloc(0, pMem, nSize);
  1296. }
  1297. void * __cdecl _expand(void *, size_t)
  1298. {
  1299. return 0;
  1300. }
  1301. void * __cdecl _expand_dbg(void *, size_t, int, const char *, int)
  1302. {
  1303. return 0;
  1304. }
  1305. //////////////////////////////////////////////////////////////////////////
  1306. //
  1307. //
  1308. //
  1309. void __cdecl wWinMainCRTStartup();
  1310. void __cdecl WinMainCRTStartup();
  1311. void __cdecl wmainCRTStartup();
  1312. void __cdecl mainCRTStartup();
  1313. void __cdecl ModuleEntry()
  1314. {
  1315. g_GuardAllocator.Create();
  1316. #ifdef _CONSOLE
  1317. #ifdef UNICODE
  1318. wmainCRTStartup();
  1319. #else //UNICODE
  1320. mainCRTStartup();
  1321. #endif
  1322. #else //_CONSOLE
  1323. #ifdef UNICODE
  1324. wWinMainCRTStartup();
  1325. #else //UNICODE
  1326. WinMainCRTStartup();
  1327. #endif
  1328. #endif //_CONSOLE
  1329. g_GuardAllocator.Destroy();
  1330. }
  1331. }
  1332. //////////////////////////////////////////////////////////////////////////
  1333. //
  1334. //
  1335. //
  1336. #pragma comment(linker, "/force:multiple")
  1337. #pragma comment(linker, "/entry:ModuleEntry")
  1338. #endif //_DLL
  1339. #pragma comment(lib, "dbghelp")
  1340. #endif IMPLEMENT_GUARDALLOC
  1341. #endif //_GUARDALLOC_H_