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.

1032 lines
20 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. hcttools.c
  5. Abstract:
  6. This module contains helpful functions and wrappers for debugging and
  7. tools commonly used throughout hct programs.
  8. Environment:
  9. User mode
  10. Revision History:
  11. 05-Sep-1997 : Jason Allor (jasonall)
  12. --*/
  13. #include "hcttools.h"
  14. #ifdef DEBUG
  15. static PBLOCKINFO g_pbiHead;
  16. static USHORT g_usMalloc;
  17. static USHORT g_usFree;
  18. #endif
  19. /*++
  20. Routine Description: InitializeMemoryManager
  21. Initializes globals used by this module
  22. Arguments:
  23. none
  24. Return Value:
  25. VOID
  26. --*/
  27. VOID InitializeMemoryManager()
  28. {
  29. #ifdef DEBUG
  30. g_pbiHead = NULL;
  31. g_usMalloc = 0;
  32. g_usFree = 0;
  33. #else
  34. return;
  35. #endif
  36. } // InitializeMemoryManager //
  37. #ifdef DEBUG
  38. /*++
  39. Routine Description: GetBlockInfo
  40. Searches the memory log to find the block that pb points into and
  41. returns a pointer to the corresponding blockinfo structure of the
  42. memory log. Note: pb must point into an allocated block or you
  43. will get an assertion failure. The function either asserts or
  44. succeeds -- it never returns an error.
  45. Arguments:
  46. pb: block to get info about
  47. Return Value:
  48. BLOCKINFO: returns the information
  49. --*/
  50. static PBLOCKINFO GetBlockInfo(IN PBYTE pb)
  51. {
  52. PBLOCKINFO pbi;
  53. for (pbi = g_pbiHead; pbi != NULL; pbi = pbi->pbiNext)
  54. {
  55. PBYTE pbStart = pbi->pb;
  56. PBYTE pbEnd = pbi->pb + pbi->size - 1;
  57. if (PtrGrtrEq(pb, pbStart) && PtrLessEq(pb, pbEnd))
  58. {
  59. break;
  60. }
  61. }
  62. //
  63. // Couldn't find pointer? It is garbage, pointing to a block that was
  64. // freed, or pointing to a block that moved when it was resized?
  65. //
  66. __ASSERT(pbi != NULL);
  67. return (pbi);
  68. } // GetBlockInfo //
  69. /*++
  70. Routine Description: CreateBlockInfo
  71. Creates a log entry for the memory block defined by pbNew:sizeNew.
  72. Arguments:
  73. pbNew: new block
  74. sizeNew: the size of the new block
  75. cszFile: the file name the code is located in \ these tell what code
  76. iLine: the line number of the assertion / called the malloc
  77. Return Value:
  78. BOOL: TRUE if it successfully creates the log information,
  79. FALSE otherwise
  80. --*/
  81. BOOL CreateBlockInfo(OUT PBYTE pbNew,
  82. IN size_t sizeNew,
  83. IN PCHAR cszFile,
  84. IN UINT iLine)
  85. {
  86. PBLOCKINFO pbi;
  87. __ASSERT(pbNew != NULL && sizeNew != 0);
  88. pbi = (PBLOCKINFO)malloc(sizeof(BLOCKINFO));
  89. if (pbi != NULL)
  90. {
  91. pbi->pb = pbNew;
  92. pbi->size = sizeNew;
  93. pbi->pbiNext = g_pbiHead;
  94. pbi->iLine = iLine;
  95. strcpy(pbi->cszFile, cszFile);
  96. g_pbiHead = pbi;
  97. }
  98. return (pbi != NULL);
  99. } // CreateBlockInfo //
  100. /*++
  101. Routine Description: FreeBlockInfo
  102. Destroys the log entry for the memory block that pbToFree
  103. points to. pbToFree must point to the start of an allocated
  104. block or you will get an assertion failure
  105. Arguments:
  106. pbToFree: the block to free
  107. Return Value:
  108. void
  109. --*/
  110. void FreeBlockInfo(IN PBYTE pbToFree)
  111. {
  112. PBLOCKINFO pbi, pbiPrev;
  113. pbiPrev = NULL;
  114. for (pbi = g_pbiHead; pbi != NULL; pbi = pbi->pbiNext)
  115. {
  116. if (PtrEqual(pbi->pb, pbToFree))
  117. {
  118. if (pbiPrev == NULL)
  119. {
  120. g_pbiHead = pbi->pbiNext;
  121. }
  122. else
  123. {
  124. pbiPrev->pbiNext = pbi->pbiNext;
  125. }
  126. break;
  127. }
  128. pbiPrev = pbi;
  129. }
  130. //
  131. // If pbi is NULL, the pbToFree is invalid
  132. //
  133. __ASSERT(pbi != NULL);
  134. //
  135. // Destroy the contents of *pbi before freeing them
  136. //
  137. memset(pbi, GARBAGE, sizeof(BLOCKINFO));
  138. free(pbi);
  139. } // FreeBlockInfo //
  140. /*++
  141. Routine Description: UpdateBlockInfo
  142. UpdateBlockInfo looks up the log information for the memory
  143. block that pbOld points to. The function then updates the log
  144. information to reflect the fact that the block new lives at pbNew
  145. and is "sizeNew" bytes long. pbOld must point to the start of an
  146. allocated block or you will get an assertion failure
  147. Arguments:
  148. pbOld: old location
  149. pbNew: new location
  150. sizeNew: the new size
  151. Return Value:
  152. void
  153. --*/
  154. void UpdateBlockInfo(IN PBYTE pbOld,
  155. IN PBYTE pbNew,
  156. IN size_t sizeNew)
  157. {
  158. PBLOCKINFO pbi;
  159. __ASSERT(pbNew != NULL && sizeNew);
  160. pbi = GetBlockInfo(pbOld);
  161. __ASSERT(pbOld == pbi->pb);
  162. pbi->pb = pbNew;
  163. pbi->size = sizeNew;
  164. } // UpdateBlockInfo //
  165. /*++
  166. Routine Description: SizeOfBlock
  167. Returns the size of the block that pb points to. pb must point to
  168. the start of an allocated block or you will get an assertion failure
  169. Arguments:
  170. pb: the block to find the size of
  171. Return Value:
  172. size_t: returns the size
  173. --*/
  174. size_t SizeOfBlock(IN PBYTE pb)
  175. {
  176. PBLOCKINFO pbi;
  177. pbi = GetBlockInfo(pb);
  178. __ASSERT(pb == pbi->pb);
  179. return (pbi->size);
  180. return 1;
  181. } // SizeOfBlock //
  182. /*++
  183. Routine Description: ClearMemoryRefs
  184. ClearMemoryRefs marks all blocks in the memory log as
  185. being unreferenced
  186. Arguments:
  187. void
  188. Return Value:
  189. void
  190. --*/
  191. void ClearMemoryRefs()
  192. {
  193. PBLOCKINFO pbi;
  194. for (pbi = g_pbiHead; pbi != NULL; pbi = pbi->pbiNext)
  195. {
  196. pbi->boolReferenced = FALSE;
  197. }
  198. } // ClearMemoryRefs //
  199. /*++
  200. Routine Description: NoteMemoryRef
  201. Marks the block that pv points into as being referenced.
  202. Note: pv does not have to point to the start of a block; it may
  203. point anywhere withing an allocated block
  204. Arguments:
  205. pv: the block to mark
  206. Return Value:
  207. void
  208. --*/
  209. void NoteMemoryRef(IN PVOID pv)
  210. {
  211. PBLOCKINFO pbi;
  212. pbi = GetBlockInfo((PBYTE)pv);
  213. pbi->boolReferenced = TRUE;
  214. } // NoteMemoryRef //
  215. /*++
  216. Routine Description: CheckMemoryRefs
  217. Scans the memory log looking for blocks that have not been
  218. marked with a call to NoteMemoryRef. It this function finds an
  219. unmarked block, it asserts.
  220. Arguments:
  221. void
  222. Return Value:
  223. void
  224. --*/
  225. void CheckMemoryRefs()
  226. {
  227. PBLOCKINFO pbi;
  228. for (pbi = g_pbiHead; pbi != NULL; pbi = pbi->pbiNext)
  229. {
  230. //
  231. // A simple check for block integrity. If this assert fires, it
  232. // means that something is wrong with the debug code that manages
  233. // blockinfo or, possibly, that a wild memory store has thrashed
  234. // the data structure. Either way, there's a bug
  235. //
  236. __ASSERT(pbi->pb != NULL && pbi->size);
  237. //
  238. // A check for lost or leaky memory. If this assert fires, it means
  239. // that the app has either lost track of this block or that not all
  240. // global pointers have been accounted for with NoteMemoryRef.
  241. //
  242. __ASSERT(pbi->boolReferenced);
  243. }
  244. } // CheckMemoryRefs //
  245. /*++
  246. Routine Description: ValidPointer
  247. Verifies that pv points into an allocated memory block and that there
  248. are at least "size" allocated bytes from pv to the end of a block. If
  249. either condition is not met, ValidPointer will assert.
  250. Arguments:
  251. pv: the block to check out
  252. size: the size to match against
  253. Return Value:
  254. BOOL: Always returns TRUE.
  255. The reason this always returns TRUE is to allow you to call the
  256. function within an __ASSERT macro. While this isn't the most efficient
  257. method to use, using the macro neatly handles the debug-vs-ship
  258. version control issue without your having to resort to #ifdef
  259. DEBUGS or to introducing other __ASSERT-like macros.
  260. --*/
  261. BOOL ValidPointer(IN PVOID pv,
  262. IN size_t size)
  263. {
  264. PBLOCKINFO pbi;
  265. PBYTE pb = (PBYTE)pv;
  266. __ASSERT(pv != NULL && size);
  267. pbi = GetBlockInfo(pb);
  268. //
  269. // size isn't valid if pb+size overflows the block
  270. //
  271. __ASSERT(PtrLessEq(pb + size, pbi->pb + pbi->size));
  272. return TRUE;
  273. } // ValidPointer //
  274. /*++
  275. Routine Description: _Assert
  276. My assert function. Simply outputs the file name and line number
  277. to a MessageBox and then kills the program. Note: this should only
  278. be called by the __ASSERT macro above
  279. Arguments:
  280. cszFile: the file name the code is located in
  281. iLine: the line number of the assertion
  282. Return Value:
  283. void
  284. --*/
  285. void MyAssert(IN PCHAR cszFile,
  286. IN UINT iLine)
  287. {
  288. WCHAR wszFile[100];
  289. TCHAR tszMessage[100];
  290. fflush(NULL);
  291. _stprintf(tszMessage, TEXT("Assertion failed: %s, line %u"),
  292. ConvertAnsi(cszFile, wszFile, 100), iLine);
  293. MessageBox(NULL, tszMessage, NULL, MB_OK);
  294. abort();
  295. } // MyAssert //
  296. #endif // DEBUG
  297. /*++
  298. Routine Description: __MALLOC
  299. Don't call this function. Instead, call the macro MyMalloc,
  300. which calls this function.
  301. Wrapper for malloc function. Provides better calling convention
  302. and debug syntax. Calling example:
  303. malloc: pbBlock = (byte *)malloc(sizeof(pbBlock));
  304. MyMalloc: MyMalloc(&pbBlock, sizeof(pbBlock));
  305. Arguments:
  306. ppv: variable to be malloced
  307. size: the memory size to use
  308. cszFile: the file name the code is located in \ these tell what code
  309. iLine: the line number of the assertion / called the malloc
  310. Return Value:
  311. BOOL: TRUE if malloc succeeds, FALSE if it does not
  312. --*/
  313. BOOL __MALLOC(IN OUT void **ppv,
  314. IN size_t size,
  315. IN PCHAR cszFile,
  316. IN UINT iLine)
  317. {
  318. BYTE **ppb = (BYTE **)ppv;
  319. __ASSERT(ppv != NULL && size != 0);
  320. *ppb = (BYTE *)malloc(size);
  321. #ifdef DEBUG
  322. g_usMalloc++;
  323. if (*ppb != NULL)
  324. {
  325. //
  326. // Shred the memory
  327. //
  328. memset(*ppb, GARBAGE, size);
  329. //
  330. // Record information about this block in memory
  331. //
  332. if (!CreateBlockInfo(*ppb, size, cszFile, iLine))
  333. {
  334. free(*ppb);
  335. *ppb = NULL;
  336. }
  337. }
  338. #endif
  339. return (*ppb != NULL);
  340. } // __MALLOC //
  341. /*++
  342. Routine Description: __FREE
  343. Wrapper for free function. Provides debug syntax.
  344. Sets the pointer to NULL after it is done freeing it.
  345. This should always be called in a format such as:
  346. Old syntax: free(pVariable);
  347. New syntax: MyFree(&pVariable);
  348. Arguments:
  349. ppv: variable to be freed
  350. Return Value:
  351. void
  352. --*/
  353. void __FREE(IN void **ppv)
  354. {
  355. //
  356. // *ppv should never be NULL. This is technically legal
  357. // but it's not good behavior
  358. //
  359. __ASSERT (*ppv != NULL);
  360. #ifdef DEBUG
  361. g_usFree++;
  362. //
  363. // Shred the memory
  364. //
  365. memset(*ppv, GARBAGE, SizeOfBlock(*ppv));
  366. FreeBlockInfo(*ppv);
  367. #endif
  368. free(*ppv);
  369. *ppv = NULL;
  370. } // __FREE //
  371. /*++
  372. Routine Description: CheckAllocs
  373. Checks to make sure that everything has been freed. This
  374. should be called right before the program ends.
  375. Arguments:
  376. none
  377. Return Value:
  378. VOID: If this function finds any allocated memory that
  379. has not been freed, it will __ASSERT.
  380. --*/
  381. VOID CheckAllocs()
  382. {
  383. #ifndef DEBUG
  384. return;
  385. #else
  386. PBLOCKINFO pbi;
  387. TCHAR tszInvalidMemoryLocations[10000];
  388. USHORT usCounter = 0;
  389. BOOL bBadMemFound = FALSE;
  390. WCHAR wszUnicode[100];
  391. _stprintf(tszInvalidMemoryLocations,
  392. TEXT("Unfreed Malloc Locations: \n\n"));
  393. _stprintf(tszInvalidMemoryLocations,
  394. TEXT("%sMallocs = %d Frees = %d\n\n"),
  395. tszInvalidMemoryLocations, g_usMalloc, g_usFree);
  396. for (pbi = g_pbiHead; pbi != NULL; pbi = pbi->pbiNext)
  397. {
  398. bBadMemFound = TRUE;
  399. //
  400. // Only print out the first 20 unfreed blocks we
  401. // find, so the messagebox won't be too huge
  402. //
  403. if (usCounter++ < 20)
  404. {
  405. _stprintf(tszInvalidMemoryLocations,
  406. TEXT("%sFile = %s \t Line = %d\n"),
  407. tszInvalidMemoryLocations,
  408. ConvertAnsi(pbi->cszFile, wszUnicode, 100),
  409. pbi->iLine);
  410. }
  411. }
  412. if (bBadMemFound)
  413. {
  414. MessageBox(NULL, tszInvalidMemoryLocations, NULL,
  415. MB_OK | MB_ICONERROR);
  416. __ASSERT(TRUE);
  417. }
  418. #endif
  419. } // CheckAllocs //
  420. /*++
  421. Routine Description: StrNCmp
  422. Compares two TCHAR strings. Both strings length must be >= ulLength
  423. Arguments:
  424. tszString1: the first string
  425. tszString2: the second string
  426. ulLength: the length to compare
  427. Return Value:
  428. BOOL: TRUE if strings are equal, FALSE if not
  429. --*/
  430. BOOL StrNCmp(IN PTCHAR tszString1,
  431. IN PTCHAR tszString2,
  432. IN ULONG ulLength)
  433. {
  434. ULONG ulIndex;
  435. //
  436. // Both strings must be valid and ulLength must be > 0
  437. //
  438. __ASSERT(tszString1 != NULL);
  439. __ASSERT(tszString2 != NULL);
  440. __ASSERT(ulLength > 0);
  441. if (_tcslen(tszString1) < ulLength ||
  442. _tcslen(tszString2) < ulLength)
  443. {
  444. goto RetFALSE;
  445. }
  446. for (ulIndex = 0; ulIndex < ulLength; ulIndex++)
  447. {
  448. if (tszString1[ulIndex] != tszString2[ulIndex])
  449. {
  450. goto RetFALSE;
  451. }
  452. }
  453. return TRUE;
  454. RetFALSE:
  455. return FALSE;
  456. } // StrNCmp //
  457. /*++
  458. Routine Description: StrCmp
  459. Compares two TCHAR strings
  460. Arguments:
  461. tszString1: the first string
  462. tszString2: the second string
  463. Return Value:
  464. BOOL: TRUE if strings are equal, FALSE if not
  465. --*/
  466. BOOL StrCmp(IN PTCHAR tszString1,
  467. IN PTCHAR tszString2)
  468. {
  469. ULONG ulIndex;
  470. ULONG ulLength;
  471. //
  472. // Both strings must be valid
  473. //
  474. __ASSERT(tszString1 != NULL);
  475. __ASSERT(tszString2 != NULL);
  476. ulLength = _tcslen(tszString1);
  477. if (ulLength != _tcslen(tszString2))
  478. {
  479. goto RetFALSE;
  480. }
  481. for (ulIndex = 0; ulIndex < ulLength; ulIndex++)
  482. {
  483. if (tszString1[ulIndex] != tszString2[ulIndex])
  484. {
  485. goto RetFALSE;
  486. }
  487. }
  488. return TRUE;
  489. RetFALSE:
  490. return FALSE;
  491. } // StrCmp //
  492. /*++
  493. Routine Description: AnsiToUnicode
  494. Converts an Ansi string to a Unicode string.
  495. Arguments:
  496. cszAnsi: the Ansi string to convert
  497. wszUnicode: unicode buffer to store new string. Must not be NULL
  498. ulSize: must be set to the size of the wszUnicode buffer
  499. Return Value:
  500. PWCHAR: returns the wszUnicode buffer
  501. --*/
  502. PWCHAR AnsiToUnicode(IN PCHAR cszAnsi,
  503. OUT PWCHAR wszUnicode,
  504. IN ULONG ulSize)
  505. {
  506. USHORT i;
  507. USHORT usAnsiLength;
  508. CHAR cszTemp[2000];
  509. CHAR cszTemp2[2000];
  510. //
  511. // Clear out the new Unicode string
  512. //
  513. ZeroMemory(wszUnicode, ulSize);
  514. //
  515. // Record the length of the original Ansi string
  516. //
  517. usAnsiLength = strlen(cszAnsi);
  518. //
  519. // Copy the unicode string to a temporary buffer
  520. //
  521. strcpy(cszTemp, cszAnsi);
  522. for (i = 0; i < usAnsiLength && i < ulSize - 1; i++)
  523. {
  524. //
  525. // Copy the current character
  526. //
  527. wszUnicode[i] = (WCHAR)cszTemp[i];
  528. }
  529. wszUnicode[i] = '\0';
  530. return wszUnicode;
  531. } // AnsiToUnicode //
  532. /*++
  533. Routine Description: UnicodeToAnsi
  534. Converts a Unicode string to an Ansi string.
  535. Arguments:
  536. wszUnicode: the Unicode string to convert
  537. cszAnsi: Ansi buffer to store new string. Must not be NULL
  538. ulSize: must be set to the size of the cszAnsi buffer
  539. Return Value:
  540. PCHAR: returns the cszAnsi buffer
  541. --*/
  542. PCHAR UnicodeToAnsi(IN PWCHAR wszUnicode,
  543. OUT PCHAR cszAnsi,
  544. IN ULONG ulSize)
  545. {
  546. USHORT i;
  547. USHORT usUnicodeLength;
  548. WCHAR wszTemp[2000];
  549. //
  550. // Record the length of the original Unicode string
  551. //
  552. usUnicodeLength = wcslen(wszUnicode);
  553. //
  554. // Copy the unicode string to a temporary buffer
  555. //
  556. wcscpy(wszTemp, wszUnicode);
  557. for (i = 0; i < usUnicodeLength && i < ulSize - 1; i++)
  558. {
  559. //
  560. // Copy the current character
  561. //
  562. cszAnsi[i] = (CHAR)wszTemp[0];
  563. //
  564. // Shift the unicode string up by one position
  565. //
  566. wcscpy(wszTemp, wszTemp + 1);
  567. }
  568. //
  569. // Add a null terminator to the end of the new ansi string
  570. //
  571. cszAnsi[i] = '\0';
  572. return cszAnsi;
  573. } // UnicodeToAnsi //
  574. /*++
  575. Routine Description: ConvertAnsi
  576. Receives an Ansi string. Returns the equivalent string in Ansi or
  577. Unicode, depending on the current environment
  578. Arguments:
  579. cszAnsi: the Ansi string to convert
  580. wszUnicode: unicode buffer to store new string (if needed).
  581. Must not be NULL
  582. ulSize: must be set to the size of the wszUnicode buffer
  583. Return Value:
  584. TCHAR: returns the ANSI or Unicode string
  585. --*/
  586. PTCHAR ConvertAnsi(IN OUT PCHAR cszAnsi,
  587. IN OUT PWCHAR wszUnicode,
  588. IN ULONG ulSize)
  589. {
  590. //
  591. // If Unicode, we need to convert the string
  592. //
  593. #ifdef UNICODE
  594. return AnsiToUnicode(cszAnsi, wszUnicode, ulSize);
  595. //
  596. // If not Unicode, just return the original Ansi string
  597. //
  598. #else
  599. return cszAnsi;
  600. #endif
  601. } // ConvertAnsi //
  602. /*++
  603. Routine Description: ConvertUnicode
  604. Receives a Unicode string. Returns the equivalent string in Ansi or
  605. Unicode, depending on the current environment
  606. Arguments:
  607. wszUnicode: the Unicode string to convert
  608. cszAnsi: ANSI buffer to store new string (if needed).
  609. Must not be NULL
  610. ulSize: must be set to the size of the cszAnsi buffer
  611. Return Value:
  612. TCHAR: returns the ANSI or Unicode string
  613. --*/
  614. PTCHAR ConvertUnicode(IN OUT PWCHAR wszUnicode,
  615. IN OUT PCHAR cszAnsi,
  616. IN ULONG ulSize)
  617. {
  618. //
  619. // If Unicode, just return the original Unicode string
  620. //
  621. #ifdef UNICODE
  622. return wszUnicode;
  623. //
  624. // If not Unicode, need to convert to Ansi
  625. //
  626. #else
  627. return UnicodeToAnsi(wszUnicode, cszAnsi, ulSize);
  628. #endif
  629. } // ConvertUnicode //
  630. /*++
  631. Routine Description: ErrorMsg
  632. Converts a numerical winerror into it's string value
  633. Arguments:
  634. ulError: the error number
  635. tszBuffer: this buffer is used to return the string interpretation
  636. must be declared of size MAX_ERROR_LEN
  637. Return Value:
  638. PTCHAR: returns the string value of the message stored in tszBuffer
  639. --*/
  640. PTCHAR ErrorMsg(IN ULONG ulError,
  641. IN OUT PTCHAR tszBuffer)
  642. {
  643. USHORT i, usLen;
  644. ULONG ulSuccess;
  645. __ASSERT(tszBuffer != NULL);
  646. ZeroMemory(tszBuffer, MAX_ERROR_LEN);
  647. ulSuccess = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
  648. NULL,
  649. ulError,
  650. 0,
  651. tszBuffer,
  652. MAX_ERROR_LEN,
  653. NULL);
  654. if (!ulSuccess)
  655. {
  656. //
  657. // Couldn't get a description of this error. Just return the number
  658. //
  659. _itot(ulError, tszBuffer, MAX_ERROR_LEN);
  660. }
  661. else
  662. {
  663. //
  664. // Strip out returns from tszBuffer string
  665. //
  666. for (usLen = _tcslen(tszBuffer), i = 0; i < usLen; i++)
  667. {
  668. if (tszBuffer[i] == RETURN_CHAR1 || tszBuffer[i] == RETURN_CHAR2)
  669. {
  670. tszBuffer[i] = SPACE;
  671. }
  672. }
  673. }
  674. return tszBuffer;
  675. } // ErrorMsg //