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.

566 lines
14 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. RegLeak.h
  5. Abstract:
  6. This module contains helper functions for tracking
  7. n win32 registry leaks
  8. Author:
  9. Adam Edwards (adamed) 06-May-1998
  10. --*/
  11. #ifdef LOCAL
  12. #ifdef LEAK_TRACK
  13. #include "ntverp.h"
  14. #include <rpc.h>
  15. #include "regrpc.h"
  16. #include "localreg.h"
  17. #include "regclass.h"
  18. #include "stkwalk.h"
  19. #include "regleak.h"
  20. #include <malloc.h>
  21. RegLeakTable gLeakTable;
  22. RegLeakTraceInfo g_RegLeakTraceInfo;
  23. void TrackObjectDataPrint(TrackObjectData* pKeyData)
  24. {
  25. NTSTATUS Status;
  26. SKeySemantics keyinfo;
  27. UNICODE_STRING EmptyString = {0, 0, 0};
  28. BYTE rgNameBuf[REG_MAX_CLASSKEY_LEN + REG_CHAR_SIZE + sizeof(KEY_NAME_INFORMATION)];
  29. DbgPrint("WINREG: Tracked key data for object 0x%x\n", pKeyData->hKey);
  30. //
  31. // Set buffer to store info about this key
  32. //
  33. keyinfo._pFullPath = (PKEY_NAME_INFORMATION) rgNameBuf;
  34. keyinfo._cbFullPath = sizeof(rgNameBuf);
  35. //
  36. // get information about this key
  37. //
  38. Status = BaseRegGetKeySemantics(pKeyData->hKey, &EmptyString, &keyinfo);
  39. if (!NT_SUCCESS(Status)) {
  40. DbgPrint("WINREG: Unable to retrieve object name error 0x%x\n", Status);
  41. } else {
  42. DbgPrint("WINREG: Name: %S\n", keyinfo._pFullPath->Name);
  43. }
  44. BaseRegReleaseKeySemantics(&keyinfo);
  45. DbgPrint("Frames %d", pKeyData->dwStackDepth);
  46. {
  47. DWORD iFrame;
  48. for (iFrame = 0; iFrame < pKeyData->dwStackDepth; iFrame++)
  49. {
  50. DbgPrint("WINREG: Frame %d = 0x%x\n", iFrame, pKeyData->rgStack[iFrame]);
  51. }
  52. }
  53. DbgPrint("\n");
  54. }
  55. NTSTATUS TrackObjectDataInit(TrackObjectData* pKeyData, PVOID* rgStack, DWORD dwMaxStackDepth, HKEY hKey)
  56. {
  57. RtlZeroMemory(pKeyData, sizeof(*pKeyData));
  58. pKeyData->hKey = REG_CLASS_RESET_SPECIAL_KEY(hKey);
  59. pKeyData->dwStackDepth = dwMaxStackDepth;
  60. pKeyData->rgStack = rgStack;
  61. return STATUS_SUCCESS;
  62. }
  63. NTSTATUS TrackObjectDataClear(TrackObjectData* pKeyData)
  64. {
  65. if (pKeyData->rgStack) {
  66. RtlFreeHeap(RtlProcessHeap(), 0, pKeyData->rgStack);
  67. pKeyData->rgStack = NULL;
  68. }
  69. return STATUS_SUCCESS;
  70. }
  71. NTSTATUS RegLeakTableInit(RegLeakTable* pLeakTable, DWORD dwFlags)
  72. {
  73. NTSTATUS Status;
  74. RtlZeroMemory(pLeakTable, sizeof(*pLeakTable));
  75. pLeakTable->dwFlags = dwFlags;
  76. Status = RtlInitializeCriticalSection(
  77. &(pLeakTable->CriticalSection));
  78. if (!NT_SUCCESS(Status)) {
  79. return Status;
  80. }
  81. //
  82. // Remember that we have initialized this critical section
  83. // so we can remember to delete it.
  84. //
  85. pLeakTable->bCriticalSectionInitialized = TRUE;
  86. Status = RtlInitializeCriticalSection(
  87. &(g_RegLeakTraceInfo.StackInitCriticalSection));
  88. if (!NT_SUCCESS(Status)) {
  89. return Status;
  90. }
  91. return STATUS_SUCCESS;
  92. }
  93. NTSTATUS RegLeakTableClear(RegLeakTable* pLeakTable)
  94. {
  95. NTSTATUS Status;
  96. #if defined(DBG) // LEAK_TRACK
  97. DbgPrint("WINREG: Leak data for process id 0x%x\n", NtCurrentTeb()->ClientId.UniqueProcess);
  98. DbgPrint("WINREG: Keys Leaked 0x%x\n", pLeakTable->cKeys);
  99. #endif // LEAK_TRACK
  100. Status = RtlDeleteCriticalSection(
  101. &(pLeakTable->CriticalSection));
  102. ASSERT(NT_SUCCESS(Status));
  103. Status = RtlDeleteCriticalSection(
  104. &(g_RegLeakTraceInfo.StackInitCriticalSection));
  105. ASSERT(NT_SUCCESS(Status));
  106. #if DBG
  107. if ( !NT_SUCCESS( Status ) ) {
  108. DbgPrint( "WINREG: RtlDeleteCriticalSection() in EnumTableClear() failed. Status = %lx \n", Status );
  109. }
  110. #endif
  111. {
  112. DWORD cKeys;
  113. cKeys = 0;
  114. for (;;)
  115. {
  116. if (!(pLeakTable->pHead)) {
  117. break;
  118. }
  119. TrackObjectDataPrint(pLeakTable->pHead);
  120. cKeys++;
  121. (void) RegLeakTableRemoveKey(pLeakTable, pLeakTable->pHead->hKey);
  122. }
  123. #if defined(DBG) // LEAK_TRACK
  124. DbgPrint("WINREG: 0x%x total keys leaked\n", cKeys);
  125. #endif // LEAK_TRACK
  126. }
  127. return STATUS_SUCCESS;
  128. }
  129. NTSTATUS RegLeakTableAddKey(RegLeakTable* pLeakTable, HKEY hKey)
  130. {
  131. NTSTATUS Status;
  132. TrackObjectData* pNewData;
  133. PVOID* rgStack;
  134. DWORD dwMaxStackDepth;
  135. rgStack = NULL;
  136. dwMaxStackDepth = 0;
  137. hKey = REG_CLASS_RESET_SPECIAL_KEY(hKey);
  138. if (!RegLeakTableIsTrackedObject(pLeakTable, hKey)) {
  139. return STATUS_SUCCESS;
  140. }
  141. (void) GetLeakStack(
  142. &rgStack,
  143. &dwMaxStackDepth,
  144. g_RegLeakTraceInfo.dwMaxStackDepth);
  145. Status = RtlEnterCriticalSection(&(pLeakTable->CriticalSection));
  146. ASSERT( NT_SUCCESS( Status ) );
  147. if ( !NT_SUCCESS( Status ) ) {
  148. #if DBG
  149. DbgPrint( "WINREG: RtlEnterCriticalSection() in EnumTableRemoveKey() failed. Status = %lx \n", Status );
  150. #endif
  151. return Status;
  152. }
  153. pNewData = RtlAllocateHeap(RtlProcessHeap(), 0, sizeof(*pNewData));
  154. if (!pNewData) {
  155. Status = STATUS_NO_MEMORY;
  156. goto cleanup;
  157. }
  158. Status = TrackObjectDataInit(pNewData, rgStack, dwMaxStackDepth, hKey);
  159. if (!NT_SUCCESS(Status)) {
  160. goto cleanup;
  161. }
  162. if (!RegLeakTableIsEmpty(pLeakTable)) {
  163. pNewData->Links.Flink = (PLIST_ENTRY) pLeakTable->pHead;
  164. pLeakTable->pHead->Links.Blink = (PLIST_ENTRY) pNewData;
  165. }
  166. pLeakTable->pHead = pNewData;
  167. pLeakTable->cKeys++;
  168. cleanup:
  169. {
  170. NTSTATUS Status;
  171. Status = RtlLeaveCriticalSection(&(pLeakTable->CriticalSection));
  172. ASSERT( NT_SUCCESS( Status ) );
  173. #if DBG
  174. if ( !NT_SUCCESS( Status ) ) {
  175. DbgPrint( "WINREG: RtlLeaveCriticalSection() in EnumTableClear() failed. Status = %lx \n", Status );
  176. }
  177. #endif
  178. }
  179. return Status;
  180. }
  181. NTSTATUS RegLeakTableRemoveKey(RegLeakTable* pLeakTable, HKEY hKey)
  182. {
  183. NTSTATUS Status;
  184. TrackObjectData* pData;
  185. Status = RtlEnterCriticalSection(&(pLeakTable->CriticalSection));
  186. ASSERT( NT_SUCCESS( Status ) );
  187. if ( !NT_SUCCESS( Status ) ) {
  188. #if DBG
  189. DbgPrint( "WINREG: RtlEnterCriticalSection() in EnumTableRemoveKey() failed. Status = %lx \n", Status );
  190. #endif
  191. return Status;
  192. }
  193. hKey = REG_CLASS_RESET_SPECIAL_KEY(hKey);
  194. for (pData = pLeakTable->pHead;
  195. pData != NULL;
  196. pData = (TrackObjectData*) pData->Links.Flink)
  197. {
  198. if (hKey == pData->hKey) {
  199. PLIST_ENTRY pFlink;
  200. PLIST_ENTRY pBlink;
  201. pBlink = pData->Links.Blink;
  202. pFlink = pData->Links.Flink;
  203. if (pBlink) {
  204. pBlink->Flink = pFlink;
  205. }
  206. if (pFlink) {
  207. pFlink->Blink = pBlink;
  208. }
  209. if (pData == pLeakTable->pHead) {
  210. pLeakTable->pHead = (TrackObjectData*) pFlink;
  211. }
  212. (void) TrackObjectDataClear(pData);
  213. RtlFreeHeap(RtlProcessHeap(), 0, pData);
  214. pLeakTable->cKeys--;
  215. goto cleanup;
  216. }
  217. }
  218. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  219. cleanup:
  220. {
  221. NTSTATUS Status;
  222. Status = RtlLeaveCriticalSection(&(pLeakTable->CriticalSection));
  223. ASSERT( NT_SUCCESS( Status ) );
  224. #if DBG
  225. if ( !NT_SUCCESS( Status ) ) {
  226. DbgPrint( "WINREG: RtlLeaveCriticalSection() in EnumTableClear() failed. Status = %lx \n", Status );
  227. }
  228. #endif
  229. }
  230. return Status;
  231. }
  232. BOOL RegLeakTableIsEmpty(RegLeakTable* pLeakTable)
  233. {
  234. return pLeakTable->pHead == NULL;
  235. }
  236. BOOL RegLeakTableIsTrackedObject(RegLeakTable* pLeakTable, HKEY hKey)
  237. {
  238. NTSTATUS Status;
  239. SKeySemantics keyinfo;
  240. UNICODE_STRING EmptyString = {0, 0, 0};
  241. BYTE rgNameBuf[REG_MAX_CLASSKEY_LEN + REG_CHAR_SIZE + sizeof(KEY_NAME_INFORMATION)];
  242. BOOL fTrackObject;
  243. fTrackObject = FALSE;
  244. if (LEAK_TRACK_FLAG_ALL == pLeakTable->dwFlags) {
  245. return TRUE;
  246. }
  247. if (LEAK_TRACK_FLAG_NONE == pLeakTable->dwFlags) {
  248. return FALSE;
  249. }
  250. //
  251. // Set buffer to store info about this key
  252. //
  253. keyinfo._pFullPath = (PKEY_NAME_INFORMATION) rgNameBuf;
  254. keyinfo._cbFullPath = sizeof(rgNameBuf);
  255. //
  256. // get information about this key
  257. //
  258. Status = BaseRegGetKeySemantics(hKey, &EmptyString, &keyinfo);
  259. if (!NT_SUCCESS(Status)) {
  260. return Status;
  261. }
  262. if (LEAK_TRACK_FLAG_USER & pLeakTable->dwFlags) {
  263. WCHAR UserChar;
  264. UserChar = keyinfo._pFullPath->Name[REG_CLASSES_FIRST_DISTINCT_ICH];
  265. if ((L'U' == UserChar) || (L'u' == UserChar)) {
  266. fTrackObject = TRUE;
  267. }
  268. }
  269. BaseRegReleaseKeySemantics(&keyinfo);
  270. return fTrackObject;
  271. }
  272. NTSTATUS TrackObject(HKEY hKey)
  273. {
  274. return RegLeakTableAddKey(&gLeakTable, hKey);
  275. }
  276. #define WINLOGON_KEY L"\\Registry\\Machine\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"
  277. #define LEAKTRACK_VALUE L"LeakTrack"
  278. #define DEFAULT_VALUE_SIZE 128
  279. void ReadRegLeakTrackInfo()
  280. {
  281. LPTSTR lpWinlogonKey;
  282. LONG error;
  283. OBJECT_ATTRIBUTES Attributes;
  284. NTSTATUS Status;
  285. HKEY hKey;
  286. UNICODE_STRING uWinlogonPath;
  287. UNICODE_STRING uValueName;
  288. KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass;
  289. PVOID KeyValueInformation;
  290. BYTE PrivateKeyValueInformation[ sizeof( KEY_VALUE_PARTIAL_INFORMATION) +
  291. DEFAULT_VALUE_SIZE ];
  292. ULONG BufferLength;
  293. ULONG ResultLength;
  294. //
  295. // Look in the registry whether tracking is enabled uder
  296. // \Registry\Machine\Software\Microsoft\Windows NT\CurrentVersion\Winlogon
  297. //
  298. memset(&g_RegLeakTraceInfo, 0, sizeof(g_RegLeakTraceInfo));
  299. g_RegLeakTraceInfo.bEnableLeakTrack = 0;
  300. RtlInitUnicodeString(&uWinlogonPath, WINLOGON_KEY);
  301. InitializeObjectAttributes(&Attributes,
  302. &uWinlogonPath,
  303. OBJ_CASE_INSENSITIVE,
  304. NULL,
  305. NULL);
  306. Status = NtOpenKey( &hKey,
  307. KEY_READ,
  308. &Attributes );
  309. if (NT_SUCCESS(Status)) {
  310. RtlInitUnicodeString(&uValueName, LEAKTRACK_VALUE);
  311. KeyValueInformationClass = KeyValuePartialInformation;
  312. KeyValueInformation = PrivateKeyValueInformation;
  313. BufferLength = sizeof( PrivateKeyValueInformation );
  314. Status = NtQueryValueKey( hKey,
  315. &uValueName,
  316. KeyValueInformationClass,
  317. KeyValueInformation,
  318. BufferLength,
  319. &ResultLength );
  320. //
  321. // if it succeeded and the datalength is greater than zero
  322. // check whether it is non-zero
  323. //
  324. if ((NT_SUCCESS(Status)) &&
  325. (((PKEY_VALUE_PARTIAL_INFORMATION )KeyValueInformation )->DataLength)) {
  326. if (((( PKEY_VALUE_PARTIAL_INFORMATION )KeyValueInformation)->Data) &&
  327. (*((( PKEY_VALUE_PARTIAL_INFORMATION )KeyValueInformation)->Data)))
  328. g_RegLeakTraceInfo.bEnableLeakTrack = 1;
  329. }
  330. NtClose(hKey);
  331. }
  332. // g_RegLeakTraceInfo.bEnableLeakTrack = GetProfileInt(TEXT("RegistryLeak"), TEXT("Enable"), 0);
  333. }
  334. BOOL InitializeLeakTrackTable()
  335. {
  336. ReadRegLeakTrackInfo();
  337. if (g_RegLeakTraceInfo.bEnableLeakTrack)
  338. return NT_SUCCESS(RegLeakTableInit(&gLeakTable, LEAK_TRACK_FLAG_USER));
  339. else
  340. return TRUE;
  341. }
  342. BOOL CleanupLeakTrackTable()
  343. {
  344. BOOL fSuccess;
  345. if (!g_RegLeakTraceInfo.bEnableLeakTrack)
  346. return TRUE;
  347. //
  348. // if leak_tracking is not enabled, quit quickly.
  349. //
  350. fSuccess = NT_SUCCESS(RegLeakTableClear(&gLeakTable));
  351. (void) StopDebug();
  352. return fSuccess;
  353. }
  354. NTSTATUS UnTrackObject(HKEY hKey)
  355. {
  356. return RegLeakTableRemoveKey(&gLeakTable, hKey);
  357. }
  358. NTSTATUS GetLeakStack(PVOID** prgStack, DWORD* pdwMaxDepth, DWORD dwMaxDepth)
  359. {
  360. PCALLER_SYM pStack;
  361. DWORD dwDepth;
  362. pStack = (PCALLER_SYM) RtlAllocateHeap(
  363. RtlProcessHeap(),
  364. 0,
  365. dwMaxDepth * sizeof(*pStack));
  366. if (!pStack) {
  367. return STATUS_NO_MEMORY;
  368. }
  369. RtlZeroMemory(pStack, sizeof(*pStack) * dwMaxDepth);
  370. *prgStack = RtlAllocateHeap(
  371. RtlProcessHeap(),
  372. 0,
  373. dwMaxDepth * sizeof(*(*prgStack)));
  374. if (!*prgStack) {
  375. RtlFreeHeap(RtlProcessHeap(),
  376. 0,
  377. pStack);
  378. return STATUS_NO_MEMORY;
  379. }
  380. RtlZeroMemory(*prgStack, sizeof(*(*prgStack)) * dwMaxDepth);
  381. GetCallStack(
  382. pStack,
  383. 4,
  384. dwMaxDepth,
  385. FALSE);
  386. for (dwDepth = 0; dwDepth < dwMaxDepth; dwDepth++)
  387. {
  388. if (!(pStack[dwDepth].Addr)) {
  389. break;
  390. }
  391. (*prgStack)[dwDepth] = pStack[dwDepth].Addr;
  392. }
  393. *pdwMaxDepth = dwDepth;
  394. RtlFreeHeap(
  395. RtlProcessHeap(),
  396. 0,
  397. pStack);
  398. return STATUS_SUCCESS;
  399. }
  400. #endif // DBG
  401. #endif // LOCAL