CERT.STDLIB.SIGNAL

从 SIGFPE、SIGBUS、SIGSEGV、SIGILL、SIGEMT 或 SIGTRAP 的计算异常信号处理程序返回会导致未定义的行为。

CERT.STDLIB.SIGNAL 检查器会标记从 SIGFPE、SIGBUS、SIGSEGV、SIGILL、SIGEMT 和 SIGTRAP 的计算异常信号处理程序返回的情况。 此检查器会将所有带任何指定信号类型的 signal() 调用标记为缺陷。因此,此缺陷的含义是应该检查该代码行,并非表示它一定是缺陷。

漏洞与风险

如果程序从计算异常信号处理程序返回,则会出现未定义的行为。

缓解与预防

如果信号是计算错误的结果,如 SIGFPE、SIGBUS,、SIGSEGV、SIGILL、SIGEMT 或 SIGTRAP,则不要从信号处理程序返回。

漏洞代码示例

复制
     #include <errno.h>
     #include <limits.h>
     #include <signal.h>
     #include <stdlib.h>

     volatile sig_atomic_t denom;

     void sighandle(int s)
     {
        if (denom == 0) {
            denom = 1;
        }
    }

    int main(int argc, char *argv[])
    {
        if (argc < 2) {
            return 0;
        }

        char *end = NULL;
        long temp = strtol(argv[1], &end, 10);

        if (end == argv[1] || 0 != *end ||
            ((LONG_MIN == temp || LONG_MAX == temp) && errno == ERANGE)) {
            /* Handle error */
        }

        denom = (sig_atomic_t)temp;

        signal(SIGFPE, sighandle);  

        long result = 100 / (long)denom;
        return 0;
    }

在此不符合要求的示例中,Klocwork 在第 31 行报告了 CERT.STDLIB.SIGNAL 缺陷,因为该程序从计算信号处理程序返回,这属于未定义的行为。 如果输入 0,并且即使在使用信号处理程序(带信号 SIGFPE)修复错误状况后,上述程序仍未执行预期行为,则此不符合要求的代码示例将无限循环。

修正代码示例

复制
     #include <errno.h>
     #include <limits.h>
     #include <signal.h>
     #include <stdlib.h>

     int main(int argc, char *argv[]) {
       if (argc < 2) {
         return 0;
       }

      char *end = NULL;
      long denom = strtol(argv[1], &end, 10);

      if (end == argv[1] || 0 != *end ||
          ((LONG_MIN == denom || LONG_MAX == denom) && errno == ERANGE)) {
        /* Handle error */
      }

      long result = 100 / denom;
      return 0;
    }

以上代码符合要求,因为该程序未从 SIGFPE 处理程序返回,而是调用了 abort ()、quick_exit() 或退出函数。

相关检查器

  • MISRA.STDLIB.SIGNAL