☰
  • 首页
  • 规则分类
  • 项目介绍
search
•••

避免异步信号处理产生的数据竞争

15.1 ID_sig_dataRaces
目录 › next › previous

异步信号处理函数的调用会随时打断主程序的流程,当处理函数返回后,主程序在被打断的位置继续执行,这种方式称为“中断(interrupt)”,与执行非并发的线程相似,但没有锁等同步机制,而且信号处理函数本身也可能被中断,所以在信号处理函数中访问共享数据应格外小心。

异步信号处理函数的安全模式:

  • 调用“异步信号安全”函数执行清理或结束进程,如 abort、_Exit 等
  • 对 volatile sig_atomic_t 等类型的共享对象赋值,主程序周期性地检查共享对象并执行相应动作
  • 利用 sigsetjmp、siglongjmp 等函数使流程跳转到主程序中的预定位置
  • 通过管道等方式与主程序通信,向管道写入一个字节,主程序监控该管道并执行相应动作

只应选择其中一种方式,且尽量避免访问共享数据,否则对共享数据的错误处理会使程序产生未定义的行为。

示例:

char msg[32];

void handler(int signum) {
    strcpy(msg, "SIGINT received");   // Non-compliant
}

int main() {
    signal(SIGINT, handler);
    strcpy(msg, "No signal received");   // Race condition
    ....
    printf("%s\n", msg);
}

例中信号处理函数和主程序均访问了共享数据,handler 中的 strcpy 可以在 main 中的 strcpy 执行之前或中途执行,造成非预期的结果。

应改为:

volatile sig_atomic_t flag = 0;

void handler(int signum) {
    flag = 1;                // Compliant
}

int main() {
    signal(SIGINT, handler);
    ....
    printf("%s received\n", flag? "SIGINT": "No signal");
}

注意,sig_atomic_t 由实现定义,其最小值和最大值分别为 SIG_ATOMIC_MIN 和 SIG_ATOMIC_MAX。标准规定,当 sig_atomic_t 是有符号整型时,最小值不会大于 -127,最大值不会小于 127,当 sig_atomic_t 是无符号整型时,最小值为 0,最大值不会小于 255。应避免使用超出范围的数值对 sig_atomic_t 型变量赋值。

相关

ID_dataRaces ID_sig_nonAsyncSafeCall

依据

ISO/IEC 9899:1999 7.14.1.1(5)-undefined ISO/IEC 9899:2011 7.14.1.1(5)-undefined ISO/IEC 14882:2003 1.9(9)-undefined ISO/IEC 14882:2011 1.9(6)-undefined

参考

SEI CERT SIG31-C
Copyright©2024 360 Security Technology Inc., Licensed under the Apache-2.0 license.