C++ 在所有错误情况下,我需要采取什么措施来获取崩溃转储?
我们在Windows上,我们希望为所有应用程序意外退出的场景获得崩溃转储(可能使用C++ 在所有错误情况下,我需要采取什么措施来获取崩溃转储?,c++,windows,visual-c++,crash-dumps,C++,Windows,Visual C++,Crash Dumps,我们在Windows上,我们希望为所有应用程序意外退出的场景获得崩溃转储(可能使用MiniDumpWriteDump) 到目前为止,我们已经确定并建立了以下内容: >代码> SununHANDLeDeXCEPTIONSUMENTROWS/,用于未处理异常(Win32,以及“正常”C++)。 \u set\u无效\u参数\u处理程序用于CRT无效参数处理 \u设置\u abort\u行为加上一个SIGABRT处理程序,以说明调用abort() 我们错过了什么吗?(对一些非合法调用ExitPr
MiniDumpWriteDump
)
到目前为止,我们已经确定并建立了以下内容:
用于CRT无效参数处理\u set\u无效\u参数\u处理程序
加上一个\u设置\u abort\u行为
处理程序,以说明调用SIGABRT
abort()
ExitProcess
、TerminateProcess
或其中一个exit
变体的代码进行模化。)
我将注意到,这里的这个问题与如何获得崩溃转储是正交的。例如,如果您想在
中止
的情况下进行崩溃转储,则必须始终使用\u set\u abort\u behavior
,否则中止只需退出
s即可
我还要注意的是,在Windows7+上,不设置SetUHEF,而只设置通常是一种可行的方法。简单来说,这是一个很高的要求:
- 您不需要使用任何其他的
函数,\u set*
就足够了SetUnhandledExceptionFilter
- C运行时函数如
将禁用全局异常处理程序,您可以使用abort
设置全局异常处理程序。CRT将简单地调用相同的函数willSetUnhandledExceptionFilter
参数,如果CRT导致崩溃,您的异常处理程序将被禁用(未调用)!你能做什么[X]NULL
- 在调用exption处理程序时禁用所有其他正在运行的线程。只需使用
和其他函数查找所有线程。查找此进程,并挂起所有其他正在运行的线程(当然,当前线程除外)CreateToolhelp32Snapshot
- 使用SEH或不使用SEH,除非CRT干涉器,否则将调用全局异常处理程序。不用担心(在大多数情况下)
- 不要在两者之间使用任何CLR,如果任何CLR/托管调用(来自C/C++)介于两者之间,它将不允许异常处理程序调用
- 您无法处理一个异常-堆栈溢出!想想看!在调试器下运行是唯一的解决方案,请参见下文
SetUnhandledExceptionFilter
(在您为自己调用它之后)。虚拟(挂钩)函数将如下所示:
xxx SetUnhandledExceptionFilter_DUMMY(xxx)
{
// Dont do any thing
return NULL;
}
我手头没有API挂钩的链接和详细信息
为什么不尝试让你的应用程序更安全呢
- 更正所有警告(是,甚至级别4)李>
- 使用静态分析。VS本身有(但在更高的版本中,除了2012,所有的变体都有)。还提供了其他SA工具
- 仔细检查代码。这是值得的李>
- 从调试器运行并调试发布版本。使用所有功能
- 检查并纠正所有可能的内存泄漏
- 使用防御性的编程方法。与其检查是否为null,不如使用ASSERT或您自己的ASSERT来保护它。使用断言、日志和函数返回将其打包
所以,如果你对此没意见,你“只是”必须确保你真正感兴趣的崩溃场景会触发。。。这真的让我们回到了这个问题上,但仍然…你可以抓住WER的任何异常。正如您所看到的,CRT有时会强制调用WER
如果希望始终捕获进程中的Exception,则需要防止从CRT调用
SetUnhandledExceptionFilter(NULL)
。有关更多信息,请参阅我的博客:我使用的正是您列出的那些,再加上\u set\u purecall\u handler
,再加上这个方便的代码片段:
void EnableCrashingOnCrashes()
{
typedef BOOL (WINAPI *tGetPolicy)(LPDWORD lpFlags);
typedef BOOL (WINAPI *tSetPolicy)(DWORD dwFlags);
static const DWORD EXCEPTION_SWALLOWING = 0x1;
const HMODULE kernel32 = LoadLibraryA("kernel32.dll");
const tGetPolicy pGetPolicy = (tGetPolicy)GetProcAddress(kernel32, "GetProcessUserModeExceptionPolicy");
const tSetPolicy pSetPolicy = (tSetPolicy)GetProcAddress(kernel32, "SetProcessUserModeExceptionPolicy");
if(pGetPolicy && pSetPolicy)
{
DWORD dwFlags;
if(pGetPolicy(&dwFlags))
{
// Turn off the filter
pSetPolicy(dwFlags & ~EXCEPTION_SWALLOWING);
}
}
}
资料来源:
他的网站上的这些其他文章也帮助我理解了这一点:
SetUnhandledExceptionFilter显然不足以捕获所有意外出口。如果应用程序意外调用纯虚拟函数,则会弹出一个对话框。应用程序将挂起,但不会崩溃。由于没有异常,SetUnhandledExceptionFilter和WER都无法提供帮助。这个主题有一些变化 更糟糕的是,如果在内核回调(如WindowProc)中崩溃,会出现奇怪的情况。如果在64位Windows上的32位应用程序中发生这种情况,则操作系统会捕获异常并继续执行。是的,坠机是无声的。我觉得这很可怕
应详细说明处理这些异常情况所需的所有技巧。要详细介绍所有答案,我发现以下内容最适合100万次以上的安装:
- 以防止出现任何WER对话框
- 对于系统异常
- 对于CRT,参数处理无效
- 加上一个SIGABRT处理程序来解释对abort()的调用
- 所有这些处理程序都应该调用在互斥体/关键部分下执行的函数,以确保sa的其他线程中是否发生任何其他崩溃
#include <signal.h> #include <windows.h> #include <boost/thread/mutex.hpp> void EnableCrashingOnCrashes(); void PreventSetUnhandledExceptionFilter(); static void exceptionHandler(EXCEPTION_POINTERS* excpInfo) { // your code to handle the exception. Ideally it should // marshal the exception for processing to some other // thread and waif for the thread to complete the job } static boost::mutex unhandledExceptionMx; static LONG WINAPI unhandledException(EXCEPTION_POINTERS* excpInfo = NULL) { boost::mutex::scoped_lock lock(unhandledExceptionMx); if (!excpInfo == NULL) { __try // Generate exception to get proper context in dump { RaiseException(EXCEPTION_BREAKPOINT, 0, 0, NULL); } __except (exceptionHandler(GetExceptionInformation()), EXCEPTION_EXECUTE_HANDLER) { } } else { exceptionHandler(excpInfo); } return 0; } static void invalidParameter(const wchar_t* expr, const wchar_t* func, const wchar_t* file, unsigned int line, uintptr_t reserved) { unhandledException(); } static void pureVirtualCall() { unhandledException(); } static void sigAbortHandler(int sig) { // this is required, otherwise if there is another thread // simultaneously tries to abort process will be terminated signal(SIGABRT, sigAbortHandler); unhandledException(); } static void setExceptionHandlers() { SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); SetUnhandledExceptionFilter(unhandledException); _set_invalid_parameter_handler(invalidParameter); _set_purecall_handler(pureVirtualCall); signal(SIGABRT, sigAbortHandler); _set_abort_behavior(0, 0); EnableCrashingOnCrashes(); PreventSetUnhandledExceptionFilter(); }