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.

358 lines
8.5 KiB

  1. /*****************************************************************************\
  2. * MODULE: mem.cxx
  3. *
  4. * Memory management routines. These routines provide head/tail checking
  5. * to verify memory corruption problems.
  6. *
  7. *
  8. * Copyright (C) 1996-1998 Microsoft Corporation.
  9. * Copyright (C) 1996-1998 Hewlett Packard Company.
  10. *
  11. * History:
  12. * 07-Oct-1996 HWP-Guys Initiated port from win95 to winNT
  13. *
  14. \*****************************************************************************/
  15. #include <windows.h>
  16. #include "libpriv.h"
  17. /*********************************************************** local routine ***\
  18. * mem_StrSize
  19. *
  20. * Returns size of string.
  21. *
  22. \*****************************************************************************/
  23. _inline DWORD mem_StrSize(
  24. PCTSTR pszStr)
  25. {
  26. return (pszStr ? ((lstrlen(pszStr) + 1) * sizeof(TCHAR)) : 0);
  27. }
  28. /*********************************************************** local routine ***\
  29. * mem_HeadPtr
  30. *
  31. * Returns the pointer to the head-block. This needs to decrement enough
  32. * to account for the extra information stored at the head.
  33. *
  34. \*****************************************************************************/
  35. _inline PMEMHEAD mem_HeadPtr(
  36. PVOID pvMem)
  37. {
  38. return (PMEMHEAD)(pvMem ? (((PBYTE)pvMem) - MEM_HEADSIZE) : NULL);
  39. }
  40. /*********************************************************** local routine ***\
  41. * mem_TailPtr
  42. *
  43. * Returns the pointer to the tail-block. This requires the aligned-size
  44. * to retrieve the offset.
  45. *
  46. \*****************************************************************************/
  47. _inline PMEMTAIL mem_TailPtr(
  48. PMEMHEAD pmh,
  49. DWORD cbAlign)
  50. {
  51. return (PMEMTAIL)((PBYTE)pmh + cbAlign - MEM_TAILSIZE);
  52. }
  53. #ifdef DEBUG
  54. PMEMHEAD g_pmHead = NULL;
  55. /*********************************************************** local routine ***\
  56. * mem_InsPtr
  57. *
  58. * Inserts the pointer into our list for tracking allocations.
  59. *
  60. \*****************************************************************************/
  61. _inline VOID mem_InsPtr(
  62. PMEMHEAD pmHead)
  63. {
  64. if (g_pmHead) {
  65. g_pmHead->pmPrev = pmHead;
  66. pmHead->pmNext = g_pmHead;
  67. } else {
  68. pmHead->pmNext = NULL;
  69. }
  70. g_pmHead = pmHead;
  71. }
  72. /*********************************************************** local routine ***\
  73. * mem_DelPtr
  74. *
  75. * Removes the pointer from our list of tracked allocations.
  76. |
  77. \*****************************************************************************/
  78. _inline VOID mem_DelPtr(
  79. PMEMHEAD pmHead)
  80. {
  81. PMEMHEAD pmPtr;
  82. if (pmHead->pmNext) {
  83. pmPtr = pmHead->pmNext;
  84. pmPtr->pmPrev = pmHead->pmPrev;
  85. }
  86. if (pmHead->pmPrev) {
  87. pmPtr = pmHead->pmPrev;
  88. pmPtr->pmNext = pmHead->pmNext;
  89. } else {
  90. g_pmHead = pmHead->pmNext;
  91. }
  92. }
  93. /*****************************************************************************\
  94. * _mem_validate (Local Routine)
  95. *
  96. * Checks memory blocks allocated by memAlloc. These blocks contain
  97. * debugging information that helps to check for pointer overruns and
  98. * underruns.
  99. *
  100. * Returns a pointer to the memory header. Otherwise, we return NULL.
  101. *
  102. \*****************************************************************************/
  103. PMEMHEAD _mem_validate(
  104. PVOID pvMem,
  105. UINT cbSize)
  106. {
  107. DWORD cbAlign;
  108. PMEMHEAD pmHead;
  109. PMEMTAIL pmTail;
  110. PMEMHEAD pmRet = NULL;
  111. // Retrieve the head-pointer.
  112. //
  113. if (pmHead = mem_HeadPtr(pvMem)) {
  114. // Calculate the "real" size of our allocated block and round it
  115. // up to an even number of DWORD blocks.
  116. //
  117. cbAlign = memAlignSize(cbSize + MEM_SIZE);
  118. // Get the tail location.
  119. //
  120. pmTail = mem_TailPtr(pmHead, cbAlign);
  121. // Compare the values that memAlloc stored at the beginning
  122. // and end of the block
  123. //
  124. if ((pmHead->cbSize == cbSize) && (pmTail->dwSignature == DEADBEEF))
  125. pmRet = pmHead;
  126. // Assert if errors.
  127. //
  128. DBG_ASSERT((pmHead->cbSize == cbSize), (TEXT("Err : _mem_validate: Bad Size at %08lX"), pvMem));
  129. DBG_ASSERT((pmTail->dwSignature == DEADBEEF), (TEXT("Err : _mem_validate: Block Corruption at %08lX"), pvMem));
  130. } else {
  131. DBG_MSG(DBG_LEV_ERROR, (TEXT("Err : _mem_validate: Bad Pointer")));
  132. }
  133. return pmRet;
  134. }
  135. #else
  136. /*********************************************************** local routine ***\
  137. * Non-Debug Mappings.
  138. *
  139. * On non-debug builds, we will just return the most efficient values.
  140. *
  141. \*****************************************************************************/
  142. #define mem_InsPtr(pmHead) {}
  143. #define mem_DelPtr(pmHead) {}
  144. #define _mem_validate(pvMem, cbSize) mem_HeadPtr(pvMem)
  145. #endif
  146. /*****************************************************************************\
  147. * memAlloc
  148. *
  149. *
  150. \*****************************************************************************/
  151. PVOID memAlloc(
  152. UINT cbSize)
  153. {
  154. PMEMHEAD pmHead;
  155. PMEMTAIL pmTail;
  156. DWORD cbAlign;
  157. // The size of this memory-block will include header-information. So,
  158. // we will add the header-size and align our memory on DWORD boundries.
  159. //
  160. cbAlign = memAlignSize(cbSize + MEM_SIZE);
  161. // Attempt to allocate the memory. Proceed to setup
  162. // the memory block.
  163. //
  164. if (pmHead = (PMEMHEAD)GlobalAlloc(GPTR, cbAlign)) {
  165. pmTail = mem_TailPtr(pmHead, cbAlign);
  166. // Zero the memory-block so that we're dealing with
  167. // a clean contiguous array.
  168. //
  169. ZeroMemory((PVOID)pmHead, cbAlign);
  170. // Set up header/tail-information. This contains the requested
  171. // size of the memory-block. Increment the block so we return
  172. // the next available memory for the caller to use.
  173. //
  174. pmTail->dwSignature = DEADBEEF;
  175. pmHead->dwTag = 0;
  176. pmHead->cbSize = cbSize;
  177. pmHead->pmPrev = NULL;
  178. pmHead->pmNext = NULL;
  179. mem_InsPtr(pmHead);
  180. } else {
  181. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  182. }
  183. return (pmHead ? pmHead->pvMem : NULL);
  184. }
  185. /*****************************************************************************\
  186. * memFree
  187. *
  188. *
  189. \*****************************************************************************/
  190. BOOL memFree(
  191. PVOID pvMem,
  192. UINT cbSize)
  193. {
  194. PMEMHEAD pmHead;
  195. BOOL bRet = FALSE;
  196. // Try to at least make sure it's our memory and that no pointers have
  197. // gone astray in it.
  198. //
  199. if (pmHead = _mem_validate(pvMem, cbSize)) {
  200. mem_DelPtr(pmHead);
  201. bRet = (GlobalFree((PVOID)pmHead) == NULL);
  202. }
  203. return bRet;
  204. }
  205. /*****************************************************************************\
  206. * memCopy
  207. *
  208. * Copies a block of memory into a Win32 format buffer -- a structure at the
  209. * front of the buffer and strings packed into the end.
  210. *
  211. * On entry, *buf should point to the last available byte in the buffer.
  212. *
  213. \*****************************************************************************/
  214. VOID memCopy(
  215. PSTR *ppDst,
  216. PSTR pSrc,
  217. UINT cbSize,
  218. PSTR *ppBuf)
  219. {
  220. if (pSrc != NULL) {
  221. // Place bytes at end of buffer.
  222. //
  223. (*ppBuf) -= cbSize + 1;
  224. memcpy(*ppBuf, pSrc, cbSize);
  225. // Place buffer address in structure and save pointer to new
  226. // last available byte.
  227. //
  228. *ppDst = *ppBuf;
  229. (*ppBuf)--;
  230. } else {
  231. *ppDst = NULL;
  232. }
  233. }
  234. /*****************************************************************************\
  235. * memGetSize
  236. *
  237. * Returns the size of a block of memory that was allocated with memAlloc().
  238. *
  239. \*****************************************************************************/
  240. UINT memGetSize(
  241. PVOID pvMem)
  242. {
  243. PMEMHEAD pmHead;
  244. return ((pmHead = mem_HeadPtr(pvMem)) ? pmHead->cbSize : 0);
  245. }
  246. /*****************************************************************************\
  247. * memAllocStr
  248. *
  249. * Allocates local memory to store the specified string. This takes in a
  250. * (lpszStr) which is copied to the new memory.
  251. *
  252. \*****************************************************************************/
  253. PTSTR memAllocStr(
  254. LPCTSTR lpszStr)
  255. {
  256. PTSTR pMem;
  257. if (lpszStr == NULL)
  258. return NULL;
  259. if (pMem = (PTSTR)memAlloc(mem_StrSize(lpszStr))) {
  260. if (!lstrcpy((LPTSTR)pMem, lpszStr)) {
  261. memFreeStr (pMem);
  262. pMem = NULL;
  263. }
  264. }
  265. return pMem;
  266. }
  267. /*****************************************************************************\
  268. * memFreeStr
  269. *
  270. * Frees the memory allocated by memAllocStr.
  271. *
  272. \*****************************************************************************/
  273. BOOL memFreeStr(
  274. PTSTR pszStr)
  275. {
  276. return memFree(pszStr, memGetSize(pszStr));
  277. }