Linux 常见异常信号速查与辨析
是什么
Linux 内核在检测到进程违规操作时,会向该进程发送对应的异常信号(Signal)。理解这些信号的含义和区别,是定位崩溃、调试内存问题和编写健壮程序的基础。本文梳理开发中最常遇到的 7 种异常信号,重点辨析容易混淆的信号对。
信号速查表
| 信号 | 编号 | 全称 | 触发原因 | 典型场景 |
|---|---|---|---|---|
| SIGSEGV | 11 | Segmentation Violation | 访问未映射或无权限的内存地址 | 空指针解引用、野指针、数组越界、栈溢出 |
| SIGBUS | 7 | Bus Error | 硬件层面的内存访问错误 | 内存未对齐访问、mmap 文件被截断后访问、物理内存故障 |
| SIGABRT | 6 | Abort | 进程主动调用 abort() 终止 | assert 失败、glibc/ASan 检测到堆损坏(double-free 等) |
| SIGFPE | 8 | Floating-Point Exception | 算术运算异常 | 整数除以零、浮点溢出/无效操作 |
| SIGILL | 4 | Illegal Instruction | CPU 无法识别当前指令 | 二进制损坏、跳转到非代码区域、不支持的指令集 |
| SIGTRAP | 5 | Trace/Breakpoint Trap | 断点或单步调试陷阱 | GDB 断点、__builtin_trap()、sanitizer 内部检查点 |
| SIGSYS | 31 | Bad System Call | 非法或不存在的系统调用 | seccomp 沙箱拦截、glibc 与内核版本不匹配 |
以上信号的默认动作均为终止进程并生成 core dump(受 ulimit 限制)。SIGKILL(9) 和 SIGSTOP(19) 不可捕获,其余可通过 sigaction() 自定义处理。
核心辨析:三组易混淆信号
SIGSEGV vs SIGBUS
这是最常混淆的一对。本质区别在于错误发生的层级不同:
- SIGSEGV:MMU 页表层面拒绝。地址在逻辑上就不该访问(未映射、权限不足)。x86/ARM 上绝大多数内存访问错误都是 SEGV。
- SIGBUS:硬件总线层面失败。地址在页表中合法,但物理总线无法完成传输。典型触发条件:
- ARM/RISC-V 上的未对齐访问(x86 通常自动处理不报错)
- mmap 的文件被其他进程截断后继续访问
- 物理内存硬件故障
实践判断:x86 上遇到 SIGBUS 优先考虑 mmap 文件问题;ARM 上优先考虑对齐问题;其余情况大概率是 SIGSEGV。
SIGABRT vs SIGSEGV
- SIGABRT 是软件主动自杀:运行时库(glibc、ASan、assert 宏)检测到不可恢复的错误后,故意调用 abort() 发出。收到 ABRT 意味着"程序自己发现了问题并选择终止"。
- SIGSEGV 是硬件被动捕获:CPU/MMU 直接报错,程序本身没有意识到出了问题。
实践意义:看到 SIGABRT 应优先查看 stderr 输出(glibc/ASan 通常会打印详细诊断信息);看到 SIGSEGV 则需要 core dump + GDB 回溯。
SIGFPE 的名称陷阱
SIGFPE 全称含 “Floating-Point”,但实际涵盖所有算术异常,包括整数除以零。历史上浮点异常是最常见的算术错误,信号名沿用至今。不要因为名字里带"浮点"就忽略整数运算的可能性。
ASan 与信号的关系
AddressSanitizer 会将大部分本应触发 SIGSEGV/SIGBUS 的错误转化为 SIGABRT,并在 abort 前输出结构化诊断报告(含调用栈、内存布局、分配/释放历史)。这就是为什么开启 ASan 后看到的通常是 ABRT 而非 SEGV——ASan 抢先检测到了问题并主动终止。
调试流程建议
- 确认信号类型:
dmesg | tail或/proc/<pid>/status中的 SigCgt/SigIgn 掩码 - 获取 core dump:
ulimit -c unlimited+coredumpctl list - 分析现场:
gdb ./binary core→bt full查看完整调用栈 - 启用 sanitizer:编译时加
-fsanitize=address获得更精确的错误定位 - 区分环境:x86 vs ARM 对 SIGBUS 的行为差异显著,注意目标架构
未完全理解的部分
- SIGBUS 在不同架构上的精确触发条件仍有差异,需查阅具体 CPU 手册
- seccomp-bpf 返回 SIGSYS 时的 errno 传递机制尚未深入研究
- 实时信号(SIGRTMIN~SIGRTMAX)在应用层的使用场景和注意事项待补充