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.

745 lines
12 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. memory.c
  5. Abstract:
  6. This module provides all the memory management functions
  7. Author:
  8. Krishna Ganugapati (KrishnaG) 03-Feb-1994
  9. Revision History:
  10. --*/
  11. #include <nt.h>
  12. #include <ntrtl.h>
  13. #include <nturtl.h>
  14. #include <windows.h>
  15. #include <imagehlp.h>
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include "debug.h"
  19. #include "memory.h"
  20. #include "symhelp.h"
  21. //#define WORD_ALIGN_DOWN(addr) ((LPBYTE)((DWORD)addr &= ~1))
  22. #define DWORD_ALIGN_UP(size) ((size+3)&~3)
  23. DWORD
  24. MemSizeOri(
  25. LPVOID pMem
  26. );
  27. int
  28. UnicodeToAnsiString(
  29. PCWSTR pszUnicode,
  30. PSTR pszAnsi
  31. )
  32. /*++
  33. Routine Description:
  34. Convert a Unicode string to ansi. If the same string is passed in to the
  35. result string pszAnsi, it will use the same blob of memory.
  36. Arguments:
  37. pszUnicode - the unicode string to be converted to an ansi string
  38. pszAnsi - the result ansi string
  39. Return Value:
  40. --*/
  41. {
  42. PSTR pszTemp = NULL;
  43. int rc = 0;
  44. DWORD dwLength = 0;
  45. dwLength = wcslen(pszUnicode) + 1;
  46. //
  47. // Unfortunately, WideCharToMultiByte doesn't do conversion in place,
  48. // so allocate a temporary buffer, which we can then copy:
  49. //
  50. if(pszAnsi == (PSTR)pszUnicode) {
  51. pszTemp = (PSTR)MemAlloc_E(dwLength);
  52. if (!pszTemp) {
  53. return rc;
  54. }
  55. pszAnsi = pszTemp;
  56. }
  57. if(pszAnsi) {
  58. rc = WideCharToMultiByte( CP_ACP,
  59. 0,
  60. pszUnicode,
  61. dwLength,
  62. pszAnsi,
  63. dwLength,
  64. NULL,
  65. NULL );
  66. }
  67. //
  68. // If szTemp is non-null, we must copy the resulting string
  69. // so that it looks as if we did it in place:
  70. //
  71. if( pszTemp && ( rc > 0 ) ) {
  72. pszAnsi = (PSTR)pszUnicode;
  73. strcpy( pszAnsi, pszTemp );
  74. MemFree( pszTemp );
  75. }
  76. return rc;
  77. }
  78. PSTR
  79. AllocateAnsiString(
  80. PCWSTR pszUnicodeString
  81. )
  82. /*++
  83. Routine Description:
  84. Allocate an Ansi string with a unicode string as input
  85. Arguments:
  86. pszUnicodeString - the unicode string to be converted to an ansi string
  87. Return Value:
  88. --*/
  89. {
  90. PSTR pszAnsiString = NULL;
  91. int rc = 0;
  92. ASSERT(pszUnicodeString);
  93. pszAnsiString = (PSTR)MemAlloc(wcslen(pszUnicodeString)+1);
  94. if (pszAnsiString) {
  95. rc = UnicodeToAnsiString(
  96. pszUnicodeString,
  97. pszAnsiString
  98. );
  99. }
  100. if (rc>0) {
  101. return pszAnsiString;
  102. }
  103. if (pszAnsiString) {
  104. MemFree(pszAnsiString);
  105. }
  106. return NULL;
  107. }
  108. int
  109. AnsiToUnicodeString(
  110. PCSTR pszAnsi,
  111. PWSTR pszUnicode
  112. )
  113. /*++
  114. Routine Description:
  115. Convert an ansi string to unicode. An output string of enough size
  116. is expected to be passed in.
  117. Arguments:
  118. pszUnicode - the unicode string to be converted to an ansi string
  119. pszAnsi - the result ansi string
  120. Return Value:
  121. --*/
  122. {
  123. int rc;
  124. DWORD dwLength = strlen(pszAnsi);
  125. rc = MultiByteToWideChar(CP_ACP,
  126. MB_PRECOMPOSED,
  127. pszAnsi,
  128. dwLength + 1,
  129. pszUnicode,
  130. dwLength + 1);
  131. //
  132. // Ensure NULL termination.
  133. //
  134. pszUnicode[dwLength] = 0;
  135. return rc;
  136. }
  137. LPWSTR
  138. AllocateUnicodeString(
  139. PCSTR pszAnsiString
  140. )
  141. /*++
  142. Routine Description:
  143. Allocate a Unicode string with an ansi string as input
  144. Arguments:
  145. pszAnsiString - the ansi string to be converted to a unicode string
  146. Return Value:
  147. --*/
  148. {
  149. PWSTR pszUnicodeString = NULL;
  150. int rc;
  151. ASSERT(pszAnsiString);
  152. pszUnicodeString = (PWSTR)MemAlloc(strlen(pszAnsiString)*sizeof(WCHAR) +
  153. sizeof(WCHAR));
  154. if (pszUnicodeString) {
  155. rc = AnsiToUnicodeString(
  156. pszAnsiString,
  157. pszUnicodeString
  158. );
  159. }
  160. if (rc>0) {
  161. return pszUnicodeString;
  162. }
  163. if (pszUnicodeString) {
  164. MemFree(pszUnicodeString);
  165. }
  166. return NULL;
  167. }
  168. PSTR MemAllocStr_E(
  169. PSTR pszIn
  170. )
  171. {
  172. PSTR pszTemp;
  173. pszTemp = (PSTR)MemAlloc_E((strlen(pszIn)+1)*sizeof(char));
  174. if (pszTemp==NULL) {
  175. return NULL;
  176. }
  177. return strcpy(pszTemp, pszIn);
  178. }
  179. PWSTR MemAllocStrW_E(
  180. PWSTR pszIn
  181. )
  182. {
  183. PWSTR pszTemp;
  184. pszTemp = (PWSTR)MemAlloc_E((wcslen(pszIn)+1)*sizeof(WCHAR));
  185. if (pszTemp==NULL) {
  186. return NULL;
  187. }
  188. return wcscpy(pszTemp, pszIn);
  189. }
  190. LPVOID MemAlloc_E(
  191. DWORD dwBytes
  192. )
  193. {
  194. LPVOID pReturn = NULL;
  195. pReturn = MemAlloc(dwBytes);
  196. if (!pReturn) {
  197. RaiseException(LL_MEMORY_ERROR, 0, 0, NULL);
  198. }
  199. return pReturn;
  200. }
  201. LPVOID MemRealloc_E(
  202. LPVOID IpMem,
  203. DWORD dwBytes
  204. )
  205. {
  206. DWORD dwSize;
  207. LPVOID pReturn = NULL;
  208. dwSize = MemSizeOri(IpMem);
  209. pReturn = MemRealloc(IpMem,dwSize,dwBytes);
  210. if (!pReturn) {
  211. RaiseException(LL_MEMORY_ERROR, 0, 0, NULL);
  212. }
  213. return pReturn;
  214. }
  215. #if DBG
  216. DWORD dwMemoryLog = 1;
  217. #define MAXDEPTH 10
  218. typedef struct _MEMTAG {
  219. DWORD Tag ;
  220. DWORD Size ;
  221. PVOID pvBackTrace[MAXDEPTH+1];
  222. LPSTR pszSymbol[MAXDEPTH+1];
  223. DWORD uDepth;
  224. LIST_ENTRY List ;
  225. } MEMTAG, *PMEMTAG ;
  226. LIST_ENTRY MemList ;
  227. DWORD MemCount ;
  228. CRITICAL_SECTION MemCritSect ;
  229. /*++
  230. Routine Description:
  231. This function initializes the mem tracking code. Must be call
  232. during DLL load an ONLY during DLL load.
  233. Arguments:
  234. None
  235. Return Value:
  236. None.
  237. --*/
  238. VOID InitMem(
  239. VOID
  240. )
  241. {
  242. InitializeCriticalSection(&MemCritSect) ;
  243. InitializeListHead(&MemList) ;
  244. MemCount = 0 ;
  245. }
  246. /*++
  247. Routine Description:
  248. This function asserts that the mem list is empty on exit.
  249. Arguments:
  250. None
  251. Return Value:
  252. None.
  253. --*/
  254. VOID AssertMemLeaks(
  255. VOID
  256. )
  257. {
  258. ASSERT(IsListEmpty(&MemList)) ;
  259. }
  260. #endif
  261. LPVOID
  262. MemAlloc(
  263. DWORD cb
  264. )
  265. /*++
  266. Routine Description:
  267. This function will allocate local memory. It will possibly allocate extra
  268. memory and fill this with debugging information for the debugging version.
  269. Arguments:
  270. cb - The amount of memory to allocate
  271. Return Value:
  272. NON-NULL - A pointer to the allocated memory
  273. FALSE/NULL - The operation failed. Extended error status is available
  274. using GetLastError.
  275. --*/
  276. {
  277. #if DBG
  278. DWORD cbNew ;
  279. PMEMTAG pMem ;
  280. DWORD i = 0;
  281. ULONG ulHash;
  282. //
  283. // adjust size for our tag and one spare dword at end
  284. // and allocate the memory
  285. //
  286. cb = DWORD_ALIGN_UP(cb);
  287. cbNew = cb + ( sizeof(MEMTAG) + sizeof(DWORD) );
  288. pMem=(PMEMTAG)LocalAlloc(LPTR, cbNew);
  289. if (!pMem) {
  290. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  291. return 0;
  292. }
  293. //
  294. // fill in deadbeef at end and tag info.
  295. // and insert it into the MemList
  296. //
  297. *(LPDWORD)((LPBYTE)pMem+cbNew-sizeof(DWORD)) = 0xdeadbeef;
  298. pMem->Tag = 0xB00FB00F ;
  299. pMem->Size = cb ;
  300. //
  301. // Capture a backtrace at this spot for debugging.
  302. //
  303. #if (defined(i386) && !defined(WIN95))
  304. pMem->uDepth = RtlCaptureStackBackTrace(
  305. 0,
  306. MAXDEPTH,
  307. pMem->pvBackTrace,
  308. &ulHash
  309. );
  310. #else
  311. pMem->uDepth = 0;
  312. #endif
  313. EnterCriticalSection(&MemCritSect) ;
  314. InsertHeadList(&MemList, &pMem->List) ;
  315. MemCount++ ;
  316. LeaveCriticalSection(&MemCritSect) ;
  317. //
  318. // skip past the mem tag
  319. //
  320. pMem++ ;
  321. return (LPVOID)(pMem);
  322. #else
  323. return(LocalAlloc(LPTR, cb));
  324. #endif
  325. }
  326. BOOL
  327. MemFree(
  328. LPVOID pMem
  329. )
  330. {
  331. #if DBG
  332. DWORD cb;
  333. DWORD cbNew = 0;
  334. PMEMTAG pNewMem ;
  335. LPDWORD pRetAddr;
  336. DWORD i = 0;
  337. pNewMem = (PMEMTAG)pMem;
  338. pNewMem -- ;
  339. cb = pNewMem->Size;
  340. cbNew = cb + sizeof(DWORD) + sizeof(MEMTAG);
  341. //
  342. // check the trailing deadbeef and remove from list
  343. //
  344. if (*(LPDWORD)(((LPBYTE)pNewMem) + cbNew - sizeof(DWORD)) != 0xdeadbeef) {
  345. ERR(("Freeing memory not allocated by MemAlloc"));
  346. return FALSE;
  347. }
  348. EnterCriticalSection(&MemCritSect) ;
  349. RemoveEntryList(&pNewMem->List) ;
  350. MemCount-- ;
  351. LeaveCriticalSection(&MemCritSect) ;
  352. for (i = 0; i < pNewMem->uDepth; i++) {
  353. if (pNewMem->pszSymbol[i]) {
  354. LocalFree(pNewMem->pszSymbol[i]);
  355. }
  356. }
  357. //
  358. // Whack freed memory with known pattern
  359. //
  360. memset(pMem, 0x65, cb);
  361. return(LocalFree((LPVOID)pNewMem) == NULL);
  362. #else
  363. return(LocalFree(pMem) == NULL);
  364. #endif
  365. }
  366. DWORD
  367. MemSize(
  368. LPVOID pMem
  369. )
  370. {
  371. #if DBG
  372. DWORD cb;
  373. DWORD cbNew = 0;
  374. PMEMTAG pNewMem ;
  375. LPDWORD pRetAddr;
  376. DWORD i = 0;
  377. pNewMem = (PMEMTAG)pMem;
  378. pNewMem -- ;
  379. cb = pNewMem->Size;
  380. cbNew = cb + sizeof(DWORD) + sizeof(MEMTAG);
  381. if (*(LPDWORD)(((LPBYTE)pNewMem) + cbNew - sizeof(DWORD)) != 0xdeadbeef) {
  382. ERR(("Getting size not allocated by MemAlloc!"));
  383. return 0;
  384. }
  385. return((DWORD)LocalSize((LPVOID)pNewMem));
  386. #else
  387. return((DWORD)LocalSize(pMem));
  388. #endif
  389. }
  390. DWORD
  391. MemSizeOri(
  392. LPVOID pMem
  393. )
  394. {
  395. #if DBG
  396. DWORD cb;
  397. PMEMTAG pNewMem ;
  398. pNewMem = (PMEMTAG)pMem;
  399. pNewMem -- ;
  400. cb = pNewMem->Size;
  401. return((DWORD)cb);
  402. #else
  403. return((DWORD)LocalSize(pMem));
  404. #endif
  405. }
  406. LPVOID
  407. MemRealloc(
  408. LPVOID pOldMem,
  409. DWORD cbOld,
  410. DWORD cbNew
  411. )
  412. {
  413. LPVOID pNewMem;
  414. pNewMem=MemAlloc(cbNew);
  415. if (pOldMem && pNewMem) {
  416. memcpy(pNewMem, pOldMem, min(cbNew, cbOld));
  417. MemFree(pOldMem);
  418. }
  419. return pNewMem;
  420. }
  421. LPSTR
  422. MemAllocStr(
  423. LPSTR pStr
  424. )
  425. /*++
  426. Routine Description:
  427. This function will allocate enough local memory to store the specified
  428. string, and copy that string to the allocated memory
  429. Arguments:
  430. pStr - Pointer to the string that needs to be allocated and stored
  431. Return Value:
  432. NON-NULL - A pointer to the allocated memory containing the string
  433. FALSE/NULL - The operation failed. Extended error status is available
  434. using GetLastError.
  435. --*/
  436. {
  437. LPSTR pMem;
  438. if (!pStr)
  439. return 0;
  440. if (pMem = (LPSTR)MemAlloc( strlen(pStr)*sizeof(CHAR) + sizeof(CHAR) ))
  441. strcpy(pMem, pStr);
  442. return pMem;
  443. }
  444. PWSTR
  445. MemAllocStrW(
  446. PWSTR pStr
  447. )
  448. /*++
  449. Routine Description:
  450. This function will allocate enough local memory to store the specified
  451. string, and copy that string to the allocated memory
  452. Arguments:
  453. pStr - Pointer to the string that needs to be allocated and stored
  454. Return Value:
  455. NON-NULL - A pointer to the allocated memory containing the string
  456. FALSE/NULL - The operation failed. Extended error status is available
  457. using GetLastError.
  458. --*/
  459. {
  460. PWSTR pMem;
  461. if (!pStr)
  462. return 0;
  463. if (pMem = (PWSTR)MemAlloc( wcslen(pStr)*sizeof(WCHAR) + sizeof(WCHAR) ))
  464. wcscpy(pMem, pStr);
  465. return pMem;
  466. }
  467. BOOL
  468. MemReallocStr(
  469. LPSTR *ppStr,
  470. LPSTR pStr
  471. )
  472. {
  473. if (ppStr && (*ppStr)) {
  474. MemFree(*ppStr);
  475. *ppStr=MemAllocStr(pStr);
  476. return TRUE;
  477. }
  478. else {
  479. return FALSE;
  480. }
  481. }
  482. #if DBG
  483. VOID
  484. DumpMemoryTracker(
  485. VOID
  486. )
  487. {
  488. #ifndef _WIN64
  489. LIST_ENTRY* pEntry;
  490. MEMTAG* pMem;
  491. BYTE* pTemp;
  492. DWORD i = 0;
  493. CHAR szSymbolPath[MAX_PATH+1];
  494. DWORD dwCount = 0;
  495. pEntry = MemList.Flink;
  496. if (!dwMemoryLog) {
  497. return;
  498. }
  499. if ( pEntry == &MemList ) {
  500. OutputDebugStringA( "No Memory leaks found\n" );
  501. }
  502. while( pEntry != &MemList )
  503. {
  504. CHAR szLeak[1024];
  505. pTemp = (BYTE*)pEntry;
  506. pTemp = pTemp - sizeof(DWORD) - sizeof(DWORD)
  507. - sizeof(DWORD) -
  508. (sizeof(CHAR*) + sizeof(LPVOID))*( MAXDEPTH +1);
  509. pMem = (MEMTAG*)pTemp;
  510. sprintf(
  511. szLeak,
  512. "[oleds] Memory leak!!! Addresss = %.8x Size = %ld \n",
  513. pMem + 1,
  514. pMem->Size
  515. );
  516. OutputDebugStringA( szLeak );
  517. for (i = 0; i < pMem->uDepth; i++) {
  518. dwCount = TranslateAddress(
  519. (ULONG)pMem->pvBackTrace[ i ],
  520. szSymbolPath,
  521. MAX_PATH
  522. );
  523. szSymbolPath[dwCount] = '\0';
  524. sprintf(szLeak, "%s\n",szSymbolPath);
  525. OutputDebugStringA( szLeak);
  526. }
  527. pEntry = pEntry->Flink;
  528. }
  529. #endif
  530. }
  531. #endif