暂停的危险(2)

主要观点:

  • 介绍了在简单程序中常见的因循环和信号处理未加屏蔽而导致的错误,此类错误不易立即显现,易被忽视。
  • 解释了信号屏蔽与信号处置的区别,屏蔽信号不影响其处置,且信号处置是进程级的,信号掩码是线程级的。
  • 给出了在pause(2)poll(2)select(2)等情况下避免此类错误的方法,如使用sigsuspend(2)sigwait(2)等函数,以及ppoll(2)pselect(2)等变体。
  • 提出了一种针对新添加代码的审查级别的代码检查方法(用 coccinelle 实现),用于检查访问信号处理程序设置的变量并调用特定函数的代码。
  • 指出 dash 已修复该类错误,busybox ash 和 hush 承认存在此问题,glibc 的信息页对此有详细讨论,而 Linux 的pause(2)手册页未提及相关细节,通过运行代码检查脚本发现仍有此类问题存在。

关键信息:

  • 程序中设置信号处理程序后调用pause()会导致在信号到达时阻塞,可能出现各种意外情况。
  • sigsuspend()可用于在等待信号时自动解除信号屏蔽。
  • sigwait()可用于等待特定信号并获取其编号。
  • 对于pollselect,有相应的变体ppollpselect
  • coccinelle 可用于检查特定代码模式,以发现可能存在的此类错误。

重要细节:

  • OpenBSD 对默认处置为停止或继续程序的信号有特殊处理,视为忽略状态。
  • 编写更复杂的 coccinelle 规则时要注意一些特性,如do {} while匹配的合并时间等。
  • 测试发现一些旧代码未使用volatile关键字,可编写更复杂脚本检查从sigaction传递的函数设置的全局变量。
阅读 15
0 条评论