作为一个程序员,必现的 bug 容易排查,最怕遇见非必现 bug,尤其是那种在自己环境上测多少次都没问题,到用户环境偶尔会 crash,无从下手,让人瞬间抓狂。并且像这种非必现 bug 一般很难采用日志的方式来定位。
又或者是那种当程序 crash 的时候,想要做一些操作
今天做项目遇到了这种问题,特此记录一下
Win
windows 实际上已经提供了可以捕捉异常信号的方法 SetUnhandledExceptionFilter() ,当程序 crash 的时候,会调用这个函数,进而执行你想要执行的操作
函数说明
头文件
返回值 (可以理解为 int 类型,一般用不上)
- EXCEPTION_EXECUTE_HANDLER 1 表示我已经处理了异常,可以优雅地结束了
- EXCEPTION_CONTINUE_SEARCH 0 表示我不处理,其他人来吧,于是windows调用默认的处理程序显示一个错误框,并结束
- EXCEPTION_CONTINUE_EXECUTION -1 表示错误已经被修复,请从异常发生处继续执行
SetUnhandledExceptionFilter 官方说明
具体例子
void exceptionHandler(PEXCEPTION_POINTERS excpInfo) {
// 执行自己想要执行的操作。也就是说,当程序 crash 的时候,会执行这块代码
}
LONG WINAPI unhandledException(PEXCEPTION_POINTERS excpInfo = nullptr) {
if (excpInfo == nullptr) {
__try
{
RaiseException(EXCEPTION_BREAKPOINT, 0, 0, nullptr);
} __except(exceptionHandler(GetExceptionInformation()),
EXCEPTION_EXECUTE_HANDLER) {
}
} else {
exceptionHandler(excpInfo);
}
return 0;
}
int main(int argc, char** argv) {
SetUnhandledExceptionFilter(unhandledException);
}
Linux
linux 捕捉信号比 windows 要简单一点,因为 linux 下已经有了一些信号:
SIGINT 2 // interrupt
SIGILL 4 // illegal instruction - invalid function image
SIGFPE 8 // floating point exception
SIGSEGV 11 // segment violation
SIGTERM 15 // Software termination signal from kill
SIGBREAK 21 // Ctrl-Break sequence
SIGABRT 22 // abnormal termination triggered by abort call
SIGABRT_COMPAT 6 // SIGABRT compatible with other platforms, same as SIGABRT
具体例子
void SignalHandler(int sig) {
// 执行自己要执行的操作
}
void InitSignalHandler(void) {
signal(SIGINT, SignalHandler); // Ctrl + c
signal(SIGILL, SignalHandler);
signal(SIGSEGV, SignalHandler);
signal(SIGABRT, SignalHandler);
signal(SIGTERM, SignalHandler); // kill -15
signal(SIGTSTP, SignalHandler); // Ctrl + z (cannot be caught or ignored)
signal(SIGKILL, SignalHandler); // kill -9 (cannot be caught or ignored)
signal(SIGQUIT, SignalHandler);
}
int main() {
InitSignalHandler();
}
如果要知道如何 crash 后的情况下保存 dump 文件。看另一篇文章