情况: 我们有一个MFC / C ++ Visual Studio(2005)应用程序,包含许多可执行文件和许多dll,都使用MFC并与DCOM互连。有些正在控制器(w2012)上运行,该控制器控制在WES2009上运行的从属计算机。
问题: 出于诊断目的,我们将minidump嵌入到我们的所有流程中。这个机制在所有进程中都可以正常工作,除了一个:GUI exe。所有进程(包括GUI)使dmp文件 BUT GUI的dmp文件内容似乎不同/错误。当我故意使用例如我们的应用程序崩溃时空指针取消引用,所有进程/ dll(GUI除外)的所有dmp文件都指向原因(空指针取消引用)! GUI进程的dmp文件已创建,可在Visual Studio中打开,但非线程指向原因(空指针取消引用)。 windbg也找不到原因!奇怪的是,当我们手动使用WriteStackDetails()来转储callstack时,它会返回正确的有问题的行!那么为什么MinidumpWriteDump()只能为这一个进程做同样的事情呢?什么可能是歧视因素?任何人都有任何想法?
我们尝试了什么: 我们尝试在所有其他进程和dll中崩溃,除了GUI进程外,它们似乎都运行正常! Unicode /非Unicode似乎并不重要。当我链接包含UnhandledExceptionFilter()和MinidumpWriteDump()的生产代码库时,单独的测试应用程序也能很好地工作。 sub(-sub)dll中的崩溃似乎并不重要。异常处理的项目设置似乎完全相同。任何人都有任何想法?
更多信息和备注:
我们的生产代码(控制器和从属设备)在不同的虚拟框中运行以进行开发。
是的,我们理解minidump理想情况下应该是从另一个进程创建的(某个例子在哪里?wrt进程查询和安全性?)但是在进程中执行它似乎工作总是好的'目前。因此,我们现在接受在极少数情况下可能会挂起的风险。
我的意思是dmp文件内容不同/错误如下: 对于我们的非GUI exe,我们得到以下OK线程/ callstack信息: 0xC0000005:访问冲突读取位置0x00000000。 Studio会自动打开正确的源和"断点"设置为错误的代码行。 在Call stack选项卡中,我在自己的dll中看到了我自己的函数,它导致了崩溃:我的空指针取消引用。 在Threads选项卡中,我还看到了我的活动线程和Location,它还指向崩溃的错误功能。 所以在这种情况下一切都很好用!超级方便的功能!
对于我们的GUI exe,它链接到相同的生产库代码wrt MinidumpWriteDump()和ExceptionHandlingFiler()代码,我们得到以下NOK线程/ callstack信息: our_exe_pid_2816_tid_2820_crash.dmp中0x77d66e29(ntdll.dll)的未处理异常:0xC0150010:当前执行的线程未激活的激活上下文无效 Visual Studio 2005没有显示我的错误代码是原因! 在Call stack选项卡中,我没有看到自己的错误功能。 “调用堆栈”选项卡显示问题出在ntdll.dll中!RtlDeactivateActivationContextUnsafeFast() 我们代码中显示的最顶层函数调用是一个完全不同的gui helper dll,这与我故意引入的崩溃无关! “线程”选项卡也显示相同的内容。
对于这两种情况,我使用相同的visual studio 2005(在w7上运行),并使用相同的符号路径设置!视觉工作室2017也无法分析错误' dmp文件。在上述两个测试之间,没有重建,因此exe / dlls和pdbs之间不会发生不匹配。在一种情况下,它工作正常,在另一种情况下没有!?!
我们使用的精简代码如下所示
typedef BOOL (_stdcall *tMiniDumpWriteDump)(HANDLE hProcess, DWORD dwPid, HANDLE hFile,
MINIDUMP_TYPE DumpType, CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
TCHAR CCrashReporter :: s_szLogFileNameDmp [MAX_PATH]; CRITICAL_SECTION CCrashReporter :: s_csGuard; LPTOP_LEVEL_EXCEPTION_FILTER CCrashReporter :: s_previousFilter = 0; HMODULE CCrashReporter :: s_hDbgHelp = 0; tMiniDumpWriteDump CCrashReporter :: s_fpMiniDumpWriteDump = 0;
CCrashReporter :: CCrashReporter() { LoadDBGHELP();
s_previousFilter = :: SetUnhandledExceptionFilter(UnhandledExceptionFilter); :: InitializeCriticalSection(安培; s_csGuard); }
CCrashReporter ::〜CCrashReporter() { :: SetUnhandledExceptionFilter(s_previousFilter);
...
if(0!= s_hDbgHelp) { FreeLibrary则(s_hDbgHelp); }
:: DeleteCriticalSection(安培; s_csGuard); }
LONG WINAPI CCrashReporter :: UnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo) { :: EnterCriticalSection的(安培; s_csGuard);
...
GenerateMinidump(pExceptionInfo,s_szLogFileNameDmp); :: LeaveCriticalSection(安培; s_csGuard); 返回EXCEPTION_EXECUTE_HANDLER; }
void CCrashReporter :: LoadDBGHELP() { / * ...搜索dbghelp.dll代码... * /
s_hDbgHelp = :: LoadLibrary(strDBGHELP_FILENAME);
if(0 == s_hDbgHelp) { / * ...报告错误... * / }
if(0!= s_hDbgHelp) { ...
s_fpMiniDumpWriteDump = (tMiniDumpWriteDump)GetProcAddress(s_hDbgHelp, "MiniDumpWriteDump");
if (!s_fpMiniDumpWriteDump)
{
FreeLibrary(s_hDbgHelp);
}
else
{
/* ... log ok ... */
}
} }
void CCrashReporter :: GenerateMinidump(const PEXCEPTION_POINTERS pExceptionInfo, LPCTSTR pszLogFileNameDmp) { HANDLE hReportFileDmp(:: CreateFile(pszLogFileNameDmp,GENERIC_WRITE,0,0, CREATE_ALWAYS,FILE_FLAG_WRITE_THROUGH,0));
if(INVALID_HANDLE_VALUE!= hReportFileDmp) { MINIDUMP_EXCEPTION_INFORMATION stMDEI;
stMDEI.ThreadId = ::GetCurrentThreadId();
stMDEI.ExceptionPointers = pExceptionInfo;
stMDEI.ClientPointers = TRUE;
if(!s_fpMiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(),
hReportFileDmp, MiniDumpWithIndirectlyReferencedMemory,
&stMDEI, 0, 0))
{
/* ... report error ...*/
}
else
{
/* ... report ok ... */
}
::CloseHandle(hReportFileDmp);
} 其他 { / * ...报告错误... * / } }