/*========================================================================== * * Copyright (C) 2001 Microsoft Corporation. All Rights Reserved. * * File: HandleTracking.cpp * Content: Handle Tracking debug logic * * History: * Date By Reason * ==== == ====== * 10/31/2001 masonb Created * * ***************************************************************************/ #include "dncmni.h" #ifdef DBG CBilink g_blHandles; #ifndef DPNBUILD_ONLYONETHREAD DNCRITICAL_SECTION g_HandleLock; #endif // !DPNBUILD_ONLYONETHREAD #define IsValidHandle(x) \ (x != NULL && x != INVALID_HANDLE_VALUE && \ (x->type == TypeEvent || \ x->type == TypeMutex || \ x->type == TypeSemaphore || \ x->type == TypeFile || \ x->type == TypeFileMap || \ x->type == TypeThread || \ x->type == TypeProcess || \ x->type == TypeSpecial)) BOOL DNHandleTrackInitialize() { g_blHandles.Initialize(); return DNInitializeCriticalSection(&g_HandleLock); } VOID DNHandleTrackDeinitialize() { DNDeleteCriticalSection(&g_HandleLock); } #undef DPF_MODNAME #define DPF_MODNAME "DNHandleTrackDumpLeaks" BOOL DNHandleTrackDumpLeaks() { BOOL fLeaked = FALSE; DNEnterCriticalSection(&g_HandleLock); while(!g_blHandles.IsEmpty()) { DNHANDLE dnh = CONTAINING_RECORD(g_blHandles.GetNext(), TRACKED_HANDLE, blHandle); dnh->blHandle.RemoveFromList(); fLeaked = TRUE; // Dump dnh details switch(dnh->type) { case TypeEvent: DPFX(DPFPREP, 0, "Event leaked %p", dnh->handle); break; case TypeMutex: DPFX(DPFPREP, 0, "Mutex leaked %p", dnh->handle); break; case TypeSemaphore: DPFX(DPFPREP, 0, "Semaphore leaked %p", dnh->handle); break; case TypeFile: DPFX(DPFPREP, 0, "File leaked %p", dnh->handle); break; #ifndef DPNBUILD_SINGLEPROCESS case TypeFileMap: DPFX(DPFPREP, 0, "FileMapping leaked %p", dnh->handle); break; #endif // ! DPNBUILD_SINGLEPROCESS case TypeThread: DPFX(DPFPREP, 0, "Thread leaked %p", dnh->handle); break; #ifndef DPNBUILD_SINGLEPROCESS case TypeProcess: DPFX(DPFPREP, 0, "Process leaked %p", dnh->handle); break; #endif // ! DPNBUILD_SINGLEPROCESS case TypeSpecial: DPFX(DPFPREP, 0, "Special handle leaked %p", dnh->handle); break; default: DPFX(DPFPREP, 0, "Unknown handle leaked %p", dnh->handle); DNASSERT(0); break; } // Show the callstack of the place the handle was allocated. TCHAR CallStackBuffer[ CALLSTACK_BUFFER_SIZE ]; dnh->AllocCallStack.GetCallStackString( CallStackBuffer ); DPFX(DPFPREP, 0, "%s\n", CallStackBuffer ); DNFree(dnh); } DNLeaveCriticalSection(&g_HandleLock); return fLeaked; } DNHANDLE DNHandleTrackMakeDNHANDLE(HANDLE h) { if (h == 0 || h == INVALID_HANDLE_VALUE) { return (DNHANDLE)h; } DNHANDLE dnh = (DNHANDLE)DNMalloc(sizeof(TRACKED_HANDLE)); if (!dnh) { CloseHandle(h); return 0; } dnh->AllocCallStack.NoteCurrentCallStack(); dnh->handle = h; dnh->type = TypeSpecial; dnh->blHandle.Initialize(); DNEnterCriticalSection(&g_HandleLock); dnh->blHandle.InsertBefore(&g_blHandles); DNLeaveCriticalSection(&g_HandleLock); return dnh; } VOID DNHandleTrackRemoveDNHANDLE(DNHANDLE dnh) { DNASSERT(IsValidHandle(dnh)); DNEnterCriticalSection(&g_HandleLock); dnh->blHandle.RemoveFromList(); DNLeaveCriticalSection(&g_HandleLock); DNFree(dnh); } HANDLE DNHandleTrackHandleFromDNHANDLE(DNHANDLE h) { if (h == 0 || h == INVALID_HANDLE_VALUE) { return (HANDLE)h; } DNASSERT(IsValidHandle(h)); return h->handle; } #ifndef DPNBUILD_SINGLEPROCESS // NOTE: pCurrentDirectory is const on the desktop, but non-const on WinCE BOOL DNHandleTrackCreateProcess(LPCTSTR lpApplicationName, LPTSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCTSTR lpCurrentDirectory, LPSTARTUPINFO lpStartupInfo, DNPROCESS_INFORMATION* lpProcessInformation) { PROCESS_INFORMATION pi; DWORD dwLastError; DNHANDLE dnhProcess = (DNHANDLE)DNMalloc(sizeof(TRACKED_HANDLE)); if (!dnhProcess) { return FALSE; } DNHANDLE dnhThread = (DNHANDLE)DNMalloc(sizeof(TRACKED_HANDLE)); if (!dnhThread) { DNFree(dnhProcess); return FALSE; } // NOTE: On CE only the current directory is declared non-const so cast it off #ifdef WINCE if (!CreateProcess(lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, (LPTSTR)lpCurrentDirectory, lpStartupInfo, &pi)) #else // !WINCE if (!CreateProcess(lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, &pi)) #endif // WINCE { dwLastError = GetLastError(); DNFree(dnhProcess); DNFree(dnhThread); SetLastError(dwLastError); return FALSE; } dwLastError = GetLastError(); dnhProcess->AllocCallStack.NoteCurrentCallStack(); dnhProcess->handle = pi.hProcess; dnhProcess->type = TypeProcess; dnhProcess->blHandle.Initialize(); dnhThread->AllocCallStack.NoteCurrentCallStack(); dnhThread->handle = pi.hThread; dnhThread->type = TypeThread; dnhThread->blHandle.Initialize(); DNEnterCriticalSection(&g_HandleLock); dnhProcess->blHandle.InsertBefore(&g_blHandles); dnhThread->blHandle.InsertBefore(&g_blHandles); DNLeaveCriticalSection(&g_HandleLock); lpProcessInformation->hProcess = dnhProcess; lpProcessInformation->hThread = dnhThread; lpProcessInformation->dwProcessId = pi.dwProcessId; lpProcessInformation->dwThreadId = pi.dwThreadId; SetLastError(dwLastError); return TRUE; } DNHANDLE DNHandleTrackOpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId) { DWORD dwLastError; HANDLE h = OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId); if (!h) { return 0; } dwLastError = GetLastError(); DNHANDLE dnh = (DNHANDLE)DNMalloc(sizeof(TRACKED_HANDLE)); if (!dnh) { CloseHandle(h); SetLastError(dwLastError); return 0; } dnh->AllocCallStack.NoteCurrentCallStack(); dnh->handle = h; dnh->type = TypeProcess; dnh->blHandle.Initialize(); DNEnterCriticalSection(&g_HandleLock); dnh->blHandle.InsertBefore(&g_blHandles); DNLeaveCriticalSection(&g_HandleLock); SetLastError(dwLastError); return dnh; } #endif // ! DPNBUILD_SINGLEPROCESS DNHANDLE DNHandleTrackCreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId) { DWORD dwLastError; HANDLE h = CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId); if (!h) { return 0; } dwLastError = GetLastError(); DNHANDLE dnh = (DNHANDLE)DNMalloc(sizeof(TRACKED_HANDLE)); if (!dnh) { CloseHandle(h); SetLastError(dwLastError); return 0; } dnh->AllocCallStack.NoteCurrentCallStack(); dnh->handle = h; dnh->type = TypeThread; dnh->blHandle.Initialize(); DNEnterCriticalSection(&g_HandleLock); dnh->blHandle.InsertBefore(&g_blHandles); DNLeaveCriticalSection(&g_HandleLock); SetLastError(dwLastError); return dnh; } DNHANDLE DNHandleTrackCreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCTSTR lpName) { DWORD dwLastError; HANDLE h = CreateEvent(lpEventAttributes, bManualReset, bInitialState, lpName); if (!h) { return 0; } dwLastError = GetLastError(); DNHANDLE dnh = (DNHANDLE)DNMalloc(sizeof(TRACKED_HANDLE)); if (!dnh) { CloseHandle(h); SetLastError(dwLastError); return 0; } dnh->AllocCallStack.NoteCurrentCallStack(); dnh->handle = h; dnh->type = TypeEvent; dnh->blHandle.Initialize(); DNEnterCriticalSection(&g_HandleLock); dnh->blHandle.InsertBefore(&g_blHandles); DNLeaveCriticalSection(&g_HandleLock); SetLastError(dwLastError); return dnh; } DNHANDLE DNHandleTrackOpenEvent(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpName) { DWORD dwLastError; HANDLE h = OpenEvent(dwDesiredAccess, bInheritHandle, lpName); if (!h) { return 0; } dwLastError = GetLastError(); DNHANDLE dnh = (DNHANDLE)DNMalloc(sizeof(TRACKED_HANDLE)); if (!dnh) { CloseHandle(h); SetLastError(dwLastError); return 0; } dnh->AllocCallStack.NoteCurrentCallStack(); dnh->handle = h; dnh->type = TypeEvent; dnh->blHandle.Initialize(); DNEnterCriticalSection(&g_HandleLock); dnh->blHandle.InsertBefore(&g_blHandles); DNLeaveCriticalSection(&g_HandleLock); SetLastError(dwLastError); return dnh; } BOOL DNHandleTrackSetEvent(DNHANDLE hHandle) { DNASSERT(IsValidHandle(hHandle)); DNASSERT(hHandle->type == TypeEvent); return SetEvent(hHandle->handle); } BOOL DNHandleTrackResetEvent(DNHANDLE hHandle) { DNASSERT(IsValidHandle(hHandle)); DNASSERT(hHandle->type == TypeEvent); return ResetEvent(hHandle->handle); } DNHANDLE DNHandleTrackCreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCTSTR lpName) { DWORD dwLastError; HANDLE h = CreateMutex(lpMutexAttributes, bInitialOwner, lpName); if (!h) { return 0; } dwLastError = GetLastError(); DNHANDLE dnh = (DNHANDLE)DNMalloc(sizeof(TRACKED_HANDLE)); if (!dnh) { CloseHandle(h); SetLastError(dwLastError); return 0; } dnh->AllocCallStack.NoteCurrentCallStack(); dnh->handle = h; dnh->type = TypeMutex; dnh->blHandle.Initialize(); DNEnterCriticalSection(&g_HandleLock); dnh->blHandle.InsertBefore(&g_blHandles); DNLeaveCriticalSection(&g_HandleLock); SetLastError(dwLastError); return dnh; } DNHANDLE DNHandleTrackOpenMutex(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpName) { DWORD dwLastError; HANDLE h = OpenMutex(dwDesiredAccess, bInheritHandle, lpName); if (!h) { return 0; } dwLastError = GetLastError(); DNHANDLE dnh = (DNHANDLE)DNMalloc(sizeof(TRACKED_HANDLE)); if (!dnh) { CloseHandle(h); SetLastError(dwLastError); return 0; } dnh->AllocCallStack.NoteCurrentCallStack(); dnh->handle = h; dnh->type = TypeMutex; dnh->blHandle.Initialize(); DNEnterCriticalSection(&g_HandleLock); dnh->blHandle.InsertBefore(&g_blHandles); DNLeaveCriticalSection(&g_HandleLock); SetLastError(dwLastError); return dnh; } BOOL DNHandleTrackReleaseMutex(DNHANDLE hHandle) { DNASSERT(IsValidHandle(hHandle)); DNASSERT(hHandle->type == TypeMutex); return ReleaseMutex(hHandle->handle); } DNHANDLE DNHandleTrackCreateSemaphore(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, LPCTSTR lpName) { DWORD dwLastError; HANDLE h = CreateSemaphore(lpSemaphoreAttributes, lInitialCount, lMaximumCount, lpName); if (!h) { return 0; } dwLastError = GetLastError(); DNHANDLE dnh = (DNHANDLE)DNMalloc(sizeof(TRACKED_HANDLE)); if (!dnh) { CloseHandle(h); SetLastError(dwLastError); return 0; } dnh->AllocCallStack.NoteCurrentCallStack(); dnh->handle = h; dnh->type = TypeSemaphore; dnh->blHandle.Initialize(); DNEnterCriticalSection(&g_HandleLock); dnh->blHandle.InsertBefore(&g_blHandles); DNLeaveCriticalSection(&g_HandleLock); SetLastError(dwLastError); return dnh; } BOOL DNHandleTrackReleaseSemaphore(DNHANDLE hHandle, LONG lReleaseCount, LPLONG lpPreviousCount) { DNASSERT(IsValidHandle(hHandle)); DNASSERT(hHandle->type == TypeSemaphore); return ReleaseSemaphore(hHandle->handle, lReleaseCount, lpPreviousCount); } DNHANDLE DNHandleTrackCreateFile(LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { DWORD dwLastError; HANDLE h = CreateFile(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); if (h == INVALID_HANDLE_VALUE) { return DNINVALID_HANDLE_VALUE; } dwLastError = GetLastError(); DNHANDLE dnh = (DNHANDLE)DNMalloc(sizeof(TRACKED_HANDLE)); if (!dnh) { CloseHandle(h); SetLastError(dwLastError); return 0; } dnh->AllocCallStack.NoteCurrentCallStack(); dnh->handle = h; dnh->type = TypeFile; dnh->blHandle.Initialize(); DNEnterCriticalSection(&g_HandleLock); dnh->blHandle.InsertBefore(&g_blHandles); DNLeaveCriticalSection(&g_HandleLock); SetLastError(dwLastError); return dnh; } #ifndef DPNBUILD_SINGLEPROCESS DNHANDLE DNHandleTrackCreateFileMapping(HANDLE hFile, LPSECURITY_ATTRIBUTES lpAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCTSTR lpName) { DWORD dwLastError; // If someone wants to actually map a file, we need to make param 1 a DNHANDLE and do the appropriate work here. DNASSERT(hFile == INVALID_HANDLE_VALUE); HANDLE h = CreateFileMapping(hFile, lpAttributes, flProtect, dwMaximumSizeHigh, dwMaximumSizeLow, lpName); if (!h) { return 0; } dwLastError = GetLastError(); DNHANDLE dnh = (DNHANDLE)DNMalloc(sizeof(TRACKED_HANDLE)); if (!dnh) { CloseHandle(h); SetLastError(dwLastError); return 0; } dnh->AllocCallStack.NoteCurrentCallStack(); dnh->handle = h; dnh->type = TypeFileMap; dnh->blHandle.Initialize(); DNEnterCriticalSection(&g_HandleLock); dnh->blHandle.InsertBefore(&g_blHandles); DNLeaveCriticalSection(&g_HandleLock); SetLastError(dwLastError); return dnh; } DNHANDLE DNHandleTrackOpenFileMapping(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpName) { DWORD dwLastError; HANDLE h = OpenFileMapping(dwDesiredAccess, bInheritHandle, lpName); if (!h) { return 0; } dwLastError = GetLastError(); DNHANDLE dnh = (DNHANDLE)DNMalloc(sizeof(TRACKED_HANDLE)); if (!dnh) { CloseHandle(h); SetLastError(dwLastError); return 0; } dnh->AllocCallStack.NoteCurrentCallStack(); dnh->handle = h; dnh->type = TypeFileMap; dnh->blHandle.Initialize(); DNEnterCriticalSection(&g_HandleLock); dnh->blHandle.InsertBefore(&g_blHandles); DNLeaveCriticalSection(&g_HandleLock); SetLastError(dwLastError); return dnh; } BOOL DNHandleTrackGetExitCodeProcess(DNHANDLE hHandle, LPDWORD lpExitCode) { DNASSERT(IsValidHandle(hHandle)); return GetExitCodeProcess(hHandle->handle, lpExitCode); } #endif // ! DPNBUILD_SINGLEPROCESS DWORD DNHandleTrackWaitForSingleObject(DNHANDLE hHandle, DWORD dwMilliseconds) { DNASSERT(IsValidHandle(hHandle)); return WaitForSingleObject(hHandle->handle, dwMilliseconds); } DWORD DNHandleTrackWaitForSingleObjectEx(DNHANDLE hHandle, DWORD dwMilliseconds, BOOL bAlertable) { DNASSERT(IsValidHandle(hHandle)); return WaitForSingleObjectEx(hHandle->handle, dwMilliseconds, bAlertable); } DWORD DNHandleTrackWaitForMultipleObjects(DWORD nCount, CONST DNHANDLE *lpHandles, BOOL fWaitAll, DWORD dwMilliseconds) { DNASSERT(nCount <= MAXIMUM_WAIT_OBJECTS); HANDLE rgh[MAXIMUM_WAIT_OBJECTS]; DWORD iHandle; for (iHandle = 0; iHandle < nCount; iHandle++) { DNASSERT(IsValidHandle(lpHandles[iHandle])); rgh[iHandle] = lpHandles[iHandle]->handle; } for (;iHandle < MAXIMUM_WAIT_OBJECTS; iHandle++) { rgh[iHandle] = 0; } return WaitForMultipleObjects(nCount, rgh, fWaitAll, dwMilliseconds); } DWORD DNHandleTrackWaitForMultipleObjectsEx(DWORD nCount, CONST DNHANDLE *lpHandles, BOOL fWaitAll, DWORD dwMilliseconds, BOOL bAlertable) { DNASSERT(nCount <= MAXIMUM_WAIT_OBJECTS); HANDLE rgh[MAXIMUM_WAIT_OBJECTS]; DWORD iHandle; for (iHandle = 0; iHandle < nCount; iHandle++) { DNASSERT(IsValidHandle(lpHandles[iHandle])); rgh[iHandle] = lpHandles[iHandle]->handle; } for (;iHandle < MAXIMUM_WAIT_OBJECTS; iHandle++) { rgh[iHandle] = 0; } return WaitForMultipleObjectsEx(nCount, rgh, fWaitAll, dwMilliseconds, bAlertable); } DWORD DNHandleTrackSignalObjectAndWait(DNHANDLE hObjectToSignal, DNHANDLE hObjectToWaitOn, DWORD dwMilliseconds, BOOL bAlertable) { DNASSERT(IsValidHandle(hObjectToSignal)); DNASSERT(IsValidHandle(hObjectToWaitOn)); DNASSERT(hObjectToSignal->handle != hObjectToWaitOn->handle); #ifdef WINNT return SignalObjectAndWait(hObjectToSignal->handle, hObjectToWaitOn->handle, dwMilliseconds, bAlertable); #else // ! WINNT BOOL fResult; fResult = SetEvent(hObjectToSignal->handle); DNASSERT(fResult); return WaitForSingleObjectEx(hObjectToWaitOn->handle, dwMilliseconds, bAlertable); #endif // ! WINNT } BOOL DNHandleTrackCloseHandle(DNHANDLE hHandle) { DNASSERT(IsValidHandle(hHandle)); DNEnterCriticalSection(&g_HandleLock); hHandle->blHandle.RemoveFromList(); DNLeaveCriticalSection(&g_HandleLock); HANDLE h = hHandle->handle; DNFree(hHandle); return CloseHandle(h); } #endif // DBG