CallStack* CallStack::Create() { CallStack* result = NULL; if (g_vld.GetOptions() & VLD_OPT_SAFE_STACK_WALK) { result = new SafeCallStack(); } else { result = new FastCallStack(); } return result; }
__declspec(dllexport) UINT VLDReportLeaks () { return (UINT)g_vld.ReportLeaks(); }
__declspec(dllexport) void VLDGlobalEnable () { g_vld.GlobalEnableLeakDetection(); }
__declspec(dllexport) void VLDRestore () { g_vld.RestoreLeakDetectionState(); }
__declspec(dllexport) void VLDDisable () { g_vld.DisableLeakDetection(); }
__declspec(dllexport) UINT VLDGetThreadLeaksCount (UINT threadId) { return (UINT)g_vld.GetThreadLeaksCount(threadId); }
__declspec(dllexport) UINT VLDGetOptions() { return g_vld.GetOptions(); }
__declspec(dllexport) void VLDRefreshModules() { g_vld.RefreshModules(); }
__declspec(dllexport) void VLDSetModulesList(CONST WCHAR *modules, BOOL includeModules) { g_vld.SetModulesList(modules, includeModules); }
__declspec(dllexport) int VLDSetReportHook(int mode, VLD_REPORT_HOOK pfnNewHook) { return g_vld.SetReportHook(mode, pfnNewHook); }
__declspec(dllexport) void VLDSetOptions(UINT option_mask, SIZE_T maxDataDump, UINT maxTraceFrames) { g_vld.SetOptions(option_mask, maxDataDump, maxTraceFrames); }
// Resolve - Creates a nicely formatted rendition of the CallStack, including // symbolic information (function names and line numbers) if available. and // saves it for later retrieval. This is almost identical to Callstack::dump above. // // Note: The symbol handler must be initialized prior to calling this // function. // // - showInternalFrames (IN): If true, then all frames in the CallStack will be // dumped. Otherwise, frames internal to the heap will not be dumped. // // Return Value: // // None. // int CallStack::resolve(BOOL showInternalFrames) { if (m_resolved) { // already resolved, no need to do it again // resolving twice may report an incorrect module for the stack frames // if the memory was leaked in a dynamic library that was already unloaded. return 0; } if (m_status & CALLSTACK_STATUS_STARTUPCRT) { // there is no need to resolve a leak that will not be reported return 0; } if (m_status & CALLSTACK_STATUS_INCOMPLETE) { // This call stack appears to be incomplete. Using StackWalk64 may be // more reliable. Report(L" HINT: The following call stack may be incomplete. Setting \"StackWalkMethod\"\n" L" in the vld.ini file to \"safe\" instead of \"fast\" may result in a more\n" L" complete stack trace.\n"); } int unresolvedFunctionsCount = 0; IMAGEHLP_LINE64 sourceInfo = { 0 }; sourceInfo.SizeOfStruct = sizeof(IMAGEHLP_LINE64); bool skipStartupLeaks = !!(g_vld.GetOptions() & VLD_OPT_SKIP_CRTSTARTUP_LEAKS); // Use static here to increase performance, and avoid heap allocs. // It's thread safe because of g_heapMapLock lock. static WCHAR stack_line[MAXREPORTLENGTH + 1] = L""; bool isPrevFrameInternal = false; bool isDynamicInitializer = false; DWORD NumChars = 0; CriticalSectionLocker<DbgHelp> locker(g_DbgHelp); const size_t max_line_length = MAXREPORTLENGTH + 1; m_resolvedCapacity = m_size * max_line_length; const size_t allocedBytes = m_resolvedCapacity * sizeof(WCHAR); m_resolved = new WCHAR[m_resolvedCapacity]; if (m_resolved) { ZeroMemory(m_resolved, allocedBytes); } // Iterate through each frame in the call stack. for (UINT32 frame = 0; frame < m_size; frame++) { // Try to get the source file and line number associated with // this program counter address. SIZE_T programCounter = (*this)[frame]; DWORD displacement = 0; // It turns out that calls to SymGetLineFromAddrW64 may free the very memory we are scrutinizing here // in this method. If this is the case, m_Resolved will be null after SymGetLineFromAddrW64 returns. // When that happens there is nothing we can do except crash. DbgTrace(L"dbghelp32.dll %i: SymGetLineFromAddrW64\n", GetCurrentThreadId()); BOOL foundline = g_DbgHelp.SymGetLineFromAddrW64(g_currentProcess, programCounter, &displacement, &sourceInfo, locker); if (skipStartupLeaks && foundline && !isDynamicInitializer && !(m_status & CALLSTACK_STATUS_NOTSTARTUPCRT) && isCrtStartupModule(sourceInfo.FileName)) { m_status |= CALLSTACK_STATUS_STARTUPCRT; delete[] m_resolved; m_resolved = NULL; m_resolvedCapacity = 0; m_resolvedLength = 0; return 0; } bool isFrameInternal = false; if (foundline && !showInternalFrames) { if (isInternalModule(sourceInfo.FileName)) { // Don't show frames in files internal to the heap. isFrameInternal = true; } } // show one allocation function for context if (NumChars > 0 && !isFrameInternal && isPrevFrameInternal) { m_resolvedLength += NumChars; if (m_resolved) { wcsncat_s(m_resolved, m_resolvedCapacity, stack_line, NumChars); } } isPrevFrameInternal = isFrameInternal; DWORD64 displacement64; BYTE symbolBuffer[sizeof(SYMBOL_INFO) + MAX_SYMBOL_NAME_SIZE]; LPCWSTR functionName = getFunctionName(programCounter, displacement64, (SYMBOL_INFO*)&symbolBuffer, locker); if (skipStartupLeaks && foundline && beginWith(functionName, wcslen(functionName), L"`dynamic initializer for '")) { isDynamicInitializer = true; } if (!foundline) displacement = (DWORD)displacement64; NumChars = resolveFunction( programCounter, foundline ? &sourceInfo : NULL, displacement, functionName, stack_line, _countof( stack_line )); if (NumChars > 0 && !isFrameInternal) { m_resolvedLength += NumChars; if (m_resolved) { wcsncat_s(m_resolved, m_resolvedCapacity, stack_line, NumChars); } } } // end for loop m_status |= CALLSTACK_STATUS_NOTSTARTUPCRT; return unresolvedFunctionsCount; }
__declspec(dllexport) void VLDMarkThreadLeaksAsReported (UINT threadId) { g_vld.MarkThreadLeaksAsReported(threadId); }
__declspec(dllexport) UINT VLDGetLeaksCount () { return (UINT)g_vld.GetLeaksCount(); }
__declspec(dllexport) BOOL VLDGetModulesList(WCHAR *modules, UINT size) { return g_vld.GetModulesList(modules, size); }
__declspec(dllexport) void VLDMarkAllLeaksAsReported () { g_vld.MarkAllLeaksAsReported(); }
__declspec(dllexport) void VLDSetReportOptions(UINT option_mask, CONST WCHAR *filename) { g_vld.SetReportOptions(option_mask,filename); }
__declspec(dllexport) void VLDDisableModule(HMODULE module) { g_vld.DisableModule(module); }
__declspec(dllexport) void VLDResolveCallstacks() { g_vld.ResolveCallstacks(); }
__declspec(dllexport) void VLDGetReportFilename(WCHAR *filename) { g_vld.GetReportFilename(filename); }
__declspec(dllexport) UINT VLDReportThreadLeaks (UINT threadId) { return (UINT)g_vld.ReportThreadLeaks(threadId); }