strace 是 linux 下用于跟踪系统调用和信号的诊断工具,可监控进程与内核交互全过程,包括系统调用参数、返回值、错误码、执行耗时及接收的信号(如 sigsegv),支持过滤(-e trace=signal)、附加运行中进程(-p pid)和子进程跟踪(-f)。

调试信号响应异常的应用程序,核心在于确认信号是否被正确生成、投递、检测和处理。问题往往不出在“有没有注册 handler”,而在于信号被阻塞、覆盖、时机错位或 handler 本身不安全。
检查信号是否真正到达进程
用 strace 观察系统调用与信号交互:
- 运行
strace -e trace=signal,kill,rt_sigprocmask,rt_sigaction ./your_app - 关注输出中是否有
--- SIGSEGV {si_signo=SIGSEGV, ...} ---这类行 —— 表示信号确实被内核投递到了进程 - 若看到
rt_sigprocmask(SIG_BLOCK, [SIGSEGV], ...),说明该信号曾被主动阻塞,可能一直 pending 未处理 - 若无任何 SIGxxx 出现,但预期应触发(如访问非法地址),说明硬件异常根本没产生信号 —— 可能是内存映射方式(如 MAP_NORESERVE)、CPU 特性(如 SMAP)或内核配置抑制了 fault 报告
验证信号处理函数是否被调用及是否安全
自定义 handler 必须满足可重入性要求,否则极易引发二次崩溃:
Linux AI 服务器 — 将 Linux 服务器转换为本地 AI 推理集群。使用 systemd、NVIDIA CUDA 实现无头 Linux AI,零 GUI 开销。
- 避免在 handler 中调用
printf、malloc、write(非 async-signal-safe 函数);只用write(2)、siglongjmp、raise等有限函数 - 用
sigaction替代过时的signal():它能精确控制sa_mask(屏蔽哪些信号)、sa_flags(如SA_RESTART避免系统调用中断后不恢复) - 在 handler 开头加简单日志:
write(STDERR_FILENO, "SIGSEGV caught\n", 15);,确认执行路径 - 若 handler 调用
backtrace(),需确保编译时加-rdynamic且未开启-fomit-frame-pointer,否则栈信息为空
排查父子进程或线程间的信号继承与竞争
fork 后子进程会继承父进程的信号掩码和 handler,但行为常被误判:
- SIGCHLD 默认被忽略,若父进程未显式设置 handler 或调用
waitpid(-1, ..., WNOHANG),子进程退出后信号会 pending,后续 fork 可能因资源耗尽失败 - 多线程程序中,信号默认只投递给一个线程(通常是主线程)。若想定向投递,需用
pthread_kill();若需所有线程都响应,应使用sigwait()在专用线程中同步等待 - 测试框架常通过
fork + exec启动被测程序,并在父进程中wait。若测试框架自身安装了 SIGSEGV handler 并未屏蔽该信号,它可能截获本该发给子进程的信号,导致误判
利用 core dump 和调试器还原现场
当信号导致崩溃时,core 文件是最直接的证据:
- 先启用 core:
ulimit -c unlimited,并确认/proc/sys/kernel/core_pattern指向可写路径 - 崩溃后用
gdb ./your_app core.xxx加载,执行info registers和bt full查看 fault 发生时的指令地址、寄存器值与完整调用栈 - 若 stack trace 显示在
sigreturn或 handler 返回途中崩溃,大概率是 handler 破坏了栈或寄存器(如未正确保存/恢复浮点状态) - 对比正常运行时的
cat /proc/[pid]/status | grep Sig输出(SigQ、SigPnd、ShdPnd、SigBlk 等字段),可判断 pending 信号是否堆积、哪些被阻塞










