Leaked source code of windows server 2003
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.

612 lines
15 KiB

  1. ////////////////////////////////////////////////////////////////////////////////
  2. // File: memCore.c
  3. //
  4. // This module which replaces the Win32 Global heap functions used by Word
  5. // with functions which place objects at the end of a physical page. In
  6. // this way, we hope to catch out-of-bounds memory references exactly where
  7. // they happen, helping to isolate heap corruption problems.
  8. //
  9. //
  10. // This module is not enabled for ship builds.
  11. //
  12. // lenoxb: 4/05/94
  13. //
  14. ////////////////////////////////////////////////////////////////////////////////
  15. #include "precomp.h"
  16. #if defined(_DEBUG) && (defined(_M_IX86) || defined (_M_ALPHA))
  17. #include "dbgmemp.h"
  18. static DWORD s_cbMemPage = 0; // Initialize to 0 so init can check
  19. static void * FreePvCore(void*);
  20. static LPVOID PvReallocCore(PVOID, DWORD, UINT);
  21. static LPVOID DoAlloc(UINT, DWORD);
  22. static void AddToList(struct head*);
  23. static void RemoveFromList(struct head*);
  24. static void TrackHeapUsage(long dcb);
  25. static DWORD idBlockNext;
  26. static struct head* phead;
  27. static CRITICAL_SECTION csMine;
  28. #undef GlobalAlloc
  29. #undef GlobalReAlloc
  30. #undef GlobalFree
  31. #undef GlobalLock
  32. #undef GlobalUnlock
  33. #undef GlobalSize
  34. #undef GlobalHandle
  35. BOOL g_fTrackHeapUsage;
  36. DWORD g_cbAllocMax;
  37. DWORD g_cbAlloc;
  38. /*
  39. *Function Name:InitDebugMem
  40. *
  41. *Parameters:
  42. *
  43. *Description: Initialize Memory Manager
  44. *
  45. *Returns:
  46. *
  47. */
  48. void WINAPI InitDebugMem(void)
  49. {
  50. SYSTEM_INFO SysInfo;
  51. Assert(!s_cbMemPage);
  52. InitializeCriticalSection(&csMine);
  53. GetSystemInfo( &SysInfo ); // get the system memory page size
  54. s_cbMemPage = SysInfo.dwPageSize;
  55. }
  56. BOOL WINAPI FiniDebugMem(void)
  57. {
  58. Assert(s_cbMemPage);
  59. s_cbMemPage = 0;
  60. DeleteCriticalSection(&csMine);
  61. if (!phead) // no outstanding mem blocks
  62. return FALSE;
  63. else
  64. {
  65. struct head* pheadThis = phead;
  66. char buf[256];
  67. OutputDebugStringA("Unfreed Memory Blocks\n");
  68. for ( ; pheadThis; pheadThis = pheadThis->pheadNext)
  69. {
  70. sprintf(buf, "ID %d size %d\n",
  71. pheadThis->idBlock,
  72. pheadThis->cbBlock
  73. );
  74. OutputDebugStringA(buf);
  75. }
  76. }
  77. return TRUE;
  78. }
  79. /* D B G L O B A L A L L O C */
  80. /*----------------------------------------------------------------------------
  81. %%Function: dbGlobalAlloc
  82. %%Contact: lenoxb
  83. Replacement for GlobalAlloc
  84. Now an Internal Routine
  85. ----------------------------------------------------------------------------*/
  86. static void * WINAPI dbGlobalAlloc(UINT uFlags, DWORD cb)
  87. {
  88. /* Send "tough" requests to actual memory manager */
  89. if ((uFlags & GMEM_DDESHARE) || ((uFlags & GMEM_MOVEABLE) && !fMove))
  90. return GlobalAlloc(uFlags,cb);
  91. if (uFlags & GMEM_MOVEABLE)
  92. {
  93. return HgAllocateMoveable(uFlags, cb);
  94. }
  95. return (void *) PvAllocateCore(uFlags, cb);
  96. }
  97. /* D B G L O B A L F R E E */
  98. /*----------------------------------------------------------------------------
  99. %%Function: dbGlobalFree
  100. %%Contact: lenoxb
  101. Replacement for GlobalFree()
  102. Now an internal routine
  103. ----------------------------------------------------------------------------*/
  104. static void * WINAPI dbGlobalFree(void * hMem)
  105. {
  106. void** ppv;
  107. if (!fMove && FActualHandle(hMem))
  108. return GlobalFree(hMem);
  109. ppv = PpvFromHandle(hMem);
  110. if (ppv)
  111. {
  112. if (FreePvCore(*ppv) != NULL)
  113. return hMem;
  114. *ppv = NULL;
  115. return NULL;
  116. }
  117. return FreePvCore (hMem);
  118. }
  119. /* D B G L O B A L S I Z E */
  120. /*----------------------------------------------------------------------------
  121. %%Function: dbGlobalSize
  122. %%Contact: lenoxb
  123. Replacement for GlobalSize()
  124. Now an internal routine
  125. ----------------------------------------------------------------------------*/
  126. static DWORD WINAPI dbGlobalSize(void * hMem)
  127. {
  128. void** ppv;
  129. HEAD * phead;
  130. if (!fMove && FActualHandle(hMem))
  131. return GlobalSize(hMem);
  132. if (hMem == 0)
  133. return 0;
  134. ppv = PpvFromHandle(hMem);
  135. phead = GetBlockHeader(ppv ? *ppv : hMem);
  136. return phead ? phead->cbBlock : 0;
  137. }
  138. /* D B G L O B A L R E A L L O C */
  139. /*----------------------------------------------------------------------------
  140. %%Function: dbGlobalReAlloc
  141. %%Contact: lenoxb
  142. Replacement for GlobalReAlloc()
  143. Now an internal routine
  144. ----------------------------------------------------------------------------*/
  145. static void * WINAPI dbGlobalReAlloc(void * hMem, DWORD cb, UINT uFlags)
  146. {
  147. LPVOID pvNew;
  148. void** ppv;
  149. if (!fMove && FActualHandle(hMem))
  150. return GlobalReAlloc(hMem,cb,uFlags);
  151. /* REVIEW: what's supposed to happen when hMem==NULL */
  152. ppv = PpvFromHandle(hMem);
  153. if (uFlags & GMEM_MODIFY) /* Modify block attributes */
  154. {
  155. if (uFlags & GMEM_MOVEABLE)
  156. {
  157. return HgModifyMoveable(hMem, cb, uFlags);
  158. }
  159. else
  160. {
  161. HEAD * phead;
  162. if (ppv == NULL) /* Already fixed */
  163. return hMem;
  164. phead = GetBlockHeader(*ppv);
  165. if (phead->cLock != 0) /* Don't realloc a locked block */
  166. return NULL;
  167. *ppv = NULL;
  168. return phead+1;
  169. }
  170. }
  171. if (ppv)
  172. {
  173. pvNew = PvReallocCore (*ppv, cb, uFlags);
  174. if (pvNew == NULL)
  175. return NULL;
  176. *ppv = pvNew;
  177. return hMem;
  178. }
  179. if (!(uFlags & GMEM_MOVEABLE))
  180. return NULL;
  181. return PvReallocCore (hMem, cb, uFlags);
  182. }
  183. /***********************************************
  184. External interface for routines that can track usage
  185. ***********************************************/
  186. void* WINAPI dbgMallocCore(size_t cb, BOOL fTrackUsage)
  187. {
  188. void* pv;
  189. // make sure we're initialized
  190. if (s_cbMemPage == 0)
  191. InitDebugMem();
  192. EnterCriticalSection(&csMine);
  193. pv = dbGlobalAlloc(GMEM_FIXED, cb);
  194. if (fTrackUsage)
  195. TrackHeapUsage((long)dbGlobalSize(pv));
  196. LeaveCriticalSection(&csMine);
  197. return pv;
  198. }
  199. void * WINAPI dbgFreeCore(void* pv, BOOL fTrackUsage)
  200. {
  201. void * hRes;
  202. // make sure we're initialized
  203. if (s_cbMemPage == 0)
  204. InitDebugMem();
  205. EnterCriticalSection(&csMine);
  206. if (fTrackUsage)
  207. TrackHeapUsage(-(long)dbGlobalSize(pv));
  208. hRes = dbGlobalFree(pv);
  209. LeaveCriticalSection(&csMine);
  210. return hRes;
  211. }
  212. void* WINAPI dbgReallocCore(void* pv, size_t cb, BOOL fTrackUsage)
  213. {
  214. long cbOld, cbNew;
  215. // make sure we're initialized
  216. if (s_cbMemPage == 0)
  217. InitDebugMem();
  218. EnterCriticalSection(&csMine);
  219. cbOld = dbGlobalSize(pv);
  220. pv = dbGlobalReAlloc(pv,cb,GMEM_MOVEABLE);
  221. if (pv && fTrackUsage)
  222. {
  223. cbNew = dbGlobalSize(pv);
  224. TrackHeapUsage(cbNew - cbOld);
  225. }
  226. LeaveCriticalSection(&csMine);
  227. return pv;
  228. }
  229. /**************************************************************
  230. Normal Public Interface
  231. **************************************************************/
  232. void* WINAPI dbgMalloc(size_t cb)
  233. {
  234. return dbgMallocCore(cb, FALSE);
  235. }
  236. void* WINAPI dbgCalloc(size_t c, size_t cb)
  237. {
  238. void *pMem = dbgMallocCore(cb * c, FALSE);
  239. if (pMem)
  240. {
  241. memset(pMem, 0, cb * c);
  242. }
  243. return pMem;
  244. }
  245. HLOCAL WINAPI dbgFree(void* pv)
  246. {
  247. return dbgFreeCore(pv, FALSE);
  248. }
  249. void* WINAPI dbgRealloc(void* pv, size_t cb)
  250. {
  251. return dbgReallocCore(pv, cb, FALSE);
  252. }
  253. static void TrackHeapUsage(long dcb)
  254. {
  255. long cbAlloc=0, cbAllocMax=0;
  256. if (!g_fTrackHeapUsage)
  257. return;
  258. g_cbAlloc += dcb;
  259. g_cbAllocMax = (g_cbAllocMax > g_cbAlloc ? g_cbAllocMax : g_cbAlloc);
  260. cbAlloc = g_cbAlloc;
  261. cbAllocMax = g_cbAllocMax;
  262. LeaveCriticalSection(&csMine);
  263. Assert(cbAlloc >= 0);
  264. Assert(cbAllocMax >= 0);
  265. }
  266. //////////////////////////////////////
  267. /// NLG (ex T-Hammer) interfaces ///
  268. //////////////////////////////////////
  269. BOOL WINAPI
  270. fNLGNewMemory(
  271. OUT PVOID *ppv,
  272. IN ULONG cb)
  273. {
  274. Assert(ppv != NULL && cb != 0);
  275. *ppv = dbgMalloc(cb);
  276. return *ppv != NULL;
  277. }
  278. DWORD WINAPI
  279. NLGMemorySize(
  280. VOID *pvMem)
  281. {
  282. Assert (pvMem != NULL);
  283. return dbGlobalSize(pvMem);
  284. }
  285. BOOL WINAPI
  286. fNLGResizeMemory(
  287. IN OUT PVOID *ppv,
  288. IN ULONG cbNew)
  289. {
  290. PVOID pv;
  291. Assert( ppv != NULL && *ppv != NULL && cbNew != 0 );
  292. // Note that the semantics of GMEM_MOVEABLE are different
  293. // between Alloc and ReAlloc; with ReAlloc, it only means that
  294. // it's OK for the realloc'ed block to start at a different location
  295. // than the original...
  296. pv = dbgRealloc(*ppv, cbNew);
  297. if (pv != NULL)
  298. {
  299. *ppv = pv;
  300. }
  301. return (pv != NULL);
  302. }
  303. VOID WINAPI
  304. NLGFreeMemory(
  305. IN PVOID pvMem)
  306. {
  307. Assert(pvMem != NULL);
  308. dbgFree(pvMem);
  309. }
  310. // These two are the same in retail and debug;
  311. // find a home for the retail versions...
  312. BOOL WINAPI
  313. fNLGHeapDestroy(
  314. VOID)
  315. {
  316. return TRUE;
  317. }
  318. /* G E T B L O C K H E A D E R */
  319. /*----------------------------------------------------------------------------
  320. %%Function: GetBlockHeader
  321. %%Contact: lenoxb
  322. tmp
  323. Returns memory block header associated with indicated handle.
  324. Generates access violation if passed an invalid handle.
  325. ------------------------------------------tmp----------------------------------*/
  326. static HEAD * GetBlockHeader(void* pvMem)
  327. {
  328. HEAD * phead = ((HEAD *) pvMem) - 1;
  329. Assert (!IsBadWritePtr(phead, sizeof *phead));
  330. return phead;
  331. }
  332. /* P V A L L O C A T E C O R E */
  333. /*----------------------------------------------------------------------------
  334. %%Function: PvAllocateCore
  335. %%Contact: lenoxb
  336. Workhorse routine to allocate memory blocks
  337. ----------------------------------------------------------------------------*/
  338. static LPVOID PvAllocateCore (UINT uFlags, DWORD cb)
  339. {
  340. HEAD headNew;
  341. HEAD *pAllocHead;
  342. DWORD cbTotal, cbPadded, cbPages;
  343. if (fPadBlocks)
  344. cbPadded = PAD(cb,4); /* For RISC platforms, makes sure the block is aligned */
  345. else
  346. cbPadded = cb;
  347. cbTotal = PAD(cbPadded + sizeof headNew, s_cbMemPage);
  348. if (fExtraReadPage)
  349. cbPages = cbTotal+1;
  350. else
  351. cbPages = cbTotal;
  352. cbPages += s_cbMemPage;
  353. headNew.dwTag = HEAD_TAG;
  354. headNew.cbBlock = cb;
  355. headNew.cLock = 0;
  356. headNew.idBlock = idBlockNext++;
  357. headNew.pheadNext = NULL;
  358. headNew.pbBase = VirtualAlloc(NULL,
  359. cbPages, MEM_RESERVE, PAGE_READWRITE
  360. );
  361. if (headNew.pbBase == NULL)
  362. return NULL;
  363. pAllocHead = VirtualAlloc(headNew.pbBase,
  364. cbTotal, MEM_COMMIT, PAGE_READWRITE
  365. );
  366. if (pAllocHead == NULL)
  367. {
  368. VirtualFree(headNew.pbBase, 0, MEM_RELEASE);
  369. return NULL;
  370. }
  371. headNew.pbBase = (LPBYTE)pAllocHead;
  372. if (fExtraReadPage)
  373. {
  374. if (!VirtualAlloc(headNew.pbBase+cbTotal,1, MEM_COMMIT, PAGE_READONLY))
  375. {
  376. VirtualFree(headNew.pbBase, 0, MEM_RELEASE);
  377. return NULL;
  378. }
  379. }
  380. // FUTURE: do something with PAGE_GUARD?
  381. if (!VirtualAlloc(headNew.pbBase + cbPages - s_cbMemPage,
  382. 1, MEM_COMMIT, PAGE_NOACCESS))
  383. {
  384. // the entire reserved range must be either committed or decommitted
  385. VirtualFree(headNew.pbBase, cbTotal, MEM_DECOMMIT);
  386. VirtualFree(headNew.pbBase, 0, MEM_RELEASE);
  387. return FALSE;
  388. }
  389. if ((uFlags & GMEM_ZEROINIT) == 0)
  390. memset(headNew.pbBase, bNewGarbage, cbTotal);
  391. pAllocHead = ((HEAD *)(headNew.pbBase + cbTotal - cbPadded));
  392. pAllocHead[-1] = headNew;
  393. AddToList(pAllocHead-1);
  394. return pAllocHead;
  395. }
  396. /* P V R E A L L O C C O R E */
  397. /*----------------------------------------------------------------------------
  398. %%Function: PvReallocCore
  399. %%Contact: lenoxb
  400. Workhorse routine to move memory blocks
  401. ----------------------------------------------------------------------------*/
  402. static LPVOID PvReallocCore (PVOID pvMem, DWORD cb, UINT uFlags)
  403. {
  404. LPVOID pvNew;
  405. DWORD cbOld;
  406. pvNew = (LPVOID) PvAllocateCore(uFlags, cb);
  407. if (!pvNew)
  408. return NULL;
  409. cbOld = dbGlobalSize(pvMem);
  410. if (cbOld>0 && cb>0)
  411. memcpy(pvNew, pvMem, cbOld<cb ? cbOld : cb);
  412. FreePvCore (pvMem);
  413. return pvNew;
  414. }
  415. /* F R E E P V C O R E */
  416. /*----------------------------------------------------------------------------
  417. %%Function: FreePvCore
  418. %%Contact: lenoxb
  419. Workhourse routine to free memory blocks.
  420. ----------------------------------------------------------------------------*/
  421. static void * FreePvCore (void* pvMem)
  422. {
  423. HEAD * phead;
  424. if (pvMem)
  425. {
  426. phead = GetBlockHeader(pvMem);
  427. if (phead->cLock != 0)
  428. return pvMem;
  429. RemoveFromList(phead);
  430. VirtualFree(phead->pbBase, 0, MEM_RELEASE);
  431. }
  432. return NULL;
  433. }
  434. struct head* dbgHead(void)
  435. {
  436. struct head* pheadThis = phead;
  437. if (pheadThis == NULL)
  438. return NULL;
  439. for (pheadThis=phead; pheadThis->pheadNext; pheadThis = pheadThis->pheadNext)
  440. continue;
  441. return pheadThis;
  442. }
  443. static void AddToList(struct head* pheadAdd)
  444. {
  445. EnterCriticalSection(&csMine);
  446. pheadAdd->pheadNext = phead;
  447. phead = pheadAdd;
  448. LeaveCriticalSection(&csMine);
  449. }
  450. static void RemoveFromList(struct head* pheadRemove)
  451. {
  452. struct head* pheadThis;
  453. struct head* pheadPrev;
  454. BOOL fFoundNode = FALSE;
  455. Assert(pheadRemove != NULL);
  456. EnterCriticalSection(&csMine);
  457. pheadPrev = NULL;
  458. for (pheadThis = phead; pheadThis; pheadThis = pheadThis->pheadNext)
  459. {
  460. if (pheadThis == pheadRemove)
  461. {
  462. if (pheadPrev == NULL)
  463. {
  464. Assert(pheadThis == phead);
  465. phead = pheadThis->pheadNext;
  466. }
  467. else
  468. {
  469. pheadPrev->pheadNext = pheadThis->pheadNext;
  470. }
  471. fFoundNode = TRUE;
  472. goto LExit;
  473. }
  474. pheadPrev = pheadThis;
  475. }
  476. LExit:
  477. LeaveCriticalSection(&csMine);
  478. Assert(fFoundNode); // Not on the list? Never happens.
  479. }
  480. #else // !defined(DEBUG) && defined(NTX86) || defined (M_ALPHA)
  481. void * WINAPI dbgCalloc(size_t c, size_t cb)
  482. {
  483. void *pMem = dbgMalloc(cb * c);
  484. if (pMem)
  485. {
  486. memset(pMem, 0, cb * c);
  487. }
  488. return pMem;
  489. }
  490. #endif //defined(DEBUG) && defined(NTX86) || defined (M_ALPHA)