CXX.ERRNO.NOT_SET

调用库函数前 Errno 未重置为零

CXX.ERRNO.NOT_SET 检查器会标记调用库函数前未将 errno 的值重置为零的情况。

漏洞与风险

errno 的值可能是以前调用库函数时错误设置的。如果代码在调用库函数后检查 errno 的值,而没有先将其重置,则可能导致代码的错误执行。

缓解与预防

在调用设置 errno 值的库函数前,始终将 errno 的值重置为零。

漏洞代码示例 1

复制
  #include <errno.h>
  #include <limits.h>
  #include <stdlib.h>
    
  void func(const char *c_str) {
    unsigned long number;
    char *endptr;
     
    number = strtoul(c_str, &endptr, 0);
   if (errno == ERANGE) {
     /* Handle error */
   } else {
     /* Computation succeeded */
   }
 }

在此不符合要求的示例中,代码无法在调用 strtoul() 前将 errno 的值设置为零。如果发生错误,strtoul() 会返回有效值 (ULONG_MAX),因此 errno 是确定 strtoul() 是否成功运行的唯一方法。

修正代码示例 1

复制
  #include <errno.h>
  #include <limits.h>
  #include <stdlib.h>
    
  void func(const char *c_str) {
    unsigned long number;
    char *endptr;
    
    errno = 0;
   number = strtoul(c_str, &endptr, 0);
   if (errno == ERANGE) {
     /* Handle error */
   } else {
     /* Computation succeeded */
   }
 }

在此修正代码示例中,代码在调用 strtoul() 前将 errno 的值设置为零,然后在调用后检查 errno 的值。

漏洞代码示例 2

复制
  #include <errno.h>
  #include <stdio.h>
    
  void func(const char *filename) {
    FILE *fileptr;
   
    errno = 0;
    fileptr = fopen(filename, "rb");
    if (errno != 0) {
     /* Handle error */
   }
 }

在此不符合要求的示例中,代码可能无法诊断错误,因为即使发生错误,fopen() 也可能无法设置 errno 的值。

修正代码示例 2

复制
  #include <stdio.h>
    
  void func(const char *filename) {
    FILE *fileptr = fopen(filename, "rb");
    if (fileptr == NULL)  {
      /* An error occurred in fopen() */
    }

C 标准在描述 fopen() 时没有提到 errno。在此符合要求的示例中,代码使用调用 fopen() 的结果来确定故障,并且不检查 errno 的值。

扩展

此检查器可通过 Klocwork 知识库 (KB) 进行扩展。有关详情,请参阅调整 C/C++ 分析。