6.1 核心案例 1:除零操作 —— 触发 SIGFPE 信号(8 号) 当进程执行 “除以零” 的算术运算时,CPU 的运算单元会检测到该错误,通知 OS,OS 将其映射为SIGFPE > using namespace std; // 自定义SIGFPE信号处理函数 void sigfpe_handler(int signum) { cout << "捕获到信号:" << signum << "(SIGFPE),发生除零错误!" /sig_fpe_divzero 终端输出如下,触发了 SIGFPE 信号: 进程PID:12358,尝试执行除零操作... 捕获到信号:8(SIGFPE),发生除零错误! 如果我们不在处理函数中退出进程,会发现 SIGFPE 信号会被无限触发。
1.当代码中有除以0,或者其他的错误,CPU会产生异常,操作系统OS对于这个异常的处理方法是:对进程发送SIGFPE信号。 2. std::cout << "signo:" << signo << ",CPU异常" << std::endl; sleep(1); } int main() { // 自定义SIGFPE 号信号的行为,让SIGFPE信号不再执行终止进程的操作 ::signal(SIGFPE, handle); int n = 1 / 0; return 0; } 在这里,为什么会循环打印这个了 因为在除0以后,进程PCB中,一直保存这该进程出现了异常,不能继续往下执行,所以CPU每次从信号处理完以后,准备进入主控制流的时候,还会进行检查,结果除0异常的信息还没被处理,那么OS又会给进程发送SIGFPE
SIGFPE错误的算术运算,比如除以零或导致溢出的操作。SIGILL检测非法指令。SIGINT程序终止(interrupt)信号。SIGSEGV非法访问内存。SIGTERM发送到程序的终止请求。 raise() 生成信号,该函数带有一个整数信号编号作为参数,语法如下:int raise (signal sig);在这里,sig 是要发送的信号的编号,这些信号包括:SIGINT、SIGABRT、SIGFPE
SIGFPE 错误的算术运算,比如除以零或导致溢出的操作。 SIGILL 检测非法指令。 SIGINT 程序终止(interrupt)信号。 SIGSEGV 非法访问内存。 raise() 生成信号,该函数带有一个整数信号编号作为参数,语法如下: int raise (signal sig); 在这里,sig 是要发送的信号的编号,这些信号包括:SIGINT、SIGABRT、SIGFPE
在本文中,SIGSEGV(段错误),SIGBUS(内存访问错误),SIGFPE(算数异常)属于这种信号。 进程调用的库发现错误,给自己发送中止信号,默认情况下,该信号会终止进程。 整数除以零 代码示例 int a = 1; int b = a / 0; //整数除以0,产生SIGFPE信号,导致Crash 原因分析 整数除以零总是产生SIGFPE(浮点异常,产生SIGFPE信号时并非一定要涉及浮点算术
std::map<int, std::string> Signals = { {SIGINT, "SIGINT"}, {SIGABRT, "SIGABRT"}, {SIGFPE , "SIGFPE"}, {SIGILL, "SIGILL"}, {SIGSEGV, "SIGSEGV"} // 可以添加其他信号 }; 注册信号处理函数 struct
例如:当进程收到 SIGFPE 浮点异常的信号后,默认操作是对其进行 dump(转储)和退出。信号没有优先级的说法。如果同时为某个进程产生了两个信号,则可以将它们呈现给进程或者以任意的顺序进行处理。 SIGFPE SIGFPE 信号在执行错误的算术运算(例如除以零)时将被发送到进程。 SIGUP 当 SIGUP 信号控制的终端关闭时,会发送给进程。
8)SIGFPE 在发生致命的算术运算错误时发出. 不仅包括浮点运算错误, 还包括溢出及除数为0等其它所有的算术的错误。 9) SIGKILL 用来立即结束程序的运行. 在以上列出的信号中,程序不可捕获、阻塞或忽略的信号有:SIGKILL,SIGSTOP 不能恢复至默认动作的信号有:SIGILL,SIGTRAP 默认会导致进程流产的信号有:SIGABRT,SIGBUS,SIGFPE 非法指令 SIGTRAP 建立CORE文件 跟踪自陷 SIGBUS 建立CORE文件 总线错误 SIGSEGV 建立CORE文件 段非法错误 SIGFPE
2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 8) SIGFPE在发生致命的算术运算错误时发出. 不仅包括浮点运算错误, 还包括溢出及除数为0等其它所有的算术的错误。9) SIGKILL用来立即结束程序的运行. 本信号不能被阻塞、忽略。 在以上列出的信号中,程序不可捕获、阻塞或忽略的信号有:SIGKILL,SIGSTOP不能恢复至默认动作的信号有:SIGILL,SIGTRAP默认会导致进程流产的信号有:SIGABRT,SIGBUS,SIGFPE
2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 8) SIGFPE 在发生致命的算术运算错误时发出. 不仅包括浮点运算错误, 还包括溢出及除数为0等其它所有的算术的错误。 9) SIGKILL 用来立即结束程序的运行. 在以上列出的信号中,程序不可捕获、阻塞或忽略的信号有:SIGKILL,SIGSTOP 不能恢复至默认动作的信号有:SIGILL,SIGTRAP 默认会导致进程流产的信号有:SIGABRT,SIGBUS,SIGFPE
Linux支持的信号列表: ~$ kill -l 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 8) SIGFPE 在发生致命的算术运算错误时发出. 不仅包括浮点运算错误, 还包括溢出及除数为0等其它所有的算术的错误。 9) SIGKILL 用来立即结束程序的运行. 在以上列出的信号中,程序不可捕获、阻塞或忽略的信号有:SIGKILL,SIGSTOP 不能恢复至默认动作的信号有:SIGILL,SIGTRAP 默认会导致进程流产的信号有:SIGABRT,SIGBUS,SIGFPE
signal.h> void handler(int sig) { printf("catch a sig : %d\n", sig); } // v1 int main() { //signal(SIGFPE , handler); // 会跳8号错误:::8) SIGFPE sleep(1); int a = 10; a/=0; while(1); return 0; } 野指针: #include
2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 终端的挂断或进程死亡 SIGINT 2 Term 来自键盘的中断信号 SIGQUIT 3 Core 来自键盘的离开信号 SIGILL 4 Core 非法指令 SIGABRT 6 Core 来自abort的异常信号 SIGFPE
# 异常 类型 异常处理函数 信号 0 除法错误 fault divide_error() SIGFPE 1 Debug trap/fault debug( ) SIGTRAP 2 NMI - nmi( device_not_available( ) - 8 串行处理异常错误 abort doublefault_fn() - 9 协处理器错误 abort coprocessor_segment_overrun( ) SIGFPE general_protection( ) SIGSEGV 14 页错误 fault page_fault( ) SIGSEGV 15 Intel保留 - - - 16 浮点错误 fault coprocessor_error( ) SIGFPE alignment_check( ) SIGBUS 18 机器检查 abort machine_check() - 19 SIMD浮点异常 fault simd_coprocessor_error() SIGFPE
你也可以使用 signal() 函数 截取 SIGFPE 信号。
Native Crash 错误信号 信号 信号值 错误描述 SIGILL 4 非法指令 SIGFPE 4 算数错误,例如:除以零 SIGABRT 6 异常终止 SIGBUS 7 内存错误,不可访问的内存区域
咦,是个SIGFPE信号,你是遇到除数是0的除法了吗?”大哥居然看出了我的来历。 “不错,我确实是因为除了一下0才来到这里的,不知大哥是如何得知的?” “因为你手里是SIGFPE,这是在数学运算出错时才会给进程发送的信号,而通常情况下都是除法除以0时候发生,所以我才猜中的。” ? “大哥,您口中一直所说的信号,到底是个什么意思?” 比如常用的CTRL+C进程就是发送SIGINT信号,kill杀进程就是SIGTERM信号,你现在手里的SIGFPE就是表示有数学运算错误。总而言之,这就是个通知而已” “那这通知发送到了哪里呢?
咦,是个SIGFPE信号,你是遇到除数是0的除法了吗?”大哥居然看出了我的来历。 “不错,我确实是因为除了一下0才来到这里的,不知大哥是如何得知的?” “因为你手里是SIGFPE,这是在数学运算出错时才会给进程发送的信号,而通常情况下都是除法除以0时候发生,所以我才猜中的。” ? “大哥,您口中一直所说的信号,到底是个什么意思?” 比如常用的CTRL+C进程就是发送SIGINT信号,kill杀进程就是SIGTERM信号,你现在手里的SIGFPE就是表示有数学运算错误。总而言之,这就是个通知而已” “那这通知发送到了哪里呢?
GameUtil.cpp ExceptionHandler::ExceptionHandler() { #ifdef __LINUX__ signal(SIGSEGV, Handler); signal(SIGFPE act, &oact); sigaction(SIGABRT, &act, &oact); sigaction(SIGSEGV, &act, &oact); sigaction(SIGFPE
SIGFPE 8 终止进程,建立CORE文件 在发生致命的算术运算错误(Floating-Point Exception)时发出,不仅包括浮点运算错误, 还包括溢出及除数为0等其它所有的算术错误。 ,擦左系统支持的所有信号如下: 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE