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.

524 lines
13 KiB

  1. //
  2. // mem.cpp
  3. //
  4. #include "private.h"
  5. #include "ciccs.h"
  6. #include "mem.h"
  7. #ifdef USECRT
  8. #include <malloc.h>
  9. #endif
  10. #ifndef DEBUG
  11. ///////////////////////////////////////////////////////////////////////////////
  12. //
  13. // RETAIL memory functions.
  14. //
  15. ///////////////////////////////////////////////////////////////////////////////
  16. extern "C" void *cicMemAlloc(UINT uCount)
  17. {
  18. #ifdef USECRT
  19. return malloc(uCount);
  20. #else
  21. return LocalAlloc(LMEM_FIXED, uCount);
  22. #endif
  23. }
  24. extern "C" void *cicMemAllocClear(UINT uCount)
  25. {
  26. #ifdef USECRT
  27. return calloc(uCount, 1);
  28. #else
  29. return LocalAlloc(LPTR, uCount);
  30. #endif
  31. }
  32. extern "C" void cicMemFree(void *pv)
  33. {
  34. if (pv == NULL)
  35. return;
  36. #ifdef USECRT
  37. free(pv);
  38. #else
  39. HLOCAL hLocal;
  40. hLocal = LocalFree(pv);
  41. Assert(hLocal == NULL);
  42. #endif
  43. }
  44. extern "C" void *cicMemReAlloc(void *pv, UINT uCount)
  45. {
  46. #ifdef USECRT
  47. return realloc(pv, uCount);
  48. #else
  49. return LocalReAlloc((HLOCAL)pv, uCount, LMEM_MOVEABLE | LMEM_ZEROINIT);
  50. #endif
  51. }
  52. extern "C" UINT cicMemSize(void *pv)
  53. {
  54. #ifdef USECRT
  55. return _msize(pv);
  56. #else
  57. return (UINT)LocalSize((HLOCAL)pv);
  58. #endif
  59. }
  60. #else // DEBUG
  61. ///////////////////////////////////////////////////////////////////////////////
  62. //
  63. // DEBUG memory functions.
  64. //
  65. ///////////////////////////////////////////////////////////////////////////////
  66. #define MEM_SUSPICIOUSLY_LARGE_ALLOC 0x1000000 // 16MB
  67. // All the debug state goes here.
  68. // Be thread safe: make sure you hold s_Dbg_cs before touching/reading anything!
  69. DBG_MEMSTATS s_Dbg_MemStats = { 0 };
  70. DBG_MEM_COUNTER *s_rgCounters = NULL;
  71. static CCicCriticalSectionStatic s_Dbg_cs;
  72. static void *s_Dbg_pvBreak = (void *)-1; // set this to something to break on at runtime in MemAlloc/MemAllocClear/MemReAlloc
  73. extern "C" TCHAR *Dbg_CopyString(const TCHAR *pszSrc)
  74. {
  75. TCHAR *pszCpy;
  76. int c;
  77. c = lstrlen(pszSrc)+1;
  78. pszCpy = (TCHAR *)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, c*sizeof(TCHAR));
  79. if (pszCpy != NULL)
  80. {
  81. memcpy(pszCpy, pszSrc, c*sizeof(TCHAR));
  82. }
  83. return pszCpy;
  84. }
  85. //+---------------------------------------------------------------------------
  86. //
  87. // Dbg_MemInit
  88. //
  89. //----------------------------------------------------------------------------
  90. extern "C" BOOL Dbg_MemInit(const TCHAR *pszName, DBG_MEM_COUNTER *rgCounters)
  91. {
  92. if (!s_Dbg_cs.Init())
  93. return FALSE;
  94. s_Dbg_MemStats.pszName = Dbg_CopyString(pszName);
  95. s_rgCounters = rgCounters;
  96. return TRUE;
  97. }
  98. //+---------------------------------------------------------------------------
  99. //
  100. // Dbg_MemUninit
  101. //
  102. //----------------------------------------------------------------------------
  103. extern "C" BOOL Dbg_MemUninit()
  104. {
  105. DBG_MEMALLOC *pdma;
  106. DBG_MEMALLOC *pdmaTmp;
  107. TCHAR achID[64];
  108. BOOL bMemLeak = FALSE;
  109. // dump stats
  110. Dbg_MemDumpStats();
  111. // everything free?
  112. pdma = s_Dbg_MemStats.pMemAllocList;
  113. if (pdma != NULL ||
  114. s_Dbg_MemStats.uTotalAlloc != s_Dbg_MemStats.uTotalFree) // second test necessary to catch size 0 objects
  115. {
  116. TraceMsg(TF_MEMORY_LEAK, "%s: Memory leak detected! %x total bytes leaked!",
  117. s_Dbg_MemStats.pszName, s_Dbg_MemStats.uTotalAlloc - s_Dbg_MemStats.uTotalFree);
  118. bMemLeak = TRUE;
  119. }
  120. while (pdma != NULL)
  121. {
  122. if (pdma->dwID == DWORD(-1))
  123. {
  124. achID[0] = '\0';
  125. }
  126. else
  127. {
  128. wsprintf(achID, " (ID = 0x%x)", pdma->dwID);
  129. }
  130. TraceMsg(TF_MEMORY_LEAK, " Address: %8.8lx Size: %8.8lx TID: %8.8lx %s%s%s line %i %s",
  131. pdma->pvAlloc, pdma->uCount, pdma->dwThreadID, pdma->pszName ? pdma->pszName : "", pdma->pszName ? " -- " : "", pdma->pszFile, pdma->iLine, achID);
  132. // free the DBG_MEMALLOC
  133. pdmaTmp = pdma->next;
  134. LocalFree(pdma->pszName);
  135. LocalFree(pdma);
  136. pdma = pdmaTmp;
  137. }
  138. // Assert after tracing.
  139. if (bMemLeak)
  140. AssertPrivate(0);
  141. s_Dbg_MemStats.pMemAllocList = NULL; // in case someone wants to call Dbg_MemInit again
  142. s_Dbg_cs.Delete();
  143. LocalFree(s_Dbg_MemStats.pszName);
  144. return TRUE;
  145. }
  146. //+---------------------------------------------------------------------------
  147. //
  148. // Dbg_MemDumpStats
  149. //
  150. //----------------------------------------------------------------------------
  151. extern "C" void Dbg_MemDumpStats()
  152. {
  153. EnterCriticalSection(s_Dbg_cs);
  154. TraceMsg(TF_MEMORY_LEAK, "Memory: %s allocated %x bytes, freed %x bytes.",
  155. s_Dbg_MemStats.pszName, s_Dbg_MemStats.uTotalAlloc, s_Dbg_MemStats.uTotalFree);
  156. if (s_Dbg_MemStats.uTotalAlloc != s_Dbg_MemStats.uTotalFree)
  157. {
  158. TraceMsg(TF_MEMORY_LEAK, "Memory: %s %x bytes currently allocated.",
  159. s_Dbg_MemStats.pszName, s_Dbg_MemStats.uTotalAlloc - s_Dbg_MemStats.uTotalFree);
  160. }
  161. TraceMsg(TF_MEMORY_LEAK, "Memory: %x MemAlloc", s_Dbg_MemStats.uTotalMemAllocCalls);
  162. TraceMsg(TF_MEMORY_LEAK, "Memory: %x MemAllocClear", s_Dbg_MemStats.uTotalMemAllocClearCalls);
  163. TraceMsg(TF_MEMORY_LEAK, "Memory: %x MemReAlloc", s_Dbg_MemStats.uTotalMemReAllocCalls);
  164. TraceMsg(TF_MEMORY_LEAK, "Memory: %x MemFree", s_Dbg_MemStats.uTotalMemFreeCalls);
  165. LeaveCriticalSection(s_Dbg_cs);
  166. }
  167. //+---------------------------------------------------------------------------
  168. //
  169. // Dbg_MemAlloc
  170. //
  171. //----------------------------------------------------------------------------
  172. extern "C" void *Dbg_MemAlloc(UINT uCount, const TCHAR *pszFile, int iLine)
  173. {
  174. void *pv;
  175. DBG_MEMALLOC *pdma;
  176. InterlockedIncrement(&s_Dbg_MemStats.uTotalMemAllocCalls);
  177. if (uCount == 0)
  178. {
  179. // TraceMsg(TF_MEMORY_LEAK, "Zero size memory allocation! %s line %i", pszFile, iLine);
  180. //Assert(0);
  181. }
  182. if (uCount >= MEM_SUSPICIOUSLY_LARGE_ALLOC)
  183. {
  184. TraceMsg(TF_MEMORY_LEAK, "Suspiciously large memory allocation (0x%x bytes)! %s line %i", uCount, pszFile, iLine);
  185. Assert(0);
  186. }
  187. pv = LocalAlloc(LMEM_FIXED, uCount);
  188. if (pv == NULL)
  189. return NULL;
  190. //
  191. // record this allocation
  192. //
  193. if ((pdma = (DBG_MEMALLOC *)LocalAlloc(LPTR, sizeof(DBG_MEMALLOC))) == NULL)
  194. {
  195. // this is a transaction -- fail if we can't allocate the debug info
  196. LocalFree(pv);
  197. return NULL;
  198. }
  199. pdma->pvAlloc = pv;
  200. pdma->uCount = uCount;
  201. pdma->pszFile = pszFile;
  202. pdma->iLine = iLine;
  203. pdma->dwThreadID = GetCurrentThreadId();
  204. pdma->dwID = (DWORD)-1;
  205. EnterCriticalSection(s_Dbg_cs);
  206. pdma->next = s_Dbg_MemStats.pMemAllocList;
  207. s_Dbg_MemStats.pMemAllocList = pdma;
  208. //
  209. // update global stats
  210. //
  211. s_Dbg_MemStats.uTotalAlloc += uCount;
  212. LeaveCriticalSection(s_Dbg_cs);
  213. if (pv == s_Dbg_pvBreak)
  214. Assert(0);
  215. return pv;
  216. }
  217. //+---------------------------------------------------------------------------
  218. //
  219. // Dbg_MemAllocClear
  220. //
  221. //----------------------------------------------------------------------------
  222. extern "C" void *Dbg_MemAllocClear(UINT uCount, const TCHAR *pszFile, int iLine)
  223. {
  224. void *pv;
  225. InterlockedIncrement(&s_Dbg_MemStats.uTotalMemAllocClearCalls);
  226. InterlockedDecrement(&s_Dbg_MemStats.uTotalMemAllocCalls); // compensate for wrapping
  227. pv = Dbg_MemAlloc(uCount, pszFile, iLine);
  228. if (pv != NULL)
  229. {
  230. // clear out the mem
  231. memset(pv, 0, uCount);
  232. }
  233. return pv;
  234. }
  235. //+---------------------------------------------------------------------------
  236. //
  237. // Dbg_MemFree
  238. //
  239. //----------------------------------------------------------------------------
  240. extern "C" void Dbg_MemFree(void *pv)
  241. {
  242. HLOCAL hLocal;
  243. DBG_MEMALLOC *pdma;
  244. DBG_MEMALLOC **ppdma;
  245. InterlockedIncrement(&s_Dbg_MemStats.uTotalMemFreeCalls);
  246. if (pv != NULL) // MemFree(NULL) is legal
  247. {
  248. EnterCriticalSection(s_Dbg_cs);
  249. // was this guy allocated?
  250. ppdma = &s_Dbg_MemStats.pMemAllocList;
  251. if (ppdma)
  252. {
  253. while ((pdma = *ppdma) && pdma->pvAlloc != pv)
  254. {
  255. ppdma = &pdma->next;
  256. }
  257. if (pdma != NULL)
  258. {
  259. // found it, update and delete
  260. s_Dbg_MemStats.uTotalFree += pdma->uCount;
  261. *ppdma = pdma->next;
  262. LocalFree(pdma->pszName);
  263. LocalFree(pdma);
  264. }
  265. else
  266. {
  267. TraceMsg(TF_MEMORY_LEAK, "%s: MemFree'ing a bogus pointer %x!", s_Dbg_MemStats.pszName, pv);
  268. // Assert(0); // freeing bogus pointer
  269. }
  270. }
  271. else
  272. {
  273. Assert(0); // freeing bogus pointer
  274. }
  275. LeaveCriticalSection(s_Dbg_cs);
  276. hLocal = LocalFree(pv); // to match retail behavior, we don't call LocalFree for pv == NULL
  277. Assert(hLocal == NULL);
  278. }
  279. }
  280. //+---------------------------------------------------------------------------
  281. //
  282. // Dbg_MemReAlloc
  283. //
  284. //----------------------------------------------------------------------------
  285. extern "C" void *Dbg_MemReAlloc(void *pv, UINT uCount, const TCHAR *pszFile, int iLine)
  286. {
  287. DBG_MEMALLOC *pdma;
  288. InterlockedIncrement(&s_Dbg_MemStats.uTotalMemReAllocCalls);
  289. EnterCriticalSection(s_Dbg_cs);
  290. // was this guy allocated?
  291. for (pdma = s_Dbg_MemStats.pMemAllocList; pdma != NULL && pdma->pvAlloc != pv; pdma = pdma->next)
  292. ;
  293. if (pdma == NULL)
  294. {
  295. // can't find this guy!
  296. TraceMsg(TF_MEMORY_LEAK, "%s: MemReAlloc'ing a bogus pointer %x!", s_Dbg_MemStats.pszName, pv);
  297. Assert(0); // bogus pointer
  298. pv = NULL;
  299. }
  300. else
  301. {
  302. // we blow away the original pv here, but we're not free'ing it so that's ok
  303. #pragma prefast(suppress:308)
  304. pv = LocalReAlloc((HLOCAL)pv, uCount, LMEM_MOVEABLE | LMEM_ZEROINIT);
  305. }
  306. if (pv != NULL)
  307. {
  308. // update the stats
  309. pdma->pvAlloc = pv;
  310. s_Dbg_MemStats.uTotalAlloc += (uCount - pdma->uCount);
  311. pdma->uCount = uCount;
  312. pdma->pszFile = pszFile;
  313. pdma->iLine = iLine;
  314. }
  315. LeaveCriticalSection(s_Dbg_cs);
  316. if (pv == s_Dbg_pvBreak)
  317. Assert(0);
  318. return pv;
  319. }
  320. //+---------------------------------------------------------------------------
  321. //
  322. // Dbg_MemSize
  323. //
  324. //----------------------------------------------------------------------------
  325. extern "C" UINT Dbg_MemSize(void *pv)
  326. {
  327. UINT uiSize;
  328. EnterCriticalSection(s_Dbg_cs);
  329. uiSize = (UINT)LocalSize((HLOCAL)pv);
  330. LeaveCriticalSection(s_Dbg_cs);
  331. return uiSize;
  332. }
  333. //+---------------------------------------------------------------------------
  334. //
  335. // Dbg_MemSetName
  336. //
  337. //----------------------------------------------------------------------------
  338. extern "C" BOOL Dbg_MemSetName(void *pv, const TCHAR *pszName)
  339. {
  340. return Dbg_MemSetNameIDCounter(pv, pszName, (DWORD)-1, (ULONG)-1);
  341. }
  342. //+---------------------------------------------------------------------------
  343. //
  344. // Dbg_MemSetNameID
  345. //
  346. //----------------------------------------------------------------------------
  347. extern "C" BOOL Dbg_MemSetNameID(void *pv, const TCHAR *pszName, DWORD dwID)
  348. {
  349. return Dbg_MemSetNameIDCounter(pv, pszName, dwID, (ULONG)-1);
  350. }
  351. //+---------------------------------------------------------------------------
  352. //
  353. // Dbg_MemSetNameID
  354. //
  355. //----------------------------------------------------------------------------
  356. extern "C" BOOL Dbg_MemSetNameIDCounter(void *pv, const TCHAR *pszName, DWORD dwID, ULONG iCounter)
  357. {
  358. DBG_MEMALLOC *pdma;
  359. BOOL f = FALSE;
  360. EnterCriticalSection(s_Dbg_cs);
  361. for (pdma = s_Dbg_MemStats.pMemAllocList; pdma != NULL && pdma->pvAlloc != pv; pdma = pdma->next)
  362. ;
  363. if (pdma != NULL)
  364. {
  365. if (s_rgCounters != NULL && iCounter != (ULONG)-1)
  366. {
  367. s_rgCounters[iCounter].uCount++;
  368. }
  369. LocalFree(pdma->pszName);
  370. pdma->pszName = Dbg_CopyString(pszName);
  371. pdma->dwID = dwID;
  372. f = TRUE;
  373. }
  374. LeaveCriticalSection(s_Dbg_cs);
  375. return f;
  376. }
  377. //+---------------------------------------------------------------------------
  378. //
  379. // Dbg_MemGetName
  380. //
  381. // Pass in ccBuffer == 0 to get size of string only.
  382. //
  383. //----------------------------------------------------------------------------
  384. extern "C" int Dbg_MemGetName(void *pv, TCHAR *pch, int ccBuffer)
  385. {
  386. DBG_MEMALLOC *pdma;
  387. int cc;
  388. if (ccBuffer <= 0)
  389. return 0;
  390. EnterCriticalSection(s_Dbg_cs);
  391. for (pdma = s_Dbg_MemStats.pMemAllocList; pdma != NULL && pdma->pvAlloc != pv; pdma = pdma->next)
  392. ;
  393. if (pdma != NULL)
  394. {
  395. cc = lstrlen(pdma->pszName);
  396. cc = min(cc, ccBuffer-1);
  397. memcpy(pch, pdma->pszName, cc*sizeof(TCHAR));
  398. }
  399. else
  400. {
  401. cc = 0;
  402. }
  403. pch[cc] = '\0';
  404. LeaveCriticalSection(s_Dbg_cs);
  405. return cc;
  406. }
  407. #endif // DEBUG