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.

511 lines
19 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 "Heap.hpp"
  26. #include "RockallDebugBackEnd.hpp"
  27. #include "RockallDebugFrontEnd.hpp"
  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. */
  34. /* */
  35. /********************************************************************/
  36. CONST SBIT32 FindCacheSize = 2048;
  37. CONST SBIT32 FindCacheThreshold = 0;
  38. CONST SBIT32 FindSize = 1024;
  39. /********************************************************************/
  40. /* */
  41. /* The description bit vectors. */
  42. /* */
  43. /* All heaps keep track of allocations using bit vectors. An */
  44. /* allocation requires 2 bits to keep track of its state. The */
  45. /* following array supplies the size of the available bit */
  46. /* vectors measured in 32 bit words. */
  47. /* */
  48. /********************************************************************/
  49. STATIC int NewPageSizes[] = { 1,4,0 };
  50. /********************************************************************/
  51. /* */
  52. /* Class constructor. */
  53. /* */
  54. /* The overall structure and layout of the heap is controlled */
  55. /* by the various constants and calls made in this function. */
  56. /* There is a significant amount of flexibility available to */
  57. /* a heap which can lead to them having dramatically different */
  58. /* properties. */
  59. /* */
  60. /********************************************************************/
  61. ROCKALL_DEBUG_FRONT_END::ROCKALL_DEBUG_FRONT_END
  62. (
  63. CACHE_DETAILS *Caches1,
  64. CACHE_DETAILS *Caches2,
  65. int MaxFreeSpace,
  66. ROCKALL_BACK_END *RockallBackEnd,
  67. bool Recycle,
  68. bool SingleImage,
  69. int Stride1,
  70. int Stride2,
  71. bool ThreadSafe
  72. ) :
  73. //
  74. // Call the constructors for the contained classes.
  75. //
  76. ROCKALL_FRONT_END
  77. (
  78. Caches1,
  79. Caches2,
  80. FindCacheSize,
  81. FindCacheThreshold,
  82. FindSize,
  83. ((MaxFreeSpace == 0) ? MaxFreeSpace : 0),
  84. NewPageSizes,
  85. RockallBackEnd,
  86. Recycle,
  87. SingleImage,
  88. Stride1,
  89. Stride2,
  90. ThreadSafe
  91. )
  92. {
  93. //
  94. // We make much use of the guard value in the
  95. // debug heap so here we try to claim the
  96. // address but not commit it so we will ensure
  97. // an access violation if the program ever
  98. // tries to access it.
  99. //
  100. VirtualAlloc
  101. (
  102. ((void*) GuardValue),
  103. GuardSize,
  104. MEM_RESERVE,
  105. PAGE_NOACCESS
  106. );
  107. }
  108. /********************************************************************/
  109. /* */
  110. /* Memory deallocation. */
  111. /* */
  112. /* We make sure the memory is allocated and that the guard */
  113. /* words have not been damanged. If so we reset the contents */
  114. /* of the allocation and delete the allocation. */
  115. /* */
  116. /********************************************************************/
  117. bool ROCKALL_DEBUG_FRONT_END::Delete( void *Address,int Size )
  118. {
  119. //
  120. // A well known practice is to try to delete
  121. // a null pointer. This is really a very poor
  122. // style but we support it in any case.
  123. //
  124. if ( Address != ((void*) AllocationFailure) )
  125. {
  126. //
  127. // Delete the user information by writing
  128. // guard words over the allocation. This
  129. // should cause the application to crash
  130. // if the area is read and also allows us
  131. // to check to see if it is written later.
  132. //
  133. DeleteGuard( Address );
  134. return true;
  135. }
  136. else
  137. { return false; }
  138. }
  139. /********************************************************************/
  140. /* */
  141. /* Delete all allocations. */
  142. /* */
  143. /* We check to make sure the heap is not corrupt and force */
  144. /* the return of all heap space back to the operating system. */
  145. /* */
  146. /********************************************************************/
  147. void ROCKALL_DEBUG_FRONT_END::DeleteAll( bool Recycle )
  148. {
  149. AUTO bool Active;
  150. AUTO void *Address = NULL;
  151. AUTO int Space;
  152. //
  153. // Walk the heap to verify all the allocations
  154. // so that we know that the heap is undamaged.
  155. //
  156. while ( WalkGuard( & Active,& Address,& Space ) );
  157. //
  158. // Delete the heap and force all the allocated
  159. // memory to be returned to the operating system
  160. // regardless of what the user requested. Any
  161. // attempt to access the deallocated memory will
  162. // be trapped by the operating system.
  163. //
  164. ROCKALL_FRONT_END::DeleteAll( (Recycle && false) );
  165. }
  166. /********************************************************************/
  167. /* */
  168. /* Memory allocation details. */
  169. /* */
  170. /* Extract information about a memory allocation and just for */
  171. /* good measure check the guard words at the same time. */
  172. /* */
  173. /********************************************************************/
  174. bool ROCKALL_DEBUG_FRONT_END::Details( void *Address,int *Space )
  175. { return Verify( Address,Space ); }
  176. /********************************************************************/
  177. /* */
  178. /* Exception processing. */
  179. /* */
  180. /* Although it is very hard to make Rockall crash it is */
  181. /* technically possible. When (or should I say if) this */
  182. /* we call the following function (which may be overloadded). */
  183. /* */
  184. /********************************************************************/
  185. void ROCKALL_DEBUG_FRONT_END::Exception( char *Message )
  186. {
  187. DebugPrint
  188. (
  189. "EXCEPTION CAUGHT: %s\n"
  190. "ROCKALL TOTAL HEAP FAILURE: You have toasted the heap - Wow !!!!\n",
  191. Message
  192. );
  193. }
  194. /********************************************************************/
  195. /* */
  196. /* Multiple memory deallocations. */
  197. /* */
  198. /* We make sure all the memory is allocated and that the guard */
  199. /* words have not been damaged. If so we reset the contents */
  200. /* of the allocations and then delete the allocations. */
  201. /* */
  202. /********************************************************************/
  203. bool ROCKALL_DEBUG_FRONT_END::MultipleDelete
  204. (
  205. int Actual,
  206. void *Array[],
  207. int Size
  208. )
  209. {
  210. REGISTER bool Result = true;
  211. REGISTER SBIT32 Count;
  212. //
  213. // We would realy like to use the multiple
  214. // delete functionality of Rockall here but
  215. // it is too much effort. So we simply call
  216. // the standard debug delete on each entry
  217. // in the array. Although this is not as
  218. // fast it does give more transparent results.
  219. //
  220. for ( Count=0;Count < Actual;Count ++ )
  221. {
  222. //
  223. // Delete each memory allocation after
  224. // carefully checking it.
  225. //
  226. if ( ! Delete( Array[ Count ],Size ) )
  227. { Result = false; }
  228. }
  229. return Result;
  230. }
  231. /********************************************************************/
  232. /* */
  233. /* Multiple memory allocations. */
  234. /* */
  235. /* Allocate a collection of memory elements and setup the */
  236. /* guard information so we can check they have not been */
  237. /* damaged later. */
  238. /* */
  239. /********************************************************************/
  240. bool ROCKALL_DEBUG_FRONT_END::MultipleNew
  241. (
  242. int *Actual,
  243. void *Array[],
  244. int Requested,
  245. int Size,
  246. int *Space,
  247. bool Zero
  248. )
  249. {
  250. //
  251. // We would realy like to use the multiple
  252. // new functionality of Rockall here but
  253. // it is too much effort. So we simply call
  254. // the standard debug new on each entry
  255. // in the array. Although this is not as
  256. // fast it does give more transparent results.
  257. //
  258. for ( (*Actual)=0;(*Actual) < Requested;(*Actual) ++ )
  259. {
  260. REGISTER void *Current = New( Size,Space,Zero );
  261. //
  262. // We add each sucessful memory allocation to
  263. // into the array.
  264. //
  265. if ( Current != ((void*) AllocationFailure) )
  266. { Array[ (*Actual) ] = Current; }
  267. else
  268. { break; }
  269. }
  270. return ((*Actual) == Requested);
  271. }
  272. /********************************************************************/
  273. /* */
  274. /* Memory allocation. */
  275. /* */
  276. /* We add some space on to the original allocation size for */
  277. /* various information and then call the allocator. We then */
  278. /* set the guard words so we can check for overruns. */
  279. /* */
  280. /********************************************************************/
  281. void *ROCKALL_DEBUG_FRONT_END::New( int Size,int *Space,bool Zero )
  282. {
  283. AUTO void *Address = ((void*) AllocationFailure);
  284. //
  285. // The size must be greater than or equal to zero.
  286. // We do not know how to allocate a negative amount
  287. // of memory.
  288. //
  289. if ( Size >= 0 )
  290. {
  291. //
  292. // We need to allocate some space plus an extra
  293. // bit for the guard words so we can detect any
  294. // corruption later.
  295. //
  296. if ( NewGuard( & Address,Size,Space ) )
  297. {
  298. //
  299. // Zero the allocation if requested. We do
  300. // this based on whether we are returning the
  301. // space information. If not we only zero
  302. // size requested. Otherwise we have to zero
  303. // the entire area.
  304. //
  305. if ( Zero )
  306. {
  307. ZeroMemory
  308. (
  309. Address,
  310. ((Space == NULL) ? Size : (*Space))
  311. );
  312. }
  313. }
  314. }
  315. else
  316. { UserError( Address,NULL,"Allocation size can not be negative" ); }
  317. return Address;
  318. }
  319. /********************************************************************/
  320. /* */
  321. /* Memory reallocation. */
  322. /* */
  323. /* We need to resize an allocation. We ensure the original */
  324. /* allocation was undamaged and then expand it. We also */
  325. /* update the guard words to reflect the changes. */
  326. /* */
  327. /********************************************************************/
  328. void *ROCKALL_DEBUG_FRONT_END::Resize
  329. (
  330. void *Address,
  331. int NewSize,
  332. int Move,
  333. int *Space,
  334. bool NoDelete,
  335. bool Zero
  336. )
  337. {
  338. REGISTER void *NewAddress = ((void*) AllocationFailure);
  339. //
  340. // A well known practice is to try to resize a null
  341. // pointer. This is really a very poor style but we
  342. // support it in any case.
  343. //
  344. if ( Address != ((void*) AllocationFailure) )
  345. {
  346. //
  347. // The new size must be greater than or equal to
  348. // zero. We do not know how to allocate a negative
  349. // amount of memory.
  350. //
  351. if ( NewSize >= 0 )
  352. {
  353. AUTO int ActualSize;
  354. //
  355. // Ask for the details of the allocation. This
  356. // will fail if the memory is not allocated.
  357. //
  358. if ( VerifyGuard( Address,& ActualSize,Space ) )
  359. {
  360. //
  361. // We always move an allocation if we are
  362. // allowed to as this has the best chance
  363. // of shaking out various types of bugs.
  364. //
  365. if ( Move != 0 )
  366. {
  367. //
  368. // We need to make sure we were able
  369. // to allocate the new memory otherwise
  370. // the copy will fail.
  371. //
  372. if ( NewGuard( & NewAddress,NewSize,Space ) )
  373. {
  374. REGISTER SBIT32 Smallest =
  375. ((ActualSize < NewSize) ? ActualSize : NewSize);
  376. REGISTER SBIT32 Largest =
  377. (((Space == NULL)) ? NewSize : (*Space));
  378. //
  379. // Copy the contents of the old allocation
  380. // to the new allocation.
  381. //
  382. memcpy
  383. (
  384. ((void*) NewAddress),
  385. ((void*) Address),
  386. ((int) Smallest)
  387. );
  388. //
  389. // Zero the allocation if requested. We do
  390. // this based on whether we are returning the
  391. // space information. If not we only zero
  392. // size requested. Otherwise we have to zero
  393. // the entire area.
  394. //
  395. if ( Zero )
  396. {
  397. ZeroMemory
  398. (
  399. (((char*) NewAddress) + Smallest),
  400. (Largest - Smallest)
  401. );
  402. }
  403. //
  404. // Delete the existing memory allocation
  405. // and clean up.
  406. //
  407. DeleteGuard( Address );
  408. }
  409. }
  410. }
  411. else
  412. { UserError( Address,NULL,"Resize on unallocated address" ); }
  413. }
  414. else
  415. { UserError( Address,NULL,"Allocation size must be positive" ); }
  416. }
  417. else
  418. { NewAddress = New( NewSize,Space,Zero ); }
  419. return NewAddress;
  420. }
  421. /********************************************************************/
  422. /* */
  423. /* Verify memory allocation details. */
  424. /* */
  425. /* Extract information about a memory allocation and just for */
  426. /* good measure check the guard words at the same time. */
  427. /* */
  428. /********************************************************************/
  429. bool ROCKALL_DEBUG_FRONT_END::Verify( void *Address,int *Space )
  430. {
  431. AUTO int Size;
  432. //
  433. // Verify that the supplied address is an area
  434. // of allocated memory. If not just exit as this
  435. // is only a request for information.
  436. //
  437. return VerifyGuard( Address,& Size,Space );
  438. }
  439. /********************************************************************/
  440. /* */
  441. /* Walk the heap. */
  442. /* */
  443. /* We have been asked to walk the heap. It is hard to know */
  444. /* why anybody might want to do this given the rest of the */
  445. /* functionality available. Nonetheless, we just do what is */
  446. /* required to keep everyone happy. */
  447. /* */
  448. /********************************************************************/
  449. bool ROCKALL_DEBUG_FRONT_END::Walk( bool *Active,void **Address,int *Space )
  450. {
  451. //
  452. // Walk the heap.
  453. //
  454. return WalkGuard( Active,Address,Space );
  455. }
  456. /********************************************************************/
  457. /* */
  458. /* Class destructor. */
  459. /* */
  460. /* Destory the current instance of the class. */
  461. /* */
  462. /********************************************************************/
  463. ROCKALL_DEBUG_FRONT_END::~ROCKALL_DEBUG_FRONT_END( void )
  464. { /* void */ }