You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为什么我注册的SIGFPE信号处理函数仅会被触发一次?

问题根因
  • POSIX 标准默认规则:当信号处理函数被触发执行时,触发该处理的信号会被自动加入进程的信号阻塞掩码,直到处理函数正常返回才会自动解除,除非在 sigaction 配置中显式指定 SA_NODEFER 标志。
  • 你在 SIGFPE 的处理函数 sigAction 中直接调用 longjmp 跳出处理函数,没有走信号处理的正常返回流程,内核自动添加的 SIGFPE 阻塞位没有被清除。
  • 你使用的标准 setjmp/longjmp 接口不会保存和恢复进程的信号掩码,所以跳回 calc 函数的错误处理分支后,SIGFPE 仍然处于阻塞状态。
  • 你看到的 longjmp 之后掩码为 0x0 是错误打印导致的假象:sigset_t 是操作系统定义的不透明类型,不能直接用 %x 格式化打印,你实际打印的是结构体起始地址的部分内容,不是真实的信号掩码值。

后续每次调用 raise(SIGFPE) 时,由于 SIGFPE 处于阻塞状态,信号只会被挂起不会递送给进程,因此处理函数永远不会被触发。

修复方案

你可以选择以下任意一种方案修复:

  1. 替换信号安全的跳转接口:将 setjmp/longjmp 替换为 sigsetjmp/siglongjmp,调用 sigsetjmp 时第二个参数传非0值,跳回时会自动恢复调用时的信号掩码:
    • 全局变量 static jmp_buf begin 修改为 static sigjmp_buf begin
    • setjmp(begin) 修改为 sigsetjmp(begin, 1)
    • longjmp(begin, 1) 修改为 siglongjmp(begin, 1)
  2. 添加SA_NODEFER标志:在 sigaction 配置中添加 SA_NODEFER 标志,进入 SIGFPE 处理函数时不会自动阻塞 SIGFPE:
    act.sa_flags |= SA_SIGINFO | SA_NODEFER;
    
  3. 手动解除阻塞:在 setjmp 返回非0的错误处理分支中,手动调用 sigprocmask 解除 SIGFPE 的阻塞。

内容的提问来源于stack exchange,提问作者Bugsy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 12:54:02