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.

1039 lines
27 KiB

  1. /**************************************************************************\
  2. *
  3. * Copyright (c) 1999 Microsoft Corporation
  4. *
  5. * Module Name:
  6. *
  7. * GDI+ memory allocation functions
  8. *
  9. * Abstract:
  10. *
  11. * This module provides GpMalloc, GpRealloc and GpFree.
  12. *
  13. * Notes:
  14. *
  15. * Office provides their own versions of these functions.
  16. *
  17. * Created:
  18. *
  19. * 07/08/1999 agodfrey
  20. *
  21. \**************************************************************************/
  22. #include "precomp.hpp"
  23. namespace GpRuntime
  24. {
  25. HANDLE GpMemHeap = NULL;
  26. };
  27. #if GPMEM_ALLOC_CHK
  28. #if GPMEM_FAULT_INJECTION
  29. #include <time.h>
  30. #include <stdlib.h>
  31. #endif
  32. // Get the definition of Globals::CaptureStackBackTraceFunction
  33. #include "..\common\common.hpp"
  34. // Size of the start and end memory guards (DWORDS)
  35. // Probably should be QWORD aligned (even number).
  36. const unsigned int GPMEM_GUARD_START = 0x10;
  37. const unsigned int GPMEM_GUARD_END = 0x10;
  38. const unsigned int GPMEM_GS = GPMEM_GUARD_START*sizeof(DWORD);
  39. const unsigned int GPMEM_GE = GPMEM_GUARD_END*sizeof(DWORD);
  40. const unsigned char GPMEM_FILL_ALLOC = 0xbf;
  41. const unsigned char GPMEM_FILL_GS = 0xac;
  42. const unsigned char GPMEM_FILL_GE = 0xfe;
  43. const unsigned char GPMEM_FILL_FREE = 0x73;
  44. #define GPMEM_ALLOC_TRACKING 1
  45. #define GPMEM_ALLOC_FILL 1
  46. enum AllocTrackHeaderFlags
  47. {
  48. MemoryAllocated = 0x00000001,
  49. MemoryFreed = 0x00000002, // useful in catching double frees
  50. APIAllocation = 0x00000004
  51. };
  52. // Head of every tracked allocation.
  53. // From <ntrtl.h> -
  54. // #define MAX_STACK_DEPTH 32
  55. // Therefore we define our stack trace size to be 32 entries.
  56. // Number of Stack Frames stash away on every allocation.
  57. // Bear in mind that every allocation will have 4xGPMEM_STACKSIZE bytes
  58. // additional overhead. (8xGPMEM_STACKSIZE on ptr64 machines)
  59. #define GPMEM_STACKSIZE 32
  60. struct AllocTrackHeader {
  61. struct AllocTrackHeader *flink;
  62. struct AllocTrackHeader *blink;
  63. DWORD size;
  64. PVOID caller_address[GPMEM_STACKSIZE];
  65. DWORD flags;
  66. #if GPMEM_ALLOC_CHK_LIST
  67. char *callerFileName;
  68. INT callerLineNumber;
  69. #endif
  70. DWORD tag;
  71. DWORD padding; // padding to keep 8 byte alignment
  72. };
  73. #define GPMEM_OVERHEAD (GPMEM_GS + GPMEM_GE + sizeof(AllocTrackHeader))
  74. // Head of double linked list of tracked memory allocations.
  75. AllocTrackHeader *gpmemAllocList=NULL;
  76. // An allocation fails if rand() < gpmemDefFailRate (gpmemInitFailRate for
  77. // gdiplus initialization code.
  78. // set to RAND_MAX/2 if you want 50% failure rate, 0 if you want no failures.
  79. //
  80. // The system starts off failing allocations at a rate specified by
  81. // gpmemInitFailRate. Once GpDoneInitializeAllocFailureMode() is called,
  82. // allocations are failed at the rate specified by gpmemDefFailRate().
  83. // This is so that dll initialization code can have a different fail rate
  84. // to regular code.
  85. int gpmemInitFailRate = 0;
  86. int gpmemDefFailRate = 0;
  87. // This would give a failure rate of 25%
  88. // int gpmemDefFailRate = (RAND_MAX/4)
  89. BOOL gpmemDoneInitialization = FALSE;
  90. // Some statistics
  91. struct AllocTrackStats {
  92. // Totals over the entire run
  93. long CumulativeAllocations; // The number of calls to GpMalloc or GpRealloc
  94. long CumulativeMemorySize; // Cumulative total of allocated memory
  95. long CumulativeReallocs; // The number of calls to GpRealloc
  96. long ForcedFailures;
  97. long AllocationFailures;
  98. // Current values
  99. long OutstandingAllocations; // The number of allocation requests
  100. long OutstandingMemorySize; // The amount of memory currently allocated
  101. // Maxima of the 'Outstanding' values
  102. long MaxAllocations; // The maximum of OutstandingAllocations
  103. long MaxMemorySize; // The maximum of OutstandingMemorySize
  104. void Allocated(long size)
  105. {
  106. size -= GPMEM_OVERHEAD;
  107. CumulativeMemorySize += size;
  108. OutstandingMemorySize += size;
  109. if (OutstandingMemorySize > MaxMemorySize)
  110. {
  111. MaxMemorySize = OutstandingMemorySize;
  112. }
  113. CumulativeAllocations++;
  114. OutstandingAllocations++;
  115. if (OutstandingAllocations > MaxAllocations)
  116. {
  117. MaxAllocations = OutstandingAllocations;
  118. }
  119. }
  120. void Freed(long size)
  121. {
  122. size -= GPMEM_OVERHEAD;
  123. OutstandingMemorySize -= size;
  124. OutstandingAllocations--;
  125. }
  126. };
  127. AllocTrackStats gpmemAllocTotal = {0};
  128. // Hash Table for tracking memory allocations sorted by callsite.
  129. // This table stores some total memory usage statistics for each
  130. // callsite.
  131. // Turn this on by setting GPMEM_DEBUG_SORT 1
  132. #define GPMEM_DEBUG_SORT 0
  133. #if GPMEM_DEBUG_SORT
  134. struct HashMem {
  135. long callsite;
  136. long size;
  137. long count;
  138. };
  139. // It is very important that this hash size be larger than the number of
  140. // possible callsites for GpMalloc.
  141. //
  142. // Set HASHSIZE to some big prime number.
  143. #define HASHSIZE 1069
  144. HashMem HashTable[HASHSIZE];
  145. // Hashing algorithm.
  146. long Hash(long cs) {
  147. long tmp = cs % HASHSIZE;
  148. long tmploop = tmp;
  149. while( (HashTable[tmp].callsite != 0) &&
  150. (HashTable[tmp].callsite != cs) ) {
  151. tmp++;
  152. if(tmp>=HASHSIZE) tmp=0;
  153. if(tmp==tmploop) return -1;
  154. }
  155. return tmp;
  156. }
  157. #endif
  158. #endif
  159. /**************************************************************************\
  160. *
  161. * Function Description:
  162. *
  163. * Do we fail this memory allocation?
  164. *
  165. * Arguments: [NONE]
  166. * Return Value: [NONE]
  167. *
  168. * History:
  169. *
  170. * 09/20/1999 asecchia
  171. * Created it.
  172. *
  173. \**************************************************************************/
  174. #if GPMEM_ALLOC_CHK
  175. BOOL GpFailMemoryAllocation() {
  176. #if GPMEM_FAULT_INJECTION
  177. int rndnum = rand();
  178. if(gpmemDoneInitialization)
  179. {
  180. if(rndnum<gpmemDefFailRate)
  181. {
  182. return TRUE;
  183. }
  184. }
  185. else
  186. {
  187. if(rndnum<gpmemInitFailRate)
  188. {
  189. return TRUE;
  190. }
  191. }
  192. #endif
  193. return FALSE;
  194. }
  195. #endif
  196. /**************************************************************************\
  197. *
  198. * Function Description:
  199. *
  200. * Initializes the random seed.
  201. *
  202. * Arguments: [NONE]
  203. * Return Value: [NONE]
  204. *
  205. * History:
  206. *
  207. * 09/20/1999 asecchia
  208. * Created it.
  209. *
  210. \**************************************************************************/
  211. void GpInitializeAllocFailures() {
  212. #if GPMEM_ALLOC_CHK
  213. #if GPMEM_FAULT_INJECTION
  214. srand((unsigned)time(NULL));
  215. #endif
  216. #endif
  217. }
  218. /**************************************************************************\
  219. *
  220. * Function Description:
  221. *
  222. * Sets the flag indicating that we're done initialization code and
  223. * we're now into regular code. The memory failure mode changes based
  224. * on the value of this flag.
  225. *
  226. * Arguments: [NONE]
  227. * Return Value: [NONE]
  228. *
  229. * History:
  230. *
  231. * 09/20/1999 asecchia
  232. * Created it.
  233. *
  234. \**************************************************************************/
  235. void GpDoneInitializeAllocFailureMode() {
  236. #if GPMEM_ALLOC_CHK
  237. gpmemDoneInitialization=TRUE;
  238. #endif
  239. }
  240. void GpStartInitializeAllocFailureMode() {
  241. #if GPMEM_ALLOC_CHK
  242. gpmemDoneInitialization=FALSE;
  243. #endif
  244. }
  245. #if GPMEM_ALLOC_CHK_LIST
  246. char *skipGdiPlus(char *s) {
  247. // Quick hack to return pointer just beyond 'gdiplus'
  248. INT i = 0;
  249. while ( s[i] != 0
  250. && ( s[i] != 'g' && s[i] != 'G'
  251. || CompareStringA(
  252. LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
  253. s+i, 7,
  254. "gdiplus", 7) != CSTR_EQUAL))
  255. {
  256. i++;
  257. }
  258. if ( CompareStringA(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, s+i, 7, "gdiplus", 7) == CSTR_EQUAL
  259. && s[i+7] != 0)
  260. {
  261. return s + i + 8; // Skip over 'gdiplus/'
  262. }
  263. else
  264. {
  265. return s; // Didn't find gdiplus so return the whole string
  266. }
  267. }
  268. #endif
  269. /**************************************************************************\
  270. *
  271. * Function Description:
  272. *
  273. * Asserts that there are no memory leaks. Called just before process
  274. * termination, the list of allocated memory blocks should be NULL indicating
  275. * that all allocated memory was properly disposed. Any memory that relies on
  276. * process termination to clean up is leaked and provision should be made
  277. * for appropriate cleanup.
  278. *
  279. * Notes:
  280. *
  281. * Designed only to be called during shutdown, because it doesn't acquire
  282. * GpMallocTrackingCriticalSection.
  283. *
  284. * This is because, during shutdown, the critsec has not necessarily been
  285. * initialized. It's safe during shutdown because shutdown itself is
  286. * expected to be single-threaded.
  287. *
  288. * Todo after we ship:
  289. *
  290. * NTRAID#NTBUG9-411495-2001/06/06-agodfrey
  291. * The refcount is legacy anyway, and the "single-threaded shutdown" thing
  292. * may need to be changed. We should initialize all our global critsecs
  293. * in DllMain, so that we can rely on them during startup/shutdown.
  294. *
  295. * Once we've done that, this function can have the "shutdown only"
  296. * restriction removed - by making it once again acquire
  297. * GpMallocTrackingCriticalSection.
  298. *
  299. * Arguments: [NONE]
  300. * Return Value: [NONE]
  301. *
  302. * History:
  303. *
  304. * 09/19/1999 asecchia
  305. * Created it.
  306. *
  307. \**************************************************************************/
  308. void GpAssertShutdownNoMemoryLeaks()
  309. {
  310. #if GPMEM_ALLOC_CHK
  311. #if GPMEM_ALLOC_CHK_LIST
  312. // Report up to 100 leaked headers
  313. if (gpmemAllocList)
  314. {
  315. INT i=0; INT j=0;
  316. AllocTrackHeader *header = gpmemAllocList;
  317. while (header && j < 100)
  318. {
  319. if (i % 20 == 0) // Title every so often
  320. {
  321. WARNING(("Address- --Size-- API TAG -Caller- -Line- File"));
  322. }
  323. // Drop everything up to 'gdiplus' off the filename string
  324. char str[200];
  325. char *tagStr;
  326. tagStr = (char *) &header->tag;
  327. lstrcpynA(str, skipGdiPlus(header->callerFileName), 200);
  328. WARNING((
  329. "%p %8d %-3.3s %c%c%c%c %p %6d %s",
  330. header,
  331. header->size,
  332. header->flags & APIAllocation ? "API" : "",
  333. tagStr[3], tagStr[2], tagStr[1], tagStr[0],
  334. header->caller_address,
  335. header->callerLineNumber,
  336. str
  337. ));
  338. header = header->flink;
  339. i++; j++;
  340. }
  341. }
  342. #endif
  343. ASSERTMSG(
  344. gpmemAllocList==NULL,
  345. ("Memory leaks detected.\n"
  346. "List header (gdiplus!gpmemAllocList) at %p\n"
  347. "Use: dt AllocTrackHeader [address] to display the memory block headers.\n"
  348. "Use: dds [AllocTrackHeader.caller_address] to display the allocation stack.",
  349. gpmemAllocList)
  350. );
  351. // Display the report stored in the Hash Table
  352. #if GPMEM_DEBUG_SORT
  353. for(int i=0; i<HASHSIZE; i++) {
  354. if(HashTable[i].callsite != 0) {
  355. WARNING(("%4d callsite %p size %8d count %8d", i, HashTable[i].callsite,
  356. HashTable[i].size, HashTable[i].count));
  357. }
  358. }
  359. #endif
  360. #endif
  361. }
  362. #if GPMEM_ALLOC_CHK_LIST
  363. void
  364. GpTagMalloc(void * mem, GpTag tag, int bApi)
  365. {
  366. if(mem)
  367. {
  368. AllocTrackHeader *hdr = (AllocTrackHeader *)((char *) mem - sizeof(AllocTrackHeader) - GPMEM_GS);
  369. hdr->tag = (unsigned long) tag;
  370. if(bApi) hdr->flags |= APIAllocation;
  371. }
  372. }
  373. #endif
  374. /**************************************************************************\
  375. *
  376. * Function Description:
  377. *
  378. * Allocates a block of memory.
  379. *
  380. * Arguments:
  381. *
  382. * [IN] size - number of bytes to allocate
  383. *
  384. * Return Value:
  385. *
  386. * A pointer to the new block, or NULL on failure.
  387. *
  388. * History:
  389. *
  390. * 09/14/1999 asecchia
  391. * Added the checked build memory guard code.
  392. * 07/08/1999 agodfrey
  393. * Created it.
  394. *
  395. \**************************************************************************/
  396. /*
  397. Here's the structure of the memory block allocated under GPMEM_ALLOC_CHK
  398. |+AllocTrackHeader Two DWORDS - contains
  399. | |+flink
  400. | | Pointer to the next memory allocation in the tracked allocation list
  401. | |+blink
  402. | | Pointer to the previous memory allocation in the tracked allocation link
  403. |
  404. |+Guard Area
  405. | GPMEM_GUARD_START DWORDs filled with the gpmemGuardFill string.
  406. |
  407. |+Data Area
  408. | This is the location we return to the caller. It is pre-initialized to
  409. | the repeated DWORD value in gpmemAllocFillBlock (usually 0xbaadf00d)
  410. |
  411. |+Guard Area:
  412. | GPMEM_GUARD_END DWORDs filled with gpmemGuardFill string.
  413. */
  414. #if GPMEM_ALLOC_CHK_LIST
  415. extern "C" void *GpMallocDebug(size_t size, char *fileName, INT lineNumber)
  416. #else
  417. extern "C" void *GpMalloc(size_t size)
  418. #endif
  419. {
  420. // on checked builds we add headers to the allocation and hence, really
  421. // large requests will overflow 32bits and succeed a really small
  422. // allocation.
  423. // Also allocations of 2-4Gb usually indicate a sign extension problem in
  424. // the caller when the size is computed. Note that size_t is UNSIGNED.
  425. // Instead of simply checking the high bit with an &, we check to see that
  426. // the size is < 0x7fffffff so that the check works on IA64 too - IA64
  427. // size_t is 64bit. Note that allocations of this size will fail in the
  428. // heap manager anyway. The caller should be using VirtualAlloc for stuff
  429. // that's really this big.
  430. ASSERT(size < 0x7fffffff);
  431. #if GPMEM_ALLOC_CHK
  432. // If we're playing with the tracking headers, we need to be thread safe.
  433. GpMallocTrackingCriticalSection critsecobj;
  434. //
  435. // Memory? _Real_ programmers don't need memory!
  436. //
  437. if(GpFailMemoryAllocation()) {
  438. gpmemAllocTotal.AllocationFailures++;
  439. gpmemAllocTotal.ForcedFailures++;
  440. return NULL;
  441. }
  442. //
  443. // Make the allocation request a multiple of a QWORD
  444. //
  445. if(size & (sizeof(DWORD)*2-1))
  446. {
  447. size = (size & ~(sizeof(DWORD)*2-1)) + sizeof(DWORD)*2;
  448. }
  449. size_t origsize = size;
  450. //
  451. // Allocate space for the FLink and BLink
  452. //
  453. size += sizeof(AllocTrackHeader);
  454. if(GPMEM_GUARD_START)
  455. {
  456. size += GPMEM_GS;
  457. }
  458. if(GPMEM_GUARD_END)
  459. {
  460. size += GPMEM_GE;
  461. }
  462. void *tmpalloc = HeapAlloc(GpMemHeap, GPMEMHEAPFLAGS, size);
  463. if(!tmpalloc)
  464. {
  465. gpmemAllocTotal.AllocationFailures++;
  466. return NULL;
  467. }
  468. ASSERTMSG(HeapSize(GpMemHeap, GPMEMHEAPFLAGS, tmpalloc) >= size,
  469. ("GpMalloc() allocated %d, but requested %d bytes",
  470. HeapSize(GpMemHeap, GPMEMHEAPFLAGS, tmpalloc), size));
  471. // Add the per-callsite allocation statistics
  472. #if GPMEM_DEBUG_SORT
  473. long hidx = Hash(calleraddr);
  474. if(hidx>=0) {
  475. HashTable[hidx].callsite = calleraddr;
  476. HashTable[hidx].size += size-GPMEM_OVERHEAD;
  477. HashTable[hidx].count ++;
  478. } else {
  479. WARNING(("Hash Table too small - increase HASHSIZE"));
  480. }
  481. #endif
  482. gpmemAllocTotal.Allocated(size);
  483. #else
  484. //
  485. // This is the only piece of code that's executed if
  486. // GPMEM_ALLOC_CHK is turned off.
  487. //
  488. #if PROFILE_MEMORY_USAGE
  489. MC_LogAllocation(size);
  490. #endif
  491. return HeapAlloc(GpMemHeap, GPMEMHEAPFLAGS, size);
  492. #endif
  493. #if GPMEM_ALLOC_CHK
  494. //
  495. // Fill up the entire allocation with the value
  496. // set in GPMEM_FILL_ALLOC
  497. //
  498. if(GPMEM_ALLOC_FILL)
  499. {
  500. GpMemset((unsigned char *)tmpalloc + sizeof(AllocTrackHeader) + GPMEM_GS,
  501. GPMEM_FILL_ALLOC,
  502. origsize);
  503. }
  504. //
  505. // Fill up the start guard area - if we have one.
  506. //
  507. if(GPMEM_GUARD_START)
  508. {
  509. unsigned char *p = (unsigned char *)tmpalloc+sizeof(AllocTrackHeader);
  510. GpMemset(p, GPMEM_FILL_GS, GPMEM_GS);
  511. }
  512. //
  513. // Fill up the end guard area - if we have one.
  514. //
  515. if(GPMEM_GUARD_END)
  516. {
  517. unsigned char *p = (unsigned char *)tmpalloc+size-GPMEM_GE;
  518. GpMemset(p, GPMEM_FILL_GE, GPMEM_GE);
  519. }
  520. //
  521. // setup the double linked-list to track all pool allocations.
  522. //
  523. AllocTrackHeader *hdr = (AllocTrackHeader *)tmpalloc;
  524. hdr->size = size;
  525. // zero out any unused frame pointers.
  526. GpMemset(hdr->caller_address, 0, sizeof(ULONG_PTR)*GPMEM_STACKSIZE);
  527. // Lets stash away the entire stack trace if we have a
  528. // backtrace function.
  529. if(Globals::CaptureStackBackTraceFunction)
  530. {
  531. ULONG hash; // dummy hash
  532. USHORT frames = Globals::CaptureStackBackTraceFunction(
  533. 0, // don't skip any frames
  534. GPMEM_STACKSIZE, // get this many frames
  535. (PVOID*)(hdr->caller_address), // ... into here.
  536. &hash
  537. );
  538. }
  539. hdr->flags = MemoryAllocated;
  540. hdr->tag = 'unkn';
  541. #if GPMEM_ALLOC_CHK_LIST
  542. hdr->callerFileName = fileName;
  543. hdr->callerLineNumber = lineNumber;
  544. #endif
  545. if(GPMEM_ALLOC_TRACKING)
  546. {
  547. hdr->blink = NULL;
  548. hdr->flink = gpmemAllocList;
  549. if(gpmemAllocList)
  550. {
  551. gpmemAllocList->blink = (AllocTrackHeader *)tmpalloc;
  552. }
  553. gpmemAllocList = (AllocTrackHeader *)tmpalloc;
  554. }
  555. else
  556. {
  557. GpMemset(hdr, 0, sizeof(AllocTrackHeader));
  558. }
  559. //
  560. // Give them a pointer just after the guard bits.
  561. //
  562. return (char *)tmpalloc+sizeof(AllocTrackHeader)+GPMEM_GS;
  563. #endif
  564. }
  565. /**************************************************************************\
  566. *
  567. * Function Description:
  568. * Allocates memory for APIs. Used to track the memory with a separate
  569. * identifying flag so that API allocations can be distinguished from
  570. * internal allocations.
  571. * Used on debug builds.
  572. *
  573. * Arguments:
  574. * [IN] size - size to pass to GpMalloc
  575. *
  576. * Return Value:
  577. * Returns the memory with the appropriately hacked up caller address
  578. *
  579. * History:
  580. *
  581. * 4/30/2000 asecchia
  582. * Created it.
  583. *
  584. \**************************************************************************/
  585. #if DBG
  586. #if GPMEM_ALLOC_CHK
  587. #if GPMEM_ALLOC_CHK_LIST
  588. extern "C" void * __stdcall GpMallocAPIDebug(size_t size, char *fileName, INT lineNumber)
  589. #else
  590. extern "C" void *GpMallocAPI(size_t size)
  591. #endif
  592. {
  593. // If we're playing with the tracking headers, we need to be thread safe.
  594. GpMallocTrackingCriticalSection critsecobj;
  595. #if GPMEM_ALLOC_CHK_LIST
  596. void *p = GpMallocDebug(size, fileName, lineNumber);
  597. #else
  598. void *p = GpMalloc(size);
  599. #endif
  600. if(p)
  601. {
  602. AllocTrackHeader *hdr = (AllocTrackHeader *)(
  603. (unsigned char *)p-(GPMEM_GS+sizeof(AllocTrackHeader)));
  604. hdr->flags |= APIAllocation;
  605. }
  606. return p;
  607. }
  608. #else // !GPMEM_ALLOC_CHK
  609. extern "C" void *GpMallocAPI(size_t size, unsigned int caddr)
  610. {
  611. return GpMalloc(size);
  612. }
  613. #endif // !GPMEM_ALLOC_CHK
  614. #endif // DBG
  615. /**************************************************************************\
  616. *
  617. * Function Description:
  618. *
  619. * Computes the original size of a memory block allocated under GPMEM_ALLOC_CHK
  620. *
  621. * Arguments:
  622. *
  623. * [IN] p - current memory block
  624. *
  625. * Return Value:
  626. *
  627. * size of the original request for a memory block (i.e. excluding guard
  628. * areas, headers, etc). The size returned is the DWORD aligned size - so it
  629. * may differ slighly from the original size requested.
  630. *
  631. * Notes:
  632. *
  633. * Returns a size of zero if called with NULL
  634. * Only compiled under GPMEM_ALLOC_CHK
  635. *
  636. * History:
  637. *
  638. * 09/14/1999 asecchia
  639. * Created it.
  640. *
  641. \**************************************************************************/
  642. #if GPMEM_ALLOC_CHK
  643. extern "C" size_t GpSizeBlock(void *p)
  644. {
  645. if(p)
  646. {
  647. // Find the beginning of the allocated block header.
  648. p = (char *)p-(GPMEM_GS+sizeof(AllocTrackHeader));
  649. ASSERT(
  650. HeapSize(GpMemHeap, GPMEMHEAPFLAGS, p) >=
  651. ((AllocTrackHeader *)p)->size
  652. );
  653. // Compute the size of the allocated block's data area.
  654. return (((AllocTrackHeader *)p)->size -
  655. (GPMEM_GS+GPMEM_GE+sizeof(AllocTrackHeader)));
  656. }
  657. else
  658. {
  659. return 0;
  660. }
  661. }
  662. #else
  663. // Non-debug build, just call HeapSize
  664. #define GpSizeBlock(p) HeapSize(GpMemHeap, GPMEMHEAPFLAGS, p)
  665. #endif
  666. /**************************************************************************\
  667. *
  668. * Function Description:
  669. *
  670. * Reallocates a memory block.
  671. *
  672. * Arguments:
  673. *
  674. * [IN] memblock - current memory block
  675. * [IN] size - new allocation size
  676. *
  677. * Return Value:
  678. *
  679. * A pointer to the new block, or NULL on failure.
  680. *
  681. * Notes:
  682. *
  683. * If size is 0, frees the block.
  684. * If memblock is NULL, allocates a new block.
  685. * (If both, does nothing.)
  686. *
  687. * LocalReAlloc only grows if it can expand the current allocation
  688. * - otherwise it fails.
  689. *
  690. * History:
  691. *
  692. * 09/14/1999 asecchia
  693. * Added the checked build memory guard code.
  694. * 07/08/1999 agodfrey
  695. * Created it.
  696. *
  697. \**************************************************************************/
  698. extern "C" void *GpRealloc(void *memblock, size_t size)
  699. {
  700. #if GPMEM_ALLOC_CHK
  701. gpmemAllocTotal.CumulativeReallocs++;
  702. #endif
  703. // Free.
  704. if (!size)
  705. {
  706. if (memblock)
  707. GpFree(memblock);
  708. return NULL;
  709. }
  710. // Alloc.
  711. if (!memblock)
  712. {
  713. return GpMalloc(size);
  714. }
  715. // Realloc - Use GpMalloc/GpMemcpy/GpFree for debug so that the
  716. // extra buffers line up (would require duplicating the code
  717. // from the GpMalloc/GpFree functions otherwise
  718. #if GPMEM_ALLOC_CHK
  719. VOID * p = GpMalloc(size);
  720. if (p != NULL)
  721. {
  722. size_t oldSize = GpSizeBlock(memblock);
  723. // Are we shrinking the block?
  724. if (oldSize > size)
  725. {
  726. oldSize = size;
  727. }
  728. GpMemcpy(p, memblock, oldSize);
  729. GpFree(memblock);
  730. }
  731. #else // !GPMEM_ALLOC_CHK
  732. #if PROFILE_MEMORY_USAGE
  733. MC_LogAllocation(size);
  734. #endif
  735. VOID *p = HeapReAlloc(GpMemHeap, GPMEMHEAPFLAGS, memblock, size);
  736. #endif // !GPMEM_ALLOC_CHK
  737. return p;
  738. }
  739. /**************************************************************************\
  740. *
  741. * Function Description:
  742. *
  743. * Frees a block of memory.
  744. *
  745. * Arguments:
  746. *
  747. * [IN] memblock - block to free
  748. *
  749. * Notes:
  750. *
  751. * If memblock is NULL, does nothing.
  752. *
  753. * History:
  754. *
  755. * 09/14/1999 asecchia
  756. * Added the checked build memory guard code.
  757. * 07/08/1999 agodfrey
  758. * Created it.
  759. *
  760. \**************************************************************************/
  761. extern "C" void GpFree(void *memblock)
  762. {
  763. // Do nothing if the pointer is NULL.
  764. if(memblock)
  765. {
  766. #if GPMEM_ALLOC_CHK
  767. // If we're playing with the tracking headers, we need to be thread safe.
  768. GpMallocTrackingCriticalSection critsecobj;
  769. memblock = (unsigned char *)memblock-(GPMEM_GS+sizeof(AllocTrackHeader));
  770. // Let's do the header stuff.
  771. AllocTrackHeader *hdr = (AllocTrackHeader *)memblock;
  772. DWORD size = hdr->size;
  773. gpmemAllocTotal.Freed(size);
  774. ASSERTMSG(
  775. (hdr->flags & MemoryAllocated) &&
  776. !(hdr->flags & MemoryFreed),
  777. ("GpFree() already freed memory %p (freed by GpFree())",
  778. memblock)
  779. );
  780. hdr->flags &= ~MemoryAllocated;
  781. hdr->flags |= MemoryFreed;
  782. ASSERTMSG(
  783. HeapSize(GpMemHeap, GPMEMHEAPFLAGS, memblock) >= hdr->size,
  784. (
  785. "GpFree() already freed memory %p (freed somewhere else?)"
  786. " local size=%d, size=%d",
  787. memblock,
  788. HeapSize(GpMemHeap, GPMEMHEAPFLAGS, memblock),
  789. hdr->size
  790. )
  791. );
  792. if(GPMEM_ALLOC_TRACKING)
  793. {
  794. // Useful on checked Win2k builds because they fill guard
  795. // area with 0xFEEEFEEE
  796. ASSERTMSG((hdr->flink == NULL) ||
  797. ((DWORD)((ULONG_PTR)(hdr->flink->blink) & 0xFFFFFFFF) != 0xFEEEFEEE),
  798. ("GpFree() updating forward link to freed page, header %p",
  799. memblock));
  800. ASSERTMSG((hdr->blink == NULL) ||
  801. ((DWORD)((ULONG_PTR)(hdr->blink->flink) & 0xFFFFFFFF) != 0xFEEEFEEE),
  802. ("GpFree() updating backward link to freed page, header %p",
  803. memblock));
  804. if(hdr->flink) hdr->flink->blink = hdr->blink;
  805. if(hdr->blink) hdr->blink->flink = hdr->flink;
  806. if(gpmemAllocList==memblock) gpmemAllocList = hdr->flink;
  807. }
  808. else
  809. {
  810. ASSERTMSG(hdr->flink==NULL, ("GpFree() corrupt header %p", memblock));
  811. ASSERTMSG(hdr->blink==NULL, ("GpFree() corrupt header %p", memblock));
  812. }
  813. int i;
  814. unsigned char *p;
  815. // Check the start guard area
  816. if(GPMEM_GUARD_START)
  817. {
  818. p = (unsigned char *)memblock+sizeof(AllocTrackHeader);
  819. for(i=0; i<GPMEM_GS; i++)
  820. {
  821. ASSERTMSG(*p==GPMEM_FILL_GS, ("GpFree() pre-guard area corrupt %p", memblock));
  822. p++;
  823. }
  824. }
  825. // Check the end guard area
  826. if(GPMEM_GUARD_END)
  827. {
  828. p = (unsigned char *)memblock+size-GPMEM_GE;
  829. for(i=0; i<GPMEM_GE; i++)
  830. {
  831. ASSERTMSG(*p==GPMEM_FILL_GE, ("GpFree() post-guard area corrupt %p", memblock));
  832. p++;
  833. }
  834. }
  835. // Now lets fill the entire block with something to prevent
  836. // use of free data.
  837. GpMemset(memblock, GPMEM_FILL_FREE, size);
  838. #endif
  839. // HeapFree may fail freeing a NULL pointer on Win98.
  840. BOOL ret = HeapFree(GpMemHeap, GPMEMHEAPFLAGS, memblock);
  841. ASSERTMSG(
  842. ret, (
  843. "HeapFree() failed at %p, GetLastError()=%08x",
  844. memblock,
  845. GetLastError()
  846. )
  847. );
  848. }
  849. }
  850. extern "C" void * __stdcall zcalloc(
  851. void *pvOpaque,
  852. unsigned int c,
  853. unsigned int cb
  854. )
  855. {
  856. void *pv = GpMalloc(c * cb);
  857. if (pv != NULL)
  858. GpMemset(pv, 0, c * cb);
  859. return pv;
  860. }
  861. extern "C" void __stdcall zcfree(void *pvOpaque, void *pv)
  862. {
  863. GpFree(pv);
  864. }