|
|
/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
RegLeak.h
Abstract:
This module contains helper functions for tracking n win32 registry leaks
Author:
Adam Edwards (adamed) 06-May-1998
--*/
#ifdef LOCAL
#ifdef LEAK_TRACK
#include "ntverp.h"
#include <rpc.h>
#include "regrpc.h"
#include "localreg.h"
#include "regclass.h"
#include "stkwalk.h"
#include "regleak.h"
#include <malloc.h>
RegLeakTable gLeakTable; RegLeakTraceInfo g_RegLeakTraceInfo;
void TrackObjectDataPrint(TrackObjectData* pKeyData) { NTSTATUS Status; SKeySemantics keyinfo; UNICODE_STRING EmptyString = {0, 0, 0}; BYTE rgNameBuf[REG_MAX_CLASSKEY_LEN + REG_CHAR_SIZE + sizeof(KEY_NAME_INFORMATION)];
DbgPrint("WINREG: Tracked key data for object 0x%x\n", pKeyData->hKey);
//
// Set buffer to store info about this key
//
keyinfo._pFullPath = (PKEY_NAME_INFORMATION) rgNameBuf; keyinfo._cbFullPath = sizeof(rgNameBuf);
//
// get information about this key
//
Status = BaseRegGetKeySemantics(pKeyData->hKey, &EmptyString, &keyinfo);
if (!NT_SUCCESS(Status)) { DbgPrint("WINREG: Unable to retrieve object name error 0x%x\n", Status); } else { DbgPrint("WINREG: Name: %S\n", keyinfo._pFullPath->Name); }
BaseRegReleaseKeySemantics(&keyinfo);
DbgPrint("Frames %d", pKeyData->dwStackDepth);
{ DWORD iFrame;
for (iFrame = 0; iFrame < pKeyData->dwStackDepth; iFrame++) { DbgPrint("WINREG: Frame %d = 0x%x\n", iFrame, pKeyData->rgStack[iFrame]); } } DbgPrint("\n");
}
NTSTATUS TrackObjectDataInit(TrackObjectData* pKeyData, PVOID* rgStack, DWORD dwMaxStackDepth, HKEY hKey) { RtlZeroMemory(pKeyData, sizeof(*pKeyData)); pKeyData->hKey = REG_CLASS_RESET_SPECIAL_KEY(hKey); pKeyData->dwStackDepth = dwMaxStackDepth; pKeyData->rgStack = rgStack;
return STATUS_SUCCESS; }
NTSTATUS TrackObjectDataClear(TrackObjectData* pKeyData) { if (pKeyData->rgStack) { RtlFreeHeap(RtlProcessHeap(), 0, pKeyData->rgStack); pKeyData->rgStack = NULL; }
return STATUS_SUCCESS; }
NTSTATUS RegLeakTableInit(RegLeakTable* pLeakTable, DWORD dwFlags) { NTSTATUS Status;
RtlZeroMemory(pLeakTable, sizeof(*pLeakTable)); pLeakTable->dwFlags = dwFlags;
Status = RtlInitializeCriticalSection( &(pLeakTable->CriticalSection));
if (!NT_SUCCESS(Status)) { return Status; }
//
// Remember that we have initialized this critical section
// so we can remember to delete it.
//
pLeakTable->bCriticalSectionInitialized = TRUE;
Status = RtlInitializeCriticalSection( &(g_RegLeakTraceInfo.StackInitCriticalSection));
if (!NT_SUCCESS(Status)) { return Status; } return STATUS_SUCCESS; }
NTSTATUS RegLeakTableClear(RegLeakTable* pLeakTable) { NTSTATUS Status;
#if defined(DBG) // LEAK_TRACK
DbgPrint("WINREG: Leak data for process id 0x%x\n", NtCurrentTeb()->ClientId.UniqueProcess); DbgPrint("WINREG: Keys Leaked 0x%x\n", pLeakTable->cKeys); #endif // LEAK_TRACK
Status = RtlDeleteCriticalSection( &(pLeakTable->CriticalSection));
ASSERT(NT_SUCCESS(Status));
Status = RtlDeleteCriticalSection( &(g_RegLeakTraceInfo.StackInitCriticalSection));
ASSERT(NT_SUCCESS(Status)); #if DBG
if ( !NT_SUCCESS( Status ) ) { DbgPrint( "WINREG: RtlDeleteCriticalSection() in EnumTableClear() failed. Status = %lx \n", Status ); } #endif
{ DWORD cKeys;
cKeys = 0;
for (;;) { if (!(pLeakTable->pHead)) { break; } TrackObjectDataPrint(pLeakTable->pHead);
cKeys++;
(void) RegLeakTableRemoveKey(pLeakTable, pLeakTable->pHead->hKey); }
#if defined(DBG) // LEAK_TRACK
DbgPrint("WINREG: 0x%x total keys leaked\n", cKeys); #endif // LEAK_TRACK
}
return STATUS_SUCCESS; }
NTSTATUS RegLeakTableAddKey(RegLeakTable* pLeakTable, HKEY hKey) { NTSTATUS Status; TrackObjectData* pNewData; PVOID* rgStack; DWORD dwMaxStackDepth;
rgStack = NULL; dwMaxStackDepth = 0;
hKey = REG_CLASS_RESET_SPECIAL_KEY(hKey);
if (!RegLeakTableIsTrackedObject(pLeakTable, hKey)) { return STATUS_SUCCESS; }
(void) GetLeakStack( &rgStack, &dwMaxStackDepth, g_RegLeakTraceInfo.dwMaxStackDepth);
Status = RtlEnterCriticalSection(&(pLeakTable->CriticalSection)); ASSERT( NT_SUCCESS( Status ) ); if ( !NT_SUCCESS( Status ) ) { #if DBG
DbgPrint( "WINREG: RtlEnterCriticalSection() in EnumTableRemoveKey() failed. Status = %lx \n", Status ); #endif
return Status; } pNewData = RtlAllocateHeap(RtlProcessHeap(), 0, sizeof(*pNewData));
if (!pNewData) { Status = STATUS_NO_MEMORY; goto cleanup; }
Status = TrackObjectDataInit(pNewData, rgStack, dwMaxStackDepth, hKey);
if (!NT_SUCCESS(Status)) { goto cleanup; }
if (!RegLeakTableIsEmpty(pLeakTable)) { pNewData->Links.Flink = (PLIST_ENTRY) pLeakTable->pHead; pLeakTable->pHead->Links.Blink = (PLIST_ENTRY) pNewData;
}
pLeakTable->pHead = pNewData;
pLeakTable->cKeys++;
cleanup: { NTSTATUS Status;
Status = RtlLeaveCriticalSection(&(pLeakTable->CriticalSection));
ASSERT( NT_SUCCESS( Status ) ); #if DBG
if ( !NT_SUCCESS( Status ) ) { DbgPrint( "WINREG: RtlLeaveCriticalSection() in EnumTableClear() failed. Status = %lx \n", Status ); } #endif
}
return Status; }
NTSTATUS RegLeakTableRemoveKey(RegLeakTable* pLeakTable, HKEY hKey) { NTSTATUS Status; TrackObjectData* pData;
Status = RtlEnterCriticalSection(&(pLeakTable->CriticalSection)); ASSERT( NT_SUCCESS( Status ) ); if ( !NT_SUCCESS( Status ) ) { #if DBG
DbgPrint( "WINREG: RtlEnterCriticalSection() in EnumTableRemoveKey() failed. Status = %lx \n", Status ); #endif
return Status; }
hKey = REG_CLASS_RESET_SPECIAL_KEY(hKey);
for (pData = pLeakTable->pHead; pData != NULL; pData = (TrackObjectData*) pData->Links.Flink) { if (hKey == pData->hKey) { PLIST_ENTRY pFlink; PLIST_ENTRY pBlink; pBlink = pData->Links.Blink; pFlink = pData->Links.Flink;
if (pBlink) { pBlink->Flink = pFlink; }
if (pFlink) { pFlink->Blink = pBlink; }
if (pData == pLeakTable->pHead) { pLeakTable->pHead = (TrackObjectData*) pFlink; }
(void) TrackObjectDataClear(pData);
RtlFreeHeap(RtlProcessHeap(), 0, pData);
pLeakTable->cKeys--;
goto cleanup; } }
Status = STATUS_OBJECT_NAME_NOT_FOUND;
cleanup:
{ NTSTATUS Status;
Status = RtlLeaveCriticalSection(&(pLeakTable->CriticalSection));
ASSERT( NT_SUCCESS( Status ) ); #if DBG
if ( !NT_SUCCESS( Status ) ) { DbgPrint( "WINREG: RtlLeaveCriticalSection() in EnumTableClear() failed. Status = %lx \n", Status ); } #endif
}
return Status; }
BOOL RegLeakTableIsEmpty(RegLeakTable* pLeakTable) { return pLeakTable->pHead == NULL; }
BOOL RegLeakTableIsTrackedObject(RegLeakTable* pLeakTable, HKEY hKey) { NTSTATUS Status; SKeySemantics keyinfo; UNICODE_STRING EmptyString = {0, 0, 0}; BYTE rgNameBuf[REG_MAX_CLASSKEY_LEN + REG_CHAR_SIZE + sizeof(KEY_NAME_INFORMATION)]; BOOL fTrackObject;
fTrackObject = FALSE;
if (LEAK_TRACK_FLAG_ALL == pLeakTable->dwFlags) { return TRUE; }
if (LEAK_TRACK_FLAG_NONE == pLeakTable->dwFlags) { return FALSE; } //
// Set buffer to store info about this key
//
keyinfo._pFullPath = (PKEY_NAME_INFORMATION) rgNameBuf; keyinfo._cbFullPath = sizeof(rgNameBuf);
//
// get information about this key
//
Status = BaseRegGetKeySemantics(hKey, &EmptyString, &keyinfo);
if (!NT_SUCCESS(Status)) { return Status; }
if (LEAK_TRACK_FLAG_USER & pLeakTable->dwFlags) {
WCHAR UserChar;
UserChar = keyinfo._pFullPath->Name[REG_CLASSES_FIRST_DISTINCT_ICH];
if ((L'U' == UserChar) || (L'u' == UserChar)) { fTrackObject = TRUE; } }
BaseRegReleaseKeySemantics(&keyinfo);
return fTrackObject;
}
NTSTATUS TrackObject(HKEY hKey) { return RegLeakTableAddKey(&gLeakTable, hKey); }
#define WINLOGON_KEY L"\\Registry\\Machine\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"
#define LEAKTRACK_VALUE L"LeakTrack"
#define DEFAULT_VALUE_SIZE 128
void ReadRegLeakTrackInfo() { LPTSTR lpWinlogonKey; LONG error; OBJECT_ATTRIBUTES Attributes; NTSTATUS Status; HKEY hKey; UNICODE_STRING uWinlogonPath; UNICODE_STRING uValueName;
KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass; PVOID KeyValueInformation;
BYTE PrivateKeyValueInformation[ sizeof( KEY_VALUE_PARTIAL_INFORMATION) + DEFAULT_VALUE_SIZE ]; ULONG BufferLength; ULONG ResultLength;
//
// Look in the registry whether tracking is enabled uder
// \Registry\Machine\Software\Microsoft\Windows NT\CurrentVersion\Winlogon
//
memset(&g_RegLeakTraceInfo, 0, sizeof(g_RegLeakTraceInfo));
g_RegLeakTraceInfo.bEnableLeakTrack = 0; RtlInitUnicodeString(&uWinlogonPath, WINLOGON_KEY); InitializeObjectAttributes(&Attributes, &uWinlogonPath, OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = NtOpenKey( &hKey, KEY_READ, &Attributes );
if (NT_SUCCESS(Status)) {
RtlInitUnicodeString(&uValueName, LEAKTRACK_VALUE);
KeyValueInformationClass = KeyValuePartialInformation;
KeyValueInformation = PrivateKeyValueInformation; BufferLength = sizeof( PrivateKeyValueInformation );
Status = NtQueryValueKey( hKey, &uValueName, KeyValueInformationClass, KeyValueInformation, BufferLength, &ResultLength );
//
// if it succeeded and the datalength is greater than zero
// check whether it is non-zero
//
if ((NT_SUCCESS(Status)) && (((PKEY_VALUE_PARTIAL_INFORMATION )KeyValueInformation )->DataLength)) {
if (((( PKEY_VALUE_PARTIAL_INFORMATION )KeyValueInformation)->Data) && (*((( PKEY_VALUE_PARTIAL_INFORMATION )KeyValueInformation)->Data))) g_RegLeakTraceInfo.bEnableLeakTrack = 1; }
NtClose(hKey);
} // g_RegLeakTraceInfo.bEnableLeakTrack = GetProfileInt(TEXT("RegistryLeak"), TEXT("Enable"), 0);
}
BOOL InitializeLeakTrackTable() { ReadRegLeakTrackInfo(); if (g_RegLeakTraceInfo.bEnableLeakTrack) return NT_SUCCESS(RegLeakTableInit(&gLeakTable, LEAK_TRACK_FLAG_USER)); else return TRUE; }
BOOL CleanupLeakTrackTable() { BOOL fSuccess;
if (!g_RegLeakTraceInfo.bEnableLeakTrack) return TRUE;
//
// if leak_tracking is not enabled, quit quickly.
//
fSuccess = NT_SUCCESS(RegLeakTableClear(&gLeakTable));
(void) StopDebug();
return fSuccess; }
NTSTATUS UnTrackObject(HKEY hKey) { return RegLeakTableRemoveKey(&gLeakTable, hKey); }
NTSTATUS GetLeakStack(PVOID** prgStack, DWORD* pdwMaxDepth, DWORD dwMaxDepth) {
PCALLER_SYM pStack; DWORD dwDepth;
pStack = (PCALLER_SYM) RtlAllocateHeap( RtlProcessHeap(), 0, dwMaxDepth * sizeof(*pStack));
if (!pStack) { return STATUS_NO_MEMORY; }
RtlZeroMemory(pStack, sizeof(*pStack) * dwMaxDepth);
*prgStack = RtlAllocateHeap( RtlProcessHeap(), 0, dwMaxDepth * sizeof(*(*prgStack)));
if (!*prgStack) { RtlFreeHeap(RtlProcessHeap(), 0, pStack);
return STATUS_NO_MEMORY; }
RtlZeroMemory(*prgStack, sizeof(*(*prgStack)) * dwMaxDepth);
GetCallStack( pStack, 4, dwMaxDepth, FALSE);
for (dwDepth = 0; dwDepth < dwMaxDepth; dwDepth++) { if (!(pStack[dwDepth].Addr)) { break; }
(*prgStack)[dwDepth] = pStack[dwDepth].Addr;
}
*pdwMaxDepth = dwDepth;
RtlFreeHeap( RtlProcessHeap(), 0, pStack);
return STATUS_SUCCESS; }
#endif // DBG
#endif // LOCAL
|