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.

450 lines
11 KiB

  1. #define __DEBUG_C__
  2. #ifndef DEBUG
  3. #define DEBUG
  4. #endif
  5. /*****************************************************************************
  6. /* Debug include files
  7. /*****************************************************************************/
  8. #include <stdio.h>
  9. #include "debug.h"
  10. /*****************************************************************************
  11. /* Local debug macro definitions
  12. /*****************************************************************************/
  13. #define SIGNATURE_SIZE 2
  14. #define HEADER_SIGNATURE 'rdHM'
  15. #define FOOTER_SIGNATURE 'rtFM'
  16. #define MEMFILL_VALUE 0xCC
  17. #define MEMORY_TRAP(msg) TRAP(TRAP_LEVEL_4, msg)
  18. /*****************************************************************************
  19. /* Data types local to debug
  20. /*****************************************************************************/
  21. typedef struct {
  22. LIST_ENTRY ListEntry;
  23. PCHAR FileName;
  24. ULONG LineNumber;
  25. BOOL IsValid;
  26. ULONG BufferSize;
  27. ULONG Signature[SIGNATURE_SIZE];
  28. } ALLOCHEADER, *PALLOCHEADER;
  29. typedef struct {
  30. ULONG Signature[SIGNATURE_SIZE];
  31. } ALLOCFOOTER, *PALLOCFOOTER;
  32. typedef enum {
  33. MEM_ALLOC_NO_ERROR, MEM_ALLOC_HEADER_OVERFLOW,
  34. MEM_ALLOC_INVALID_HEADER, MEM_ALLOC_ALREADY_FREED,
  35. MEM_ALLOC_FOOTER_OVERFLOW
  36. } MEM_ALLOC_STATUS, *PMEM_ALLOC_STATUS;
  37. /*****************************************************************************
  38. /* Global debug data variables
  39. /*****************************************************************************/
  40. INT Debug_TrapLevel = TRAP_LEVEL_1;
  41. BOOL Debug_TrapOn = FALSE;
  42. static INT Debug_ListCount = 0;
  43. /*****************************************************************************
  44. /* Local debug data variables
  45. /*****************************************************************************/
  46. static LIST_ENTRY Debug_AllocList = { &Debug_AllocList, &Debug_AllocList };
  47. /*****************************************************************************
  48. /* Local debug function declarations
  49. /*****************************************************************************/
  50. BOOL
  51. Debug_IsEmptyList(
  52. IN PLIST_ENTRY ListHead
  53. );
  54. VOID
  55. Debug_InsertIntoListAtTail(
  56. IN OUT PLIST_ENTRY ListHead,
  57. IN OUT PLIST_ENTRY NewEntry
  58. );
  59. PLIST_ENTRY
  60. Debug_RemoveHeadOfList(
  61. IN PLIST_ENTRY ListHead
  62. );
  63. VOID
  64. Debug_RemoveListEntry(
  65. IN PLIST_ENTRY OldEntry
  66. );
  67. /*****************************************************************************
  68. /* Global debug function definitions
  69. /*****************************************************************************/
  70. HGLOBAL __cdecl
  71. Debug_Alloc(
  72. IN PCHAR FileName,
  73. IN ULONG LineNumber,
  74. IN DWORD AllocSize
  75. )
  76. {
  77. INT Index;
  78. DWORD BytesToAllocate;
  79. PALLOCHEADER NewBuffer;
  80. PALLOCFOOTER BufferFooter;
  81. BytesToAllocate = sizeof(ALLOCHEADER) + sizeof(ALLOCFOOTER) + AllocSize;
  82. NewBuffer = (PALLOCHEADER) GlobalAlloc(GPTR, BytesToAllocate);
  83. if (NULL != NewBuffer) {
  84. /*
  85. // Initialize the header structure
  86. */
  87. NewBuffer -> FileName = FileName;
  88. NewBuffer -> LineNumber = LineNumber;
  89. NewBuffer -> IsValid = TRUE;
  90. NewBuffer -> BufferSize = AllocSize;
  91. for (Index = 0; Index < SIGNATURE_SIZE; Index++)
  92. NewBuffer -> Signature[Index] = HEADER_SIGNATURE;
  93. /*
  94. // Insert the new allocation block into the list of allocation blocks
  95. */
  96. Debug_InsertIntoListAtTail(&Debug_AllocList,
  97. &(NewBuffer -> ListEntry)
  98. );
  99. /*
  100. // Increment to the pointer that will get returned to the user and
  101. // initialize that to the fill value
  102. */
  103. NewBuffer++;
  104. FillMemory(NewBuffer, AllocSize, MEMFILL_VALUE);
  105. /*
  106. // Initialize the footer on the memory block
  107. */
  108. BufferFooter = (PALLOCFOOTER) (((PCHAR) NewBuffer) + AllocSize);
  109. for (Index = 0; Index < SIGNATURE_SIZE; Index++)
  110. BufferFooter -> Signature[Index] = FOOTER_SIGNATURE;
  111. }
  112. return (NewBuffer);
  113. }
  114. HGLOBAL __cdecl
  115. Debug_Realloc(
  116. IN PCHAR FileName,
  117. IN ULONG LineNumber,
  118. IN PALLOCHEADER MemoryBlock,
  119. IN DWORD AllocSize
  120. )
  121. {
  122. MEM_ALLOC_STATUS AllocStatus;
  123. PALLOCHEADER OldBuffer;
  124. PALLOCHEADER NewBuffer;
  125. ASSERT(NULL != MemoryBlock);
  126. OldBuffer = MemoryBlock-1;
  127. Debug_ValidateMemoryAlloc(MemoryBlock,
  128. &AllocStatus
  129. );
  130. NewBuffer = (PALLOCHEADER) Debug_Alloc(FileName,
  131. LineNumber,
  132. AllocSize
  133. );
  134. if (NULL != NewBuffer) {
  135. CopyMemory(NewBuffer, MemoryBlock, OldBuffer -> BufferSize);
  136. Debug_Free(MemoryBlock);
  137. }
  138. return (NewBuffer);
  139. }
  140. HGLOBAL __cdecl
  141. Debug_Free(
  142. IN PALLOCHEADER Buffer
  143. )
  144. {
  145. PALLOCHEADER Header;
  146. MEM_ALLOC_STATUS AllocStatus;
  147. Header = Buffer-1;
  148. Debug_ValidateMemoryAlloc(Buffer, &AllocStatus);
  149. /*
  150. // If the block has already been freed, we will simply return NULL.
  151. */
  152. if (MEM_ALLOC_ALREADY_FREED == AllocStatus)
  153. return (NULL);
  154. /*
  155. // If we at least have an valid header, we can remove the header entry
  156. // from our list of allocated blocks
  157. */
  158. if (MEM_ALLOC_INVALID_HEADER != AllocStatus) {
  159. Debug_RemoveListEntry(&(Header -> ListEntry));
  160. Header -> IsValid = FALSE;
  161. }
  162. /*
  163. // Free the block of memory
  164. */
  165. return (GlobalFree(Header));
  166. }
  167. BOOL __cdecl
  168. Debug_ValidateMemoryAlloc(
  169. IN PALLOCHEADER Header,
  170. OUT PMEM_ALLOC_STATUS AllocStatus
  171. )
  172. {
  173. INT Index;
  174. BOOL IsBadSignature;
  175. PALLOCFOOTER Footer;
  176. MEM_ALLOC_STATUS Status;
  177. /*
  178. // Begin by validating the header signature. If this is messed up there's
  179. // nothing else that can be done. Check each SIGNATURE entry
  180. // starting from the end to verify it is correct. If any of them are
  181. // not equal to HEADER_SIGNATURE then something went wrong. However,
  182. // if the first element in the array. Index 0 is valid, then we can
  183. // reasonably assume that the rest of the header is correct and we can
  184. // extract the appropriate info and display a more meaningful error
  185. // message. If that signature is not valid, however, there's no way
  186. // to insure that any of the other values are valid and therefore we
  187. // can't extract the valid info from the header.
  188. */
  189. Status = MEM_ALLOC_NO_ERROR;
  190. Header--;
  191. IsBadSignature = FALSE;
  192. for (Index = SIGNATURE_SIZE-1; Index >= 0; Index--) {
  193. if (Header -> Signature[Index] != HEADER_SIGNATURE) {
  194. IsBadSignature = TRUE;
  195. break;
  196. }
  197. }
  198. if (IsBadSignature) {
  199. if (HEADER_SIGNATURE == Header -> Signature[0]) {
  200. static CHAR msg[1024];
  201. sprintf(msg,
  202. "Header overflow in block: %p\nAllocated by %s on line %u\n",
  203. Header,
  204. Header -> FileName,
  205. Header -> LineNumber
  206. );
  207. MEMORY_TRAP(msg);
  208. Status = MEM_ALLOC_HEADER_OVERFLOW;
  209. }
  210. else {
  211. static CHAR msg[1024];
  212. sprintf(msg,
  213. "Corrupted allocation header in block: %p\nCannot extract allocation info",
  214. Header
  215. );
  216. MEMORY_TRAP(msg);
  217. Status = MEM_ALLOC_INVALID_HEADER;
  218. }
  219. }
  220. /*
  221. // We passed the signature phase, let's validate the rest of the memory
  222. // allocation beginning with the header where we'll check the IsValid
  223. // flag to see if this chunk of memory has previously been freed.
  224. */
  225. else if (!Header -> IsValid) {
  226. static CHAR msg[1024];
  227. sprintf(msg,
  228. "Allocated block already been freed: %p\nAllocated by %s on line %u\n",
  229. Header,
  230. Header -> FileName,
  231. Header -> LineNumber
  232. );
  233. MEMORY_TRAP(msg);
  234. Status = MEM_ALLOC_ALREADY_FREED;
  235. }
  236. else {
  237. /*
  238. // Next step is to verify that the footer is still correct and we did not
  239. // overflow our buffer on the other end.
  240. */
  241. Footer = (PALLOCFOOTER) (((PCHAR) (Header+1)) + Header -> BufferSize);
  242. IsBadSignature = FALSE;
  243. for (Index = 0; Index < SIGNATURE_SIZE; Index++) {
  244. if (FOOTER_SIGNATURE != Footer -> Signature[Index]) {
  245. IsBadSignature = TRUE;
  246. break;
  247. }
  248. }
  249. if (IsBadSignature) {
  250. static CHAR msg[1024];
  251. sprintf(msg,
  252. "Footer overflow in block: %p\nAllocated by %s on line %u\n",
  253. Header,
  254. Header -> FileName,
  255. Header -> LineNumber
  256. );
  257. MEMORY_TRAP(msg);
  258. Status = MEM_ALLOC_FOOTER_OVERFLOW;
  259. return (FALSE);
  260. }
  261. }
  262. if (NULL != AllocStatus)
  263. *AllocStatus = Status;
  264. return (MEM_ALLOC_NO_ERROR == Status);
  265. }
  266. VOID __cdecl
  267. Debug_CheckForMemoryLeaks(
  268. )
  269. {
  270. static CHAR msg[1024];
  271. PALLOCHEADER Header;
  272. while (!Debug_IsEmptyList(&Debug_AllocList)) {
  273. Header = (PALLOCHEADER) Debug_RemoveHeadOfList(&Debug_AllocList);
  274. sprintf(msg,
  275. "Memory leak block: %p\nAllocated by %s on line %u\n",
  276. Header,
  277. Header -> FileName,
  278. Header -> LineNumber
  279. );
  280. MEMORY_TRAP(msg);
  281. }
  282. return;
  283. }
  284. /*****************************************************************************
  285. /* Local debug function definitions
  286. /*****************************************************************************/
  287. BOOL
  288. Debug_IsEmptyList(
  289. IN PLIST_ENTRY ListHead
  290. )
  291. {
  292. return (ListHead -> Flink == ListHead);
  293. }
  294. VOID
  295. Debug_InsertIntoListAtTail(
  296. IN OUT PLIST_ENTRY ListHead,
  297. IN OUT PLIST_ENTRY NewEntry
  298. )
  299. {
  300. PLIST_ENTRY OldTail;
  301. OldTail = ListHead -> Blink;
  302. NewEntry -> Flink = ListHead;
  303. NewEntry -> Blink = OldTail;
  304. OldTail -> Flink = NewEntry;
  305. ListHead -> Blink = NewEntry;
  306. Debug_ListCount++;
  307. return;
  308. }
  309. VOID
  310. Debug_RemoveListEntry(
  311. IN PLIST_ENTRY OldEntry
  312. )
  313. {
  314. PLIST_ENTRY Flink;
  315. PLIST_ENTRY Blink;
  316. Flink = OldEntry -> Flink;
  317. Blink = OldEntry -> Blink;
  318. Blink -> Flink = OldEntry -> Flink;
  319. Flink -> Blink = OldEntry -> Blink;
  320. Debug_ListCount--;
  321. return;
  322. }
  323. PLIST_ENTRY
  324. Debug_RemoveHeadOfList(
  325. IN PLIST_ENTRY ListHead
  326. )
  327. {
  328. PLIST_ENTRY OldHead;
  329. OldHead = ListHead -> Flink;
  330. ListHead -> Flink = OldHead -> Flink;
  331. OldHead -> Flink -> Blink = ListHead;
  332. Debug_ListCount--;
  333. return (OldHead);
  334. }