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

446 lines
10 KiB

  1. /***
  2. *heapchk.c - perform a consistency check on the heap
  3. *
  4. * Copyright (c) 1989-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * Defines the _heapchk() and _heapset() functions
  8. *
  9. *Revision History:
  10. * 06-30-89 JCR Module created.
  11. * 07-28-89 GJF Added check for free block preceding the rover
  12. * 11-13-89 GJF Added MTHREAD support, also fixed copyright
  13. * 12-13-89 GJF Added check for descriptor order, did some tuning,
  14. * changed header file name to heap.h
  15. * 12-15-89 GJF Purged DEBUG286 stuff. Also added explicit _cdecl to
  16. * function definitions.
  17. * 12-19-89 GJF Got rid of checks involving plastdesc (revised check
  18. * of proverdesc and DEBUG errors accordingly)
  19. * 03-09-90 GJF Replaced _cdecl with _CALLTYPE1, added #include
  20. * <cruntime.h> and removed #include <register.h>.
  21. * 03-29-90 GJF Made _heap_checkset() _CALLTYPE4.
  22. * 09-27-90 GJF New-style function declarators.
  23. * 03-05-91 GJF Changed strategy for rover - old version available
  24. * by #define-ing _OLDROVER_.
  25. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  26. * 02-08-95 GJF Removed obsolete _OLDROVER_ code.
  27. * 04-30-95 GJF Spliced on winheap version.
  28. * 05-26-95 GJF Heap[Un]Lock is stubbed on Win95.
  29. * 07-04-95 GJF Fixed change above.
  30. * 03-07-96 GJF Added support for the small-block heap to _heapchk().
  31. * 04-30-96 GJF Deleted obsolete _heapset code, the functionality is
  32. * not very well defined nor useful on Win32. _heapset
  33. * now just returns _heapchk.
  34. * 05-22-97 RDK New small-block heap scheme implemented.
  35. * 12-17-97 GJF Exception-safe locking.
  36. * 09-30-98 GJF Bypass all small-block heap code when __sbh_initialized
  37. * is 0.
  38. * 11-16-98 GJF Merged in VC++ 5.0 version of small-block heap.
  39. * 05-01-99 PML Disable small-block heap for Win64.
  40. * 06-22-99 GJF Removed old small-block heap from static libs.
  41. *
  42. *******************************************************************************/
  43. #ifdef WINHEAP
  44. #include <cruntime.h>
  45. #include <windows.h>
  46. #include <errno.h>
  47. #include <malloc.h>
  48. #include <mtdll.h>
  49. #include <stddef.h>
  50. #include <stdlib.h>
  51. #include <string.h>
  52. #include <winheap.h>
  53. #ifndef _POSIX_
  54. /***
  55. *int _heapchk() - Validate the heap
  56. *int _heapset(_fill) - Obsolete function!
  57. *
  58. *Purpose:
  59. * Both functions perform a consistency check on the heap. The old
  60. * _heapset used to fill free blocks with _fill, in addition to
  61. * performing the consistency check. The current _heapset ignores the
  62. * passed parameter and just returns _heapchk.
  63. *
  64. *Entry:
  65. * For heapchk()
  66. * No arguments
  67. * For heapset()
  68. * int _fill - ignored
  69. *
  70. *Exit:
  71. * Returns one of the following values:
  72. *
  73. * _HEAPOK - completed okay
  74. * _HEAPEMPTY - heap not initialized
  75. * _HEAPBADBEGIN - can't find initial header info
  76. * _HEAPBADNODE - malformed node somewhere
  77. *
  78. * Debug version prints out a diagnostic message if an error is found
  79. * (see errmsg[] above).
  80. *
  81. * NOTE: Add code to support memory regions.
  82. *
  83. *Uses:
  84. *
  85. *Exceptions:
  86. *
  87. *******************************************************************************/
  88. int __cdecl _heapchk (void)
  89. {
  90. int retcode = _HEAPOK;
  91. #ifndef _WIN64
  92. if ( __active_heap == __V6_HEAP )
  93. {
  94. #ifdef _MT
  95. _mlock( _HEAP_LOCK );
  96. __try {
  97. #endif
  98. if ( __sbh_heap_check() < 0 )
  99. retcode = _HEAPBADNODE;
  100. #ifdef _MT
  101. }
  102. __finally {
  103. _munlock( _HEAP_LOCK );
  104. }
  105. #endif
  106. }
  107. #ifdef CRTDLL
  108. else if ( __active_heap == __V5_HEAP )
  109. {
  110. #ifdef _MT
  111. _mlock( _HEAP_LOCK );
  112. __try {
  113. #endif
  114. if ( __old_sbh_heap_check() < 0 )
  115. retcode = _HEAPBADNODE;
  116. #ifdef _MT
  117. }
  118. __finally {
  119. _munlock( _HEAP_LOCK );
  120. }
  121. #endif
  122. }
  123. #endif /* CRTDLL */
  124. #endif /* ndef _WIN64 */
  125. if (!HeapValidate(_crtheap, 0, NULL))
  126. {
  127. if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
  128. {
  129. _doserrno = ERROR_CALL_NOT_IMPLEMENTED;
  130. errno = ENOSYS;
  131. }
  132. else
  133. retcode = _HEAPBADNODE;
  134. }
  135. return retcode;
  136. }
  137. /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
  138. int __cdecl _heapset (
  139. unsigned int _fill
  140. )
  141. {
  142. return _heapchk();
  143. }
  144. #endif /* !_POSIX_ */
  145. #else /* ndef WINHEAP */
  146. #include <cruntime.h>
  147. #include <heap.h>
  148. #include <malloc.h>
  149. #include <mtdll.h>
  150. #include <stddef.h>
  151. #include <string.h>
  152. #ifdef DEBUG
  153. #include <stdio.h>
  154. #endif
  155. static int __cdecl _heap_checkset(unsigned int _fill);
  156. /* Debug error values */
  157. #define _EMPTYHEAP 0
  158. #define _BADROVER 1
  159. #define _BADRANGE 2
  160. #define _BADSENTINEL 3
  161. #define _BADEMPTY 4
  162. #define _EMPTYLOOP 5
  163. #define _BADFREE 6
  164. #define _BADORDER 7
  165. #ifdef DEBUG
  166. static char *errmsgs[] = {
  167. "_heap_desc.pfirstdesc == NULL",
  168. "_heap_desc.proverdesc not found in desc list",
  169. "address is outside the heap",
  170. "sentinel descriptor corrupted",
  171. "empty desc pblock != NULL (debug version)",
  172. "header ptr found twice in emptylist",
  173. "free block precedes rover",
  174. "adjacent descriptors in reverse order from heap blocks"
  175. };
  176. #define _PRINTERR(msg) \
  177. printf("\n*** HEAP ERROR: %s ***\n", errmsgs[(msg)]); \
  178. fflush(stdout);
  179. #else /* !DEBUG */
  180. #define _PRINTERR(msg)
  181. #endif /* DEBUG */
  182. /***
  183. *int _heapchk() - Validate the heap
  184. *int _heapset(_fill) - Validate the heap and fill in free entries
  185. *
  186. *Purpose:
  187. * Performs a consistency check on the heap.
  188. *
  189. *Entry:
  190. * For heapchk()
  191. * No arguments
  192. * For heapset()
  193. * int _fill - value to be used as filler in free entries
  194. *
  195. *Exit:
  196. * Returns one of the following values:
  197. *
  198. * _HEAPOK - completed okay
  199. * _HEAPEMPTY - heap not initialized
  200. * _HEAPBADBEGIN - can't find initial header info
  201. * _HEAPBADNODE - malformed node somewhere
  202. *
  203. * Debug version prints out a diagnostic message if an error is found
  204. * (see errmsg[] above).
  205. *
  206. * NOTE: Add code to support memory regions.
  207. *
  208. *Uses:
  209. *
  210. *Exceptions:
  211. *
  212. *******************************************************************************/
  213. int __cdecl _heapchk(void)
  214. {
  215. return(_heap_checkset((unsigned int)_HEAP_NOFILL));
  216. }
  217. int __cdecl _heapset (
  218. unsigned int _fill
  219. )
  220. {
  221. return(_heap_checkset(_fill));
  222. }
  223. /***
  224. *static int _heap_checkset(_fill) - check the heap and fill in the
  225. * free entries
  226. *
  227. *Purpose:
  228. * Workhorse routine for both _heapchk() and _heapset().
  229. *
  230. *Entry:
  231. * int _fill - either _HEAP_NOFILL or a value to be used as filler in
  232. * free entries
  233. *
  234. *Exit:
  235. * See description of _heapchk()/_heapset()
  236. *
  237. *******************************************************************************/
  238. static int __cdecl _heap_checkset (
  239. unsigned int _fill
  240. )
  241. {
  242. REG1 _PBLKDESC pdesc;
  243. REG2 _PBLKDESC pnext;
  244. int roverfound=0;
  245. int retval = _HEAPOK;
  246. /*
  247. * lock the heap
  248. */
  249. _mlock(_HEAP_LOCK);
  250. /*
  251. * Validate the sentinel
  252. */
  253. if (_heap_desc.sentinel.pnextdesc != NULL) {
  254. _PRINTERR(_BADSENTINEL);
  255. retval = _HEAPBADNODE;
  256. goto done;
  257. }
  258. /*
  259. * Test for an empty heap
  260. */
  261. if ( (_heap_desc.pfirstdesc == &_heap_desc.sentinel) &&
  262. (_heap_desc.proverdesc == &_heap_desc.sentinel) ) {
  263. retval = _HEAPEMPTY;
  264. goto done;
  265. }
  266. /*
  267. * Get and validate the first descriptor
  268. */
  269. if ((pdesc = _heap_desc.pfirstdesc) == NULL) {
  270. _PRINTERR(_EMPTYHEAP);
  271. retval = _HEAPBADBEGIN;
  272. goto done;
  273. }
  274. /*
  275. * Walk the heap descriptor list
  276. */
  277. while (pdesc != &_heap_desc.sentinel) {
  278. /*
  279. * Make sure address for this entry is in range.
  280. */
  281. if ( (_ADDRESS(pdesc) < _ADDRESS(_heap_desc.pfirstdesc)) ||
  282. (_ADDRESS(pdesc) > _heap_desc.sentinel.pblock) ) {
  283. _PRINTERR(_BADRANGE);
  284. retval = _HEAPBADNODE;
  285. goto done;
  286. }
  287. pnext = pdesc->pnextdesc;
  288. /*
  289. * Make sure the blocks corresponding to pdesc and pnext are
  290. * in proper order.
  291. */
  292. if ( _ADDRESS(pdesc) >= _ADDRESS(pnext) ) {
  293. _PRINTERR(_BADORDER);
  294. retval = _HEAPBADNODE;
  295. goto done;
  296. }
  297. /*
  298. * Check the backpointer.
  299. */
  300. if (_IS_INUSE(pdesc) || _IS_FREE(pdesc)) {
  301. if (!_CHECK_PDESC(pdesc)) {
  302. retval = _HEAPBADPTR;
  303. goto done;
  304. }
  305. }
  306. /*
  307. * Check for proverdesc
  308. */
  309. if (pdesc == _heap_desc.proverdesc)
  310. roverfound++;
  311. /*
  312. * If it is free, fill it in if appropriate
  313. */
  314. if ( _IS_FREE(pdesc) && (_fill != _HEAP_NOFILL) )
  315. memset( (void *)((unsigned)_ADDRESS(pdesc)+_HDRSIZE),
  316. _fill, _BLKSIZE(pdesc) );
  317. /*
  318. * Onto the next block
  319. */
  320. pdesc = pnext;
  321. }
  322. /*
  323. * Make sure we found 1 and only 1 rover
  324. */
  325. if (_heap_desc.proverdesc == &_heap_desc.sentinel)
  326. roverfound++;
  327. if (roverfound != 1) {
  328. _PRINTERR(_BADROVER);
  329. retval = _HEAPBADBEGIN;
  330. goto done;
  331. }
  332. /*
  333. * Walk the empty list. We can't really compare values against
  334. * anything but we may loop forever or may cause a fault.
  335. */
  336. pdesc = _heap_desc.emptylist;
  337. while (pdesc != NULL) {
  338. #ifdef DEBUG
  339. if (pdesc->pblock != NULL) {
  340. _PRINTERR(_BADEMPTY)
  341. retval = _HEAPBADPTR;
  342. goto done;
  343. }
  344. #endif
  345. pnext = pdesc->pnextdesc;
  346. /*
  347. * Header should only appear once
  348. */
  349. if (pnext == _heap_desc.emptylist) {
  350. _PRINTERR(_EMPTYLOOP)
  351. retval = _HEAPBADPTR;
  352. goto done;
  353. }
  354. pdesc = pnext;
  355. }
  356. /*
  357. * Common return
  358. */
  359. done:
  360. /*
  361. * release the heap lock
  362. */
  363. _munlock(_HEAP_LOCK);
  364. return(retval);
  365. }
  366. #endif /* WINHEAP */