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.

1370 lines
43 KiB

  1. // Ruler
  2. // 1 2 3 4 5 6 7 8
  3. //345678901234567890123456789012345678901234567890123456789012345678901234567890
  4. /********************************************************************/
  5. /* */
  6. /* The standard layout. */
  7. /* */
  8. /* The standard layout for 'cpp' files in this code is as */
  9. /* follows: */
  10. /* */
  11. /* 1. Include files. */
  12. /* 2. Constants local to the class. */
  13. /* 3. Data structures local to the class. */
  14. /* 4. Data initializations. */
  15. /* 5. Static functions. */
  16. /* 6. Class functions. */
  17. /* */
  18. /* The constructor is typically the first function, class */
  19. /* member functions appear in alphabetical order with the */
  20. /* destructor appearing at the end of the file. Any section */
  21. /* or function this is not required is simply omitted. */
  22. /* */
  23. /********************************************************************/
  24. #include "InterfacePCH.hpp"
  25. #include "DebugHeap.hpp"
  26. #include "Heap.hpp"
  27. void Failure( char* a);
  28. /********************************************************************/
  29. /* */
  30. /* Constants local to the class. */
  31. /* */
  32. /* The constants supplied here try to make the layout of the */
  33. /* the caches easier to understand and update. Additionally, */
  34. /* there are also various guard related constants. */
  35. /* */
  36. /********************************************************************/
  37. CONST SBIT32 FindCacheSize = 2048;
  38. CONST SBIT32 FindCacheThreshold = 0;
  39. CONST SBIT32 FindSize = 1024;
  40. CONST SBIT32 Stride1 = 4;
  41. CONST SBIT32 Stride2 = 1024;
  42. CONST int GuardMask = (sizeof(int)-1);
  43. CONST int GuardSize = sizeof(int);
  44. /********************************************************************/
  45. /* */
  46. /* The description of the heap. */
  47. /* */
  48. /* A heap is a collection of fixed sized allocation caches. */
  49. /* An allocation cache consists of an allocation size, the */
  50. /* number of pre-built allocations to cache, a chunk size and */
  51. /* a parent page size which is sub-divided to create elements */
  52. /* for this cache. A heap consists of two arrays of caches. */
  53. /* Each of these arrays has a stride (i.e. 'Stride1' and */
  54. /* 'Stride2') which is typically the smallest common factor of */
  55. /* all the allocation sizes in the array. */
  56. /* */
  57. /********************************************************************/
  58. STATIC ROCKALL::CACHE_DETAILS Caches1[] =
  59. {
  60. //
  61. // Bucket Size Of Bucket Parent
  62. // Size Cache Chunks Page Size
  63. //
  64. { 4, 0, 32, 32 },
  65. { 8, 0, 32, 32 },
  66. { 12, 0, 64, 64 },
  67. { 16, 0, 64, 64 },
  68. { 20, 0, 64, 64 },
  69. { 24, 0, 128, 128 },
  70. { 32, 0, 64, 64 },
  71. { 40, 0, 128, 128 },
  72. { 48, 0, 256, 256 },
  73. { 64, 0, 128, 128 },
  74. { 80, 0, 512, 512 },
  75. { 96, 0, 512, 512 },
  76. { 128, 0, 256, 256 },
  77. { 160, 0, 512, 512 },
  78. { 192, 0, 1024, 1024 },
  79. { 224, 0, 512, 512 },
  80. { 256, 0, 512, 512 },
  81. { 320, 0, 1024, 1024 },
  82. { 384, 0, 2048, 2048 },
  83. { 448, 0, 4096, 4096 },
  84. { 512, 0, 1024, 1024 },
  85. { 576, 0, 4096, 4096 },
  86. { 640, 0, 8192, 8192 },
  87. { 704, 0, 4096, 4096 },
  88. { 768, 0, 4096, 4096 },
  89. { 832, 0, 8192, 8192 },
  90. { 896, 0, 8192, 8192 },
  91. { 960, 0, 4096, 4096 },
  92. { 0,0,0,0 }
  93. };
  94. STATIC ROCKALL::CACHE_DETAILS Caches2[] =
  95. {
  96. //
  97. // Bucket Size Of Bucket Parent
  98. // Size Cache Chunks Page Size
  99. //
  100. { 1024, 0, 2048, 2048 },
  101. { 2048, 0, 4096, 4096 },
  102. { 3072, 0, 65536, 65536 },
  103. { 4096, 0, 8192, 8192 },
  104. { 5120, 0, 65536, 65536 },
  105. { 6144, 0, 65536, 65536 },
  106. { 7168, 0, 65536, 65536 },
  107. { 8192, 0, 65536, 65536 },
  108. { 9216, 0, 65536, 65536 },
  109. { 10240, 0, 65536, 65536 },
  110. { 12288, 0, 65536, 65536 },
  111. { 16384, 0, 65536, 65536 },
  112. { 21504, 0, 65536, 65536 },
  113. { 32768, 0, 65536, 65536 },
  114. { 65536, 0, 65536, 65536 },
  115. { 65536, 0, 65536, 65536 },
  116. { 0,0,0,0 }
  117. };
  118. /********************************************************************/
  119. /* */
  120. /* The description bit vectors. */
  121. /* */
  122. /* All heaps keep track of allocations using bit vectors. An */
  123. /* allocation requires 2 bits to keep track of its state. The */
  124. /* following array supplies the size of the available bit */
  125. /* vectors measured in 32 bit words. */
  126. /* */
  127. /********************************************************************/
  128. STATIC int NewPageSizes[] = { 1,4,0 };
  129. /********************************************************************/
  130. /* */
  131. /* Class constructor. */
  132. /* */
  133. /* The overall structure and layout of the heap is controlled */
  134. /* by the various constants and calls made in this function. */
  135. /* There is a significant amount of flexibility available to */
  136. /* a heap which can lead to them having dramatically different */
  137. /* properties. */
  138. /* */
  139. /********************************************************************/
  140. DEBUG_HEAP::DEBUG_HEAP
  141. (
  142. int MaxFreeSpace,
  143. bool Recycle,
  144. bool SingleImage,
  145. bool ThreadSafe
  146. ) :
  147. //
  148. // Call the constructors for the contained classes.
  149. //
  150. ROCKALL
  151. (
  152. Caches1,
  153. Caches2,
  154. FindCacheSize,
  155. FindCacheThreshold,
  156. FindSize,
  157. MaxFreeSpace,
  158. NewPageSizes,
  159. Recycle,
  160. SingleImage,
  161. Stride1,
  162. Stride2,
  163. ThreadSafe
  164. )
  165. {
  166. //
  167. // We make much use of the guard value in the
  168. // debug heap so here we try to claim the
  169. // address but not commit it so we will cause
  170. // an access violation if the program ever
  171. // tries to access it.
  172. //
  173. VirtualAlloc
  174. (
  175. ((void*) GuardValue),
  176. GuardSize,
  177. MEM_RESERVE,
  178. PAGE_NOACCESS
  179. );
  180. //
  181. // We verify various values and ensure the heap
  182. // is not corrupt.
  183. //
  184. if
  185. (
  186. (MaxFreeSpace < 0)
  187. ||
  188. (ROCKALL::Corrupt())
  189. )
  190. { Failure( "Heap initialization failed to complete" ); }
  191. }
  192. /********************************************************************/
  193. /* */
  194. /* Memory deallocation. */
  195. /* */
  196. /* We make sure the memory is allocated and that the guard */
  197. /* words have not been damanged. If so we reset the contents */
  198. /* of the allocation and delete the allocation. */
  199. /* */
  200. /********************************************************************/
  201. bool DEBUG_HEAP::Delete( void *Address,int Size )
  202. {
  203. AUTO DEBUG_HEADER *Header =
  204. (
  205. (Address == ((void*) AllocationFailure))
  206. ? ((DEBUG_HEADER*) Address)
  207. : ComputeHeaderAddress( Address )
  208. );
  209. //
  210. // A well known practice is to try to delete
  211. // a null pointer. This is really a very poor
  212. // style but we support it in any case.
  213. //
  214. if ( Header != ((void*) AllocationFailure) )
  215. {
  216. AUTO int TotalSize;
  217. //
  218. // Ask for the details of the allocation. This
  219. // will fail if the memory is not allocated.
  220. //
  221. if ( ROCKALL::Verify( ((void*) Header),& TotalSize ) )
  222. {
  223. REGISTER int NewSize = (Size + sizeof(DEBUG_GUARD));
  224. //
  225. // Test the guard words to make sure they have
  226. // not been damaged.
  227. //
  228. TestGuardWords( Header,TotalSize );
  229. //
  230. // Delete the user information by writing
  231. // guard words over the allocation. This
  232. // should cause the application to crash
  233. // if the area is read and also allows us
  234. // to check to see if it is written later.
  235. //
  236. ResetGuardWords( Header,TotalSize );
  237. //
  238. // Delete the allocation. This really ought
  239. // to work given we have already checked that
  240. // the allocation is valid unless there is a
  241. // race condition.
  242. //
  243. if ( ! ROCKALL::Delete( ((void*) Header),NewSize ) )
  244. { Failure( "Delete requested failed due to race" ); }
  245. //
  246. // We ensure that the heap has not become corrupt
  247. // during the deletion process.
  248. //
  249. if ( ROCKALL::Corrupt() )
  250. { Failure( "Delete failed to complete" ); }
  251. }
  252. else
  253. { Failure( "Delete requested on unallocated memory" ); }
  254. }
  255. return true;
  256. }
  257. /********************************************************************/
  258. /* */
  259. /* Delete all allocations. */
  260. /* */
  261. /* We check to make sure the heap is not corrupt and force */
  262. /* the return of all heap space back to the operating system. */
  263. /* */
  264. /********************************************************************/
  265. void DEBUG_HEAP::DeleteAll( bool Recycle )
  266. {
  267. AUTO bool Active;
  268. AUTO void *Address = NULL;
  269. AUTO int Space;
  270. //
  271. // Walk the heap and check all the allocations
  272. // to make sure the guard words have not been
  273. // overwritten.
  274. //
  275. while ( ROCKALL::Walk( & Active,& Address,& Space ) )
  276. {
  277. //
  278. // We inspect the guard words to make sure
  279. // they have not been overwritten.
  280. //
  281. if ( Active )
  282. { TestGuardWords( ((DEBUG_HEADER*) Address),Space ); }
  283. else
  284. { UnmodifiedGuardWords( ((DEBUG_HEADER*) Address),Space ); }
  285. }
  286. //
  287. // Delete the heap and force all the allocated
  288. // memory to be returned to the operating system
  289. // regardless of what the user requested. Any
  290. // attempt to access the deallocated memory will
  291. // be trapped by the operating system.
  292. //
  293. ROCKALL::DeleteAll( (Recycle && false) );
  294. //
  295. // We ensure that the heap has not become corrupt
  296. // during the deletion process.
  297. //
  298. if ( ROCKALL::Corrupt() )
  299. { Failure( "DeleteAll failed to complete" ); }
  300. }
  301. /********************************************************************/
  302. /* */
  303. /* Memory allocation details. */
  304. /* */
  305. /* Extract information about a memory allocation and just for */
  306. /* good measure check the guard words at the same time. */
  307. /* */
  308. /********************************************************************/
  309. bool DEBUG_HEAP::Details( void *Address,int *Space )
  310. { return Verify( Address,Space ); }
  311. /********************************************************************/
  312. /* */
  313. /* Print a list of heap leaks. */
  314. /* */
  315. /* We walk the heap and output a list of active heap */
  316. /* allocations to the debug window, */
  317. /* */
  318. /********************************************************************/
  319. void DEBUG_HEAP::HeapLeaks( void )
  320. {
  321. AUTO bool Active;
  322. AUTO void *Address = NULL;
  323. AUTO int Space;
  324. //
  325. // Walk the heap and find all the active and
  326. // available spece. We would normally expect
  327. // this to be proportional to the size of the
  328. // heap.
  329. //
  330. while ( ROCKALL::Walk( & Active,& Address,& Space ) )
  331. {
  332. CONST INT DebugBufferSize = 8192;
  333. #ifndef OUTPUT_FREE_SPACE
  334. //
  335. // We report all active heap allocations
  336. // just so the user knows there are leaks.
  337. //
  338. if ( Active )
  339. {
  340. #endif
  341. AUTO CHAR Buffer[ DebugBufferSize ];
  342. //
  343. // Format the string to be printed.
  344. //
  345. (void) sprintf
  346. (
  347. Buffer,
  348. "Memory leak \t%d \t0x%x \t%d\n",
  349. Active,
  350. (((SBIT32) Address) + sizeof(DEBUG_HEADER)),
  351. Space
  352. );
  353. //
  354. // Force null termination.
  355. //
  356. Buffer[ (DebugBufferSize-1) ] = '\0';
  357. //
  358. // Write the string to the debug window.
  359. //
  360. OutputDebugString( Buffer );
  361. #ifndef OUTPUT_FREE_SPACE
  362. }
  363. #endif
  364. }
  365. }
  366. /********************************************************************/
  367. /* */
  368. /* Multiple memory deallocations. */
  369. /* */
  370. /* We make sure all the memory is allocated and that the guard */
  371. /* words have not been damaged. If so we reset the contents */
  372. /* of the allocations and then delete all the allocations. */
  373. /* */
  374. /********************************************************************/
  375. bool DEBUG_HEAP::MultipleDelete
  376. (
  377. int Actual,
  378. void *Array[],
  379. int Size
  380. )
  381. {
  382. REGISTER int Count;
  383. REGISTER int NewSize = (Size + sizeof(DEBUG_GUARD));
  384. //
  385. // Examine each memory allocation and delete it
  386. // after carefully checking it.
  387. //
  388. for ( Count=0;Count < Actual;Count ++ )
  389. {
  390. AUTO int TotalSize;
  391. AUTO VOID *Address = Array[ Count ];
  392. AUTO DEBUG_HEADER *Header =
  393. (
  394. (Address == ((void*) AllocationFailure))
  395. ? ((DEBUG_HEADER*) Address)
  396. : ComputeHeaderAddress( Address )
  397. );
  398. //
  399. // Ask for the details of the allocation. This
  400. // will fail if the memory is not allocated.
  401. //
  402. if ( ROCKALL::Verify( ((void*) Header),& TotalSize ) )
  403. {
  404. //
  405. // Test the guard words to make sure they have
  406. // not been damaged.
  407. //
  408. TestGuardWords( Header,TotalSize );
  409. //
  410. // Delete the user information by writing
  411. // guard words over the allocation. This
  412. // should cause the application to crash
  413. // if the area is read and also allows us
  414. // to check to see if it is written later.
  415. //
  416. ResetGuardWords( Header,TotalSize );
  417. //
  418. // Update the address in the array to the
  419. // address originally allocated.
  420. //
  421. Array[ Count ] = ((VOID*) Header);
  422. }
  423. else
  424. { Failure( "Delete requested on unallocated memory" ); }
  425. }
  426. //
  427. // Delete the allocation. This really ought
  428. // to work given we have already checked that
  429. // the allocations are valid unless there is a
  430. // race condition.
  431. //
  432. if ( ! ROCKALL::MultipleDelete( Actual,Array,NewSize ) )
  433. { Failure( "Delete requested failed due to race" ); }
  434. //
  435. // We ensure that the heap has not become corrupt
  436. // during the deletion process.
  437. //
  438. if ( ROCKALL::Corrupt() )
  439. { Failure( "MultipleDelete failed to complete" ); }
  440. return true;
  441. }
  442. /********************************************************************/
  443. /* */
  444. /* Multiple memory allocations. */
  445. /* */
  446. /* Allocate a collection of memory elements and setup the */
  447. /* guard information so we can check they have not been */
  448. /* damaged later. */
  449. /* */
  450. /********************************************************************/
  451. bool DEBUG_HEAP::MultipleNew
  452. (
  453. int *Actual,
  454. void *Array[],
  455. int Requested,
  456. int Size,
  457. int *Space,
  458. bool Zero
  459. )
  460. {
  461. REGISTER bool Result = false;
  462. //
  463. // The requested number of elements and the size
  464. // must be greater than zero. We require the
  465. // caller to allocate a positive amount of memory.
  466. //
  467. if ( (Requested > 0) && (Size >= 0) )
  468. {
  469. AUTO int TotalSize;
  470. REGISTER int NewSize =
  471. (((Size + sizeof(DEBUG_GUARD)) + GuardMask) & ~GuardMask);
  472. //
  473. // Allocate the memory plus some additional
  474. // memory for the guard words.
  475. //
  476. Result =
  477. (
  478. ROCKALL::MultipleNew
  479. (
  480. Actual,
  481. Array,
  482. Requested,
  483. NewSize,
  484. & TotalSize
  485. )
  486. );
  487. //
  488. // If we were able to allocate some memory then
  489. // set the guard words so we can detect any
  490. // corruption later.
  491. //
  492. if ( (*Actual) > 0 )
  493. {
  494. REGISTER int Count;
  495. //
  496. // If the real size is requested then return
  497. // it to the caller.
  498. //
  499. if ( Space != NULL )
  500. { (*Space) = (TotalSize - sizeof(DEBUG_GUARD)); }
  501. //
  502. // Set the guard words so we can see if
  503. // someone damages any allocation. If the
  504. // caller requested the size information
  505. // then we must assume that it could be
  506. // used so we need to adjust the number
  507. // of guard words.
  508. //
  509. for ( Count=0;Count < (*Actual);Count ++ )
  510. {
  511. REGISTER void **Current = & Array[ Count ];
  512. //
  513. // Set up the guard words and ensure
  514. // the allocation has not been written
  515. // since being freed.
  516. //
  517. SetGuardWords
  518. (
  519. ((DEBUG_HEADER*) (*Current)),
  520. ((Space == NULL) ? Size : (*Space)),
  521. TotalSize
  522. );
  523. //
  524. // Compute the external address and place
  525. // it back in the array.
  526. //
  527. (*Current) = ComputeDataAddress( ((DEBUG_HEADER*) (*Current)) );
  528. //
  529. // Zero the memory if the needed.
  530. //
  531. if ( Zero )
  532. {
  533. ZeroMemory
  534. (
  535. (*Current),
  536. ((Space == NULL) ? Size : (*Space))
  537. );
  538. }
  539. }
  540. }
  541. //
  542. // We ensure that the heap has not become corrupt
  543. // during the allocation process.
  544. //
  545. if ( ROCKALL::Corrupt() )
  546. { Failure( "Multiple new failed to complete" ); }
  547. }
  548. else
  549. { Failure( "Allocation size must greater than zero" ); }
  550. return Result;
  551. }
  552. /********************************************************************/
  553. /* */
  554. /* Memory allocation. */
  555. /* */
  556. /* We add some space on to the original allocation size for */
  557. /* various information and then call the allocator. We then */
  558. /* set the guard words so we can check for overruns. */
  559. /* */
  560. /********************************************************************/
  561. void *DEBUG_HEAP::New( int Size,int *Space,bool Zero )
  562. {
  563. REGISTER void *Address = ((void*) AllocationFailure);
  564. //
  565. // The size must be greater than or equal to zero.
  566. // We do not know how to allocate a negative amount
  567. // of memory.
  568. //
  569. if ( Size >= 0 )
  570. {
  571. AUTO int TotalSize;
  572. REGISTER int NewSize =
  573. (((Size + sizeof(DEBUG_GUARD)) + GuardMask) & ~GuardMask);
  574. //
  575. // Allocate the memory plus some additional
  576. // memory for the guard words.
  577. //
  578. Address = ROCKALL::New( NewSize,& TotalSize,false );
  579. //
  580. // If we were able to allocate some memory then
  581. // set the guard words so we can detect any
  582. // corruption later.
  583. //
  584. if ( Address != ((void*) AllocationFailure) )
  585. {
  586. //
  587. // If the real size is requested then return it
  588. // to the caller.
  589. //
  590. if ( Space != NULL )
  591. { (*Space) = (TotalSize - sizeof(DEBUG_GUARD)); }
  592. //
  593. // Set the guard words so we can see if
  594. // someone damages any allocation. If the
  595. // caller requested the size information
  596. // then we must assume that it could be
  597. // used so we need to adjust the number
  598. // of guard words.
  599. //
  600. SetGuardWords
  601. (
  602. ((DEBUG_HEADER*) Address),
  603. ((Space == NULL) ? Size : (*Space)),
  604. TotalSize
  605. );
  606. //
  607. // Compute the external address and place
  608. // it back in the variable.
  609. //
  610. Address = ComputeDataAddress( ((DEBUG_HEADER*) Address) );
  611. //
  612. // Zero the allocation if needed.
  613. //
  614. if ( Zero )
  615. {
  616. ZeroMemory
  617. (
  618. Address,
  619. ((Space == NULL) ? Size : (*Space))
  620. );
  621. }
  622. }
  623. //
  624. // We ensure that the heap has not become corrupt
  625. // during the allocation process.
  626. //
  627. if ( ROCKALL::Corrupt() )
  628. { Failure( "New failed to complete" ); }
  629. }
  630. else
  631. { Failure( "Allocation size can not be negative" ); }
  632. return Address;
  633. }
  634. /********************************************************************/
  635. /* */
  636. /* Memory area allocation. */
  637. /* */
  638. /* We need to allocate some new memory from the operating */
  639. /* system and prepare it for use in the debugging heap. */
  640. /* */
  641. /********************************************************************/
  642. void *DEBUG_HEAP::NewArea( int AlignMask,int Size,bool User )
  643. {
  644. REGISTER void *Memory = ROCKALL::NewArea( AlignMask,Size,User );
  645. //
  646. // If we managed to get a new page then write
  647. // the guard value over it to allow us to
  648. // verify it has not been overwritten later.
  649. //
  650. if ( Memory != ((void*) AllocationFailure) )
  651. {
  652. REGISTER int Count;
  653. //
  654. // Write the guard value into all of the new
  655. // heap page to allow it to be checked for
  656. // corruption.
  657. //
  658. for ( Count=0;Count < Size;Count += GuardSize )
  659. { (((int*) Memory)[ (Count / GuardSize) ]) = GuardValue; }
  660. }
  661. return Memory;
  662. }
  663. /********************************************************************/
  664. /* */
  665. /* Memory reallocation. */
  666. /* */
  667. /* We need to resize an allocation. We ensure the original */
  668. /* allocation was undamaged and then expand it. We also */
  669. /* update the guard words to reflect the changes. */
  670. /* */
  671. /********************************************************************/
  672. void *DEBUG_HEAP::Resize
  673. (
  674. void *Address,
  675. int NewSize,
  676. int Move,
  677. int *Space,
  678. bool NoDelete,
  679. bool Zero
  680. )
  681. {
  682. AUTO DEBUG_HEADER *Header =
  683. (
  684. (Address == ((void*) AllocationFailure))
  685. ? ((DEBUG_HEADER*) Address)
  686. : ComputeHeaderAddress( Address )
  687. );
  688. //
  689. // A well known practice is to try to resize a null
  690. // pointer. This is really a very poor style but we
  691. // support it in any case.
  692. //
  693. if ( Header != ((void*) AllocationFailure) )
  694. {
  695. AUTO int TotalSize;
  696. //
  697. // The new size must be greater than or equal to
  698. // zero. We do not know how to allocate a negative
  699. // amount of memory.
  700. //
  701. if ( NewSize >= 0 )
  702. {
  703. REGISTER int Size =
  704. (((NewSize + sizeof(DEBUG_GUARD)) + GuardMask) & ~GuardMask);
  705. //
  706. // Ask for the details of the allocation. This
  707. // will fail if the memory is not allocated.
  708. //
  709. if ( ROCKALL::Verify( ((void*) Header),& TotalSize ) )
  710. {
  711. REGISTER void *OriginalAddress = ((void*) Header);
  712. REGISTER int OriginalSize = TotalSize;
  713. //
  714. // Test the guard words to make sure they have
  715. // not been damaged.
  716. //
  717. TestGuardWords( Header,TotalSize );
  718. //
  719. // Reallocate the memory plus some additional
  720. // memory for the guard words.
  721. //
  722. Address =
  723. (
  724. ROCKALL::Resize
  725. (
  726. OriginalAddress,
  727. Size,
  728. Move,
  729. & TotalSize,
  730. true,
  731. false
  732. )
  733. );
  734. //
  735. // If we were able to allocate some memory
  736. // then set the guard words so we can detect
  737. // any corruption later.
  738. //
  739. if ( Address != ((void*) AllocationFailure) )
  740. {
  741. REGISTER SBIT32 SpaceUsed = Header -> Size;
  742. //
  743. // Delete the user information by writing
  744. // guard words over the allocation. This
  745. // should cause the application to crash
  746. // if the area is read and allows us to
  747. // check to see if it is written later.
  748. //
  749. if ( (! NoDelete) && (Address != OriginalAddress) )
  750. {
  751. ResetGuardWords( Header,OriginalSize );
  752. if ( ! ROCKALL::Delete( OriginalAddress ) )
  753. { Failure( "Delete failed due to race" ); }
  754. }
  755. //
  756. // If the real size is requested then
  757. // return it to the caller.
  758. //
  759. if ( Space != NULL )
  760. { (*Space) = (TotalSize - sizeof(DEBUG_GUARD)); }
  761. //
  762. // Update the guard words so we can see
  763. // if someone damages the allocation. If
  764. // the caller requested the size information
  765. // then we must assume that it could be
  766. // used so we need to adjust the guard words.
  767. //
  768. UpdateGuardWords
  769. (
  770. ((DEBUG_HEADER*) Address),
  771. ((Space == NULL) ? NewSize : (*Space)),
  772. TotalSize
  773. );
  774. //
  775. // Compute the external address and place
  776. // it back in the variable.
  777. //
  778. Address = ComputeDataAddress( ((DEBUG_HEADER*) Address) );
  779. //
  780. // Zero the memory if the needed.
  781. //
  782. if ( Zero )
  783. {
  784. REGISTER SBIT32 ActualSize =
  785. ((Space == NULL) ? Size : (*Space));
  786. REGISTER SBIT32 Difference =
  787. (ActualSize - SpaceUsed);
  788. //
  789. // If the new size is larger than
  790. // old size then zero the end of the
  791. // new allocation.
  792. //
  793. if ( Difference > 0 )
  794. {
  795. REGISTER CHAR *Array = ((CHAR*) Address);
  796. ZeroMemory( & Array[ SpaceUsed ],Difference );
  797. }
  798. }
  799. }
  800. }
  801. else
  802. { Failure( "Resize requested on unallocated memory" ); }
  803. }
  804. else
  805. { Failure( "Allocation size must be positive" ); }
  806. }
  807. else
  808. { Address = New( NewSize,Space,Zero ); }
  809. //
  810. // We ensure that the heap has not become corrupt
  811. // during the reallocation process.
  812. //
  813. if ( ROCKALL::Corrupt() )
  814. { Failure( "Resize failed to complete" ); }
  815. return Address;
  816. }
  817. /********************************************************************/
  818. /* */
  819. /* Reset the guard words. */
  820. /* */
  821. /* We need to reset the guard words just before we delete a */
  822. /* memory allocation. */
  823. /* */
  824. /********************************************************************/
  825. void DEBUG_HEAP::ResetGuardWords( DEBUG_HEADER *Header,int TotalSize )
  826. {
  827. REGISTER int Count;
  828. //
  829. // Write guard words over the allocated space as
  830. // the allocation is about to be freed.
  831. //
  832. for ( Count=0;Count < TotalSize;Count += GuardSize )
  833. { (((int*) Header)[ (Count / GuardSize) ]) = GuardValue; }
  834. }
  835. /********************************************************************/
  836. /* */
  837. /* Set the guard words. */
  838. /* */
  839. /* We need to set the guard words just after an allocation so */
  840. /* we can check them later. */
  841. /* */
  842. /********************************************************************/
  843. void DEBUG_HEAP::SetGuardWords( DEBUG_HEADER *Header,int Size,int TotalSize )
  844. {
  845. //
  846. // We check that the information supplied seems
  847. // to make sense before setting up the guard words.
  848. //
  849. if
  850. (
  851. ((((int) Header) & GuardMask) == 0)
  852. &&
  853. ((TotalSize & GuardMask) == 0)
  854. &&
  855. ((Size + ((int) sizeof(DEBUG_GUARD))) <= TotalSize)
  856. &&
  857. (Size >= 0)
  858. )
  859. {
  860. REGISTER int Count;
  861. //
  862. // We know that the entire allocation should be
  863. // set to the guard value so check that it has
  864. // not been overwritten.
  865. //
  866. for ( Count=0;Count < TotalSize;Count += GuardSize )
  867. {
  868. if ( (((int*) Header)[ (Count / GuardSize) ]) != GuardValue )
  869. { Failure( "Guard words have been damaged" ); }
  870. }
  871. //
  872. // Write the header information.
  873. //
  874. Header -> Size = Size;
  875. }
  876. else
  877. { Failure( "Guard word area is too small or unaligned" ); }
  878. }
  879. /********************************************************************/
  880. /* */
  881. /* Test the guard words. */
  882. /* */
  883. /* We need to test the guard words a various times to ensure */
  884. /* are still valid. */
  885. /* */
  886. /********************************************************************/
  887. void DEBUG_HEAP::TestGuardWords( DEBUG_HEADER *Header,int TotalSize )
  888. {
  889. //
  890. // We check that the information supplied seems
  891. // to make sense before testing the guard words.
  892. //
  893. if
  894. (
  895. ((((int) Header) & GuardMask) == 0)
  896. &&
  897. ((TotalSize & GuardMask) == 0)
  898. &&
  899. ((Header -> Size + ((int) sizeof(DEBUG_GUARD))) <= TotalSize)
  900. &&
  901. (Header -> Size >= 0)
  902. )
  903. {
  904. REGISTER int Count;
  905. REGISTER char *DataArea = ((char*) ComputeDataAddress( Header ));
  906. REGISTER int EndIndex = ((Header -> Size + GuardMask) & ~GuardMask);
  907. REGISTER int EndSize = (TotalSize - sizeof(DEBUG_HEADER) - GuardSize);
  908. REGISTER char *MidGuard = & DataArea[ (EndIndex - GuardSize) ];
  909. REGISTER DEBUG_TRAILER *Trailer = ((DEBUG_TRAILER*) MidGuard);
  910. //
  911. // Test the guard word just before the allocation
  912. // to see if it has been overwritten.
  913. //
  914. if ( Header -> StartGuard != GuardValue )
  915. { Failure( "Leading guard word has been damaged" ); }
  916. //
  917. // Test the guard bytes just after the allocation
  918. // to see if they have been overwritten.
  919. //
  920. for ( Count=Header -> Size;(Count & GuardMask) != 0;Count ++ )
  921. {
  922. REGISTER int ByteIndex = (Count & GuardMask);
  923. //
  924. // Test each byte up to the next word boundary.
  925. //
  926. if
  927. (
  928. Trailer -> MidGuard[ ByteIndex ]
  929. !=
  930. ((char*) & GuardValue)[ ByteIndex ]
  931. )
  932. { Failure( "Trailing guard byte has been damaged" ); }
  933. }
  934. //
  935. // Test the guard words following the allocation
  936. // to see if they have been overwritten.
  937. //
  938. for ( Count=(EndSize - Count);Count >= 0;Count -= GuardSize )
  939. {
  940. if ( Trailer -> EndGuard[ (Count / GuardSize) ] != GuardValue )
  941. { Failure( "Trailing guard word has been damaged" ); }
  942. }
  943. }
  944. else
  945. { Failure( "Guard information has been damaged" ); }
  946. }
  947. /********************************************************************/
  948. /* */
  949. /* Memory Trunction. */
  950. /* */
  951. /* We truncate the heap and make sure that this does not */
  952. /* corrupt the heap in some way. */
  953. /* */
  954. /********************************************************************/
  955. bool DEBUG_HEAP::Truncate( int MaxFreeSpace )
  956. {
  957. REGISTER bool Result;
  958. //
  959. // We truncate the heap and release all available
  960. // memory regardless of what the caller requested.
  961. //
  962. Result = ROCKALL::Truncate( 0 );
  963. //
  964. // We verify various values and ensure the heap
  965. // is not corrupt.
  966. //
  967. if
  968. (
  969. (MaxFreeSpace < 0)
  970. ||
  971. (ROCKALL::Corrupt())
  972. )
  973. { Failure( "Heap truncation failed to complete" ); }
  974. return Result;
  975. }
  976. /********************************************************************/
  977. /* */
  978. /* Unmodified guard words. */
  979. /* */
  980. /* We need to inspect the guard words to ensure they have not */
  981. /* changed after being freed. */
  982. /* */
  983. /********************************************************************/
  984. void DEBUG_HEAP::UnmodifiedGuardWords( DEBUG_HEADER *Header,int TotalSize )
  985. {
  986. REGISTER int Count;
  987. //
  988. // We know that the entire allocation should be
  989. // set to the guard value so check that it has
  990. // not been overwritten.
  991. //
  992. for ( Count=0;Count < TotalSize;Count += GuardSize )
  993. {
  994. if ( (((int*) Header)[ (Count / GuardSize) ]) != GuardValue )
  995. { Failure( "Guard words on unallocated memory have been damaged" ); }
  996. }
  997. }
  998. /********************************************************************/
  999. /* */
  1000. /* Update the guard words. */
  1001. /* */
  1002. /* We need to update the guard words after a resize so we can */
  1003. /* check them later. */
  1004. /* */
  1005. /********************************************************************/
  1006. void DEBUG_HEAP::UpdateGuardWords( DEBUG_HEADER *Header,int Size,int TotalSize )
  1007. {
  1008. //
  1009. // We check that the information supplied seems
  1010. // to make sense before setting up the guard words.
  1011. //
  1012. if
  1013. (
  1014. ((((int) Header) & GuardMask) == 0)
  1015. &&
  1016. ((TotalSize & GuardMask) == 0)
  1017. &&
  1018. ((Size + ((int) sizeof(DEBUG_GUARD))) <= TotalSize)
  1019. &&
  1020. (Size >= 0)
  1021. )
  1022. {
  1023. //
  1024. // We only copy the smaller of the new size
  1025. // and the old size. So check just the
  1026. // correct number of guard words.
  1027. //
  1028. if ( Header -> Size > Size )
  1029. {
  1030. REGISTER int Count;
  1031. REGISTER char *DataArea = ((char*) ComputeDataAddress( Header ));
  1032. REGISTER int EndIndex = ((Size + GuardMask) & ~GuardMask);
  1033. REGISTER int EndSize = (TotalSize - sizeof(DEBUG_HEADER) - GuardSize);
  1034. REGISTER char *MidGuard = & DataArea[ (EndIndex - GuardSize) ];
  1035. REGISTER DEBUG_TRAILER *Trailer = ((DEBUG_TRAILER*) MidGuard);
  1036. //
  1037. // Update the guard bytes just after the
  1038. // allocation.
  1039. //
  1040. for ( Count=Size;(Count & GuardMask) != 0;Count ++ )
  1041. {
  1042. REGISTER int ByteIndex = (Count & GuardMask);
  1043. Trailer -> MidGuard[ ByteIndex ] =
  1044. ((char*) & GuardValue)[ ByteIndex ];
  1045. }
  1046. //
  1047. // Write guard words over part of the space
  1048. // as the allocation is being shrunk.
  1049. //
  1050. for ( Count=(EndSize - Count);Count >= 0;Count -= GuardSize )
  1051. { Trailer -> EndGuard[ (Count / GuardSize) ] = GuardValue; }
  1052. //
  1053. // Update the header information.
  1054. //
  1055. Header -> Size = Size;
  1056. //
  1057. // We know that the entire allocation should
  1058. // be set to the guard value so check that it
  1059. // has not been overwritten.
  1060. //
  1061. TestGuardWords( Header,TotalSize );
  1062. }
  1063. else
  1064. {
  1065. //
  1066. // We know that the entire allocation should be
  1067. // set to the guard value so check that it has
  1068. // not been overwritten.
  1069. //
  1070. TestGuardWords( Header,TotalSize );
  1071. //
  1072. // Update the header information.
  1073. //
  1074. Header -> Size = Size;
  1075. }
  1076. }
  1077. else
  1078. { Failure( "Guard word information area is damaged" ); }
  1079. }
  1080. /********************************************************************/
  1081. /* */
  1082. /* Verify memory allocation details. */
  1083. /* */
  1084. /* Extract information about a memory allocation and just for */
  1085. /* good measure check the guard words at the same time. */
  1086. /* */
  1087. /********************************************************************/
  1088. bool DEBUG_HEAP::Verify( void *Address,int *Space )
  1089. {
  1090. AUTO bool Result;
  1091. AUTO int TotalSize;
  1092. AUTO DEBUG_HEADER *Header =
  1093. (
  1094. (Address == ((void*) AllocationFailure))
  1095. ? ((DEBUG_HEADER*) Address)
  1096. : ComputeHeaderAddress( Address )
  1097. );
  1098. //
  1099. // Extract information about the memory allocation.
  1100. //
  1101. Result =
  1102. (
  1103. ROCKALL::Verify
  1104. (
  1105. ((void*) Header),
  1106. & TotalSize
  1107. )
  1108. );
  1109. //
  1110. // If we managed to extract the information then
  1111. // check the guard words for good measure.
  1112. //
  1113. if ( Result )
  1114. {
  1115. //
  1116. // If we are about to return the actual
  1117. // amount of spce available then we must
  1118. // update the size of the guard area.
  1119. //
  1120. if ( Space == NULL )
  1121. {
  1122. //
  1123. // Test the guard words to make sure they have
  1124. // not been damaged.
  1125. //
  1126. TestGuardWords( Header,TotalSize );
  1127. }
  1128. else
  1129. {
  1130. //
  1131. // Compute the amount of available space.
  1132. //
  1133. (*Space) = (TotalSize - sizeof(DEBUG_GUARD));
  1134. //
  1135. // Test the guard words to make sure they have
  1136. // not been damaged.
  1137. //
  1138. UpdateGuardWords( Header,(*Space),TotalSize );
  1139. }
  1140. }
  1141. //
  1142. // We ensure that the heap has not become corrupt
  1143. // during the verification process.
  1144. //
  1145. if ( ROCKALL::Corrupt() )
  1146. { Failure( "Heap verify failed to complete" ); }
  1147. return Result;
  1148. }
  1149. /********************************************************************/
  1150. /* */
  1151. /* Walk the heap. */
  1152. /* */
  1153. /* We have been asked to walk the heap. It is hard to know */
  1154. /* why anybody might want to do this given the rest of the */
  1155. /* functionality available. Nonetheless, we just do what is */
  1156. /* required to keep everyone happy. */
  1157. /* */
  1158. /********************************************************************/
  1159. bool DEBUG_HEAP::Walk( bool *Active,void **Address,int *Space )
  1160. {
  1161. AUTO DEBUG_HEADER *Header =
  1162. (
  1163. ((*Address) == ((void*) AllocationFailure))
  1164. ? ((DEBUG_HEADER*) (*Address))
  1165. : ComputeHeaderAddress( (*Address) )
  1166. );
  1167. //
  1168. // Walk the heap.
  1169. //
  1170. if ( ROCKALL::Walk( Active,((VOID**) & Header),Space ) )
  1171. {
  1172. //
  1173. // We inspect the guard words to make sure
  1174. // they have not been overwritten.
  1175. //
  1176. if ( (*Active) )
  1177. { TestGuardWords( Header,(*Space) ); }
  1178. else
  1179. { UnmodifiedGuardWords( Header,(*Space) ); }
  1180. //
  1181. // Compute the new heap address.
  1182. //
  1183. (*Address) = ComputeDataAddress( Header );
  1184. //
  1185. // Compute the amount of available space.
  1186. //
  1187. (*Space) -= sizeof(DEBUG_GUARD);
  1188. return true;
  1189. }
  1190. else
  1191. { return false; }
  1192. }
  1193. /********************************************************************/
  1194. /* */
  1195. /* Class destructor. */
  1196. /* */
  1197. /* Destory the current instance of the class. */
  1198. /* */
  1199. /********************************************************************/
  1200. DEBUG_HEAP::~DEBUG_HEAP( void )
  1201. {
  1202. AUTO bool Active;
  1203. AUTO void *Address = NULL;
  1204. AUTO int Space;
  1205. //
  1206. // Walk the heap and check all the allocations
  1207. // to make sure the guard words have not been
  1208. // overwritten.
  1209. //
  1210. while ( ROCKALL::Walk( & Active,& Address,& Space ) )
  1211. {
  1212. //
  1213. // We inspect the guard words to make sure
  1214. // they have not been overwritten.
  1215. //
  1216. if ( Active )
  1217. { TestGuardWords( ((DEBUG_HEADER*) Address),Space ); }
  1218. else
  1219. { UnmodifiedGuardWords( ((DEBUG_HEADER*) Address),Space ); }
  1220. }
  1221. //
  1222. // We ensure that the heap has not become corrupt
  1223. // during the its lifetime.
  1224. //
  1225. if ( ROCKALL::Corrupt() )
  1226. { Failure( "Destructor failed to complete" ); }
  1227. }