Oracle® Solaris Studio 12.4:代码分析器用户指南

退出打印视图

更新时间: 2014 年 10 月
 
 

代码分析器分析的错误

编译器、discoveruncover 可在您的代码中查找静态代码问题、动态内存访问问题以及覆盖问题。本附录介绍了由这些工具发现并由代码分析器分析的特定问题类型。

代码覆盖问题

代码覆盖检查可确定哪些函数未被覆盖。在结果中,发现的代码覆盖问题会标记为 "Uncovered Function"(未覆盖的函数),并且带有潜在覆盖百分比,此百分比是指在添加覆盖相关函数的测试后要添加到应用程序总覆盖中的覆盖百分比。

可能的原因:任何测试都无法执行您的函数,或者您可能忘记了删除死代码或旧代码。

静态代码问题

静态代码检查可查找以下类型的错误:

  • ABR:数组越界读

  • ABW:数组越界写

  • DFM:双重释放内存

  • ECV:显式强制类型转换违规

  • FMR:读取释放的内存

  • FMW:写入释放的内存

  • INF:无限空循环

  • MLK:内存泄漏

  • MFR:缺少函数返回值

  • MRC:缺少 malloc 返回值检查

  • NFR:返回未初始化的函数

  • NUL:NULL 指针解除引用,泄漏指针检查

  • RFM:返回释放的内存

  • UMR:读取未初始化的内存。未初始化的内存读取位操作

  • URV:未使用的返回值

  • VES:超出范围的局部变量使用

本节介绍可能的错误原因以及发生错误的代码示例。

数组越界读 (ABR)

可能的原因:试图读取超出数组边界的内存。

示例:

    int a[5];
    . . .
    printf("a[5] = %d\n",a[5]);  // Reading memory beyond array bounds

数组越界写 (ABW)

可能的原因:试图写入超出数组边界的内存。

示例:

    int a [5];
     . . .
     a[5] = 5; // Writing to memory beyond array bounds

双重释放内存 (DFM)

可能的原因:多次使用同一指针调用 free()()。在 C++ 中,多次对同一指针使用 delete 操作符。

示例:

    int *p = (int*) malloc(sizeof(int));
     free(p);
     . . .       // p was not signed a new value between the free statements
     free(p); // Double freeing memory

读取释放的内存 (FMR)

示例:

    int *p = (int*) malloc(sizeof(int));
    free(p);
    . . .  // Nothing assigned to p in between
    printf("p = 0x%h\n",p); // Reading from freed memory 

写入释放的内存 (FMW)

示例:

    int *p = (int*) malloc(sizeof(int));
     free(p);
     . . .        // Nothing assigned to p in between
     *p = 1; // Writing to freed memory 

无限空循环 (INF)

示例:

    int x=0;
    int i=0;
    while (i200) {
      x++; } // Infinite loop 

内存泄漏

可能的原因:分配了内存,但是在退出或终止函数之前未释放。

示例:

    int foo()
    {
     int *p = (int*) malloc(sizeof(int));
     if (x) {
      p = (int *) malloc(5*sizeof(int));  // will cause a leak of the 1st malloc
      }  
    }                                      // The 2nd malloc leaked here

缺少函数返回值 (MFR)

可能的原因:沿某些路径退出时缺少返回值。

示例:

    #include <stdio.h>
    int foo (int a, int b) 
    {
      if (a) 
        { 
           return b; 
        }
    }            // If foo returns here, the return is uninitialized
    int main ( )
    {
        printf("%d\n", foo(0,30));
    }

缺少 malloc 返回值检查 (MRC)

可能的原因:访问 C 中 malloc 或 C++ 中新运算符的返回值时未执行 null 检查。

示例:

    #include <stdlib.h>
    int main()
    {
     int *p3 = (int*) malloc(sizeof(int)); // Missing null-pointer check after malloc.
     *p3 = 0;
    }  

泄漏指针检查器:Null 指针解除引用 (NUL)

可能的原因:访问可能为 null 的指针,或在指针从不为 null 的情况下针对 null 进行冗余检查。

示例:

    #include <stdio.h>
    #include <stdlib.h>
    int gp, ctl;
    int main()
    {
     int *p = gp;
     if (ctl)
      p = 0;
     printf ("%c\n", *p); // May be null pointer dereference
     if (!p)
      *p = 0; // Surely null pointer dereference

    int *p2 = gp;
    *p2 = 0; // Access before checking against NULL. 
    assert (p2!=0);

    int *p3 = gp;
    if (p3) {
      printf ("p3 is not zero.\n");
    }
    *p3 = 0; // Access is not protected by previous check against NULL. 
    }

返回释放的内存 (RFM)

示例:

    #include <stdlib.h>
    int *foo ()
    {
     int *p = (int*) malloc(sizeof(int));
     free(p);
     return p; // Return freed memory is dangerous
    }
    int main()
    {
     int *p = foo();
     *p = 0;
    }

读取未初始化的内存 (UMR)

可能的原因:读取尚未初始化的局部数据或堆数据。

示例:

    #include <stdio.h>
    #include <stdlib.h>
     struct ttt {
        int a: 1;
        int b: 1;
     };

     int main()
     {
       int *p = (int*) malloc(sizeof(int));
       printf("*p = %d\n",*p); // Accessing uninitialized data 

       struct ttt t;
       extern void foo (struct ttt *);

       t.a = 1;
       foo (&t); // Access uninitialized bitfield data "t.b"
     }

未使用的返回值 (URV)

可能的原因:读取尚未初始化的局部数据或堆数据。

示例:

    int foo();
   int main()
   {
      foo(); // Return value is not used.
   }

超出范围的局部变量使用 (VES)

可能的原因:读取尚未初始化的局部数据或堆数据。

示例:

    int main() 
   {
      int *p = (int *)0;
      void bar (int *);
      {
        int a[10];
        p = a;
      } // local variable 'a' leaked out
      bar(p);
    }

动态内存访问错误

动态内存访问检查查找以下类型的错误:

  • ABR:数组越界读

  • ABW:数组越界写

  • BFM:释放错误的内存块

  • BRP:错误的重新分配地址参数

  • CGB:损坏的保护块

  • DFM:双重释放内存

  • FMR:读取释放的内存

  • FMW:写入释放的内存

  • FRP:释放的重新分配参数

  • IMR:无效的内存读取

  • IMW:无效的内存写入

  • MLK:内存泄漏

  • OLP:重叠源和目标

  • PIR:部分初始化的读取

  • SBR:堆栈越界读

  • SBW:堆栈越界写

  • UAR:读取未分配的内存

  • UAW:写入未分配的内存

  • UMR:读取未初始化的内存

本节介绍可能的错误原因以及发生错误的代码示例。

数组越界读 (ABR)

可能的原因:试图读取超出数组边界的内存。

示例:

    int a[5];
    . . .
    printf("a[5] = %d\n",a[5]);  // Reading memory beyond array bounds

数组越界写 (ABW)

可能的原因:试图写入超出数组边界的内存。

示例:

    int a [5];
     . . .
     a[5] = 5; // Writing to memory beyond array bounds

释放错误的内存块 (BFM)

可能的原因:free()()realloc()() 传递了一个非堆数据指针。

示例:

    #include <stdlib.h>
    int main()
    {
     int *p = (int*) malloc(sizeof(int));
     free(p+1); // Freeing wrong memory block
    }

错误的重新分配地址参数 (BRP)

示例:

    #include <stdlib.h>
    int main()
    {
     int *p = (int*) realloc(0,sizeof(int));
     int *q = (int*) realloc(p+20,sizeof(int[2])); // Bad address parameter for realloc 
    }

损坏的保护块 (CGB)

可能的原因:写入超出了动态分配的数组末尾,或者在“红色区域”中。

示例:

    #include <stdio.h>
    #include <stdlib.h>

    int main() {
     int *p = (int *) malloc(sizeof(int)*4);
     *(p+5) = 10; //  Corrupted array guard block detected (only when the code is not annotated)
     free(p);

     return 0;
    }

双重释放内存 (DFM)

可能的原因:多次使用同一指针调用 free()()。在 C++ 中,多次对同一指针使用 delete 操作符。

示例:

    int *p = (int*) malloc(sizeof(int));
     free(p);
     . . .       // p was not assigned a new value between the free statements
     free(p); // Double freeing memory

读取释放的内存 (FMR)

示例:

    int *p = (int*) malloc(sizeof(int));
     free(p);
     . . .  // Nothing assigned to p in between
     printf("p = 0x%h\n",p); // Reading from freed memory

写入释放的内存 (FMW)

示例:

    int *p = (int*) malloc(sizeof(int));
     free(p);
     . . .        // Nothing assigned to p in between
     *p = 1; // Writing to freed memory 

释放的重新分配参数 (FRP)

示例:

   #include <stdlib.h>

   int main() {
     int *p = (int *) malloc(sizeof(int));
     free(0);
     int *q = (int*) realloc(p,sizeof(it[2])); //Freed pointer passed to realloc
   }

无效的内存读取 (IMR)

可能的原因:分别从那些没有半字对齐、单字对齐或双字对齐的地址中读取 2 个、4 个或 8 个字节。

示例:

    #include <stdlib.h>
    int main()
    {  
      int *p = 0;
      int i = *p;   // Read from invalid memory address 
    }

无效的内存写入 (IMW)

可能的原因:分别从那些没有半字对齐、单字对齐或双字对齐的地址中写入 2 个、4 个或 8 个字节。向文本地址写入、向只读数据区 (.rodata) 写入或向已由 mmap 设置为只读的页面写入。

示例:

     int main()
   {
     int *p = 0;
     *p = 1;  // Write to invalid memory address 
   }

内存泄漏

可能的原因:分配了内存,但是在退出或终止函数之前未释放。

示例:

       int foo()
   {
     int *p = (int*) malloc(sizeof(int));
     if (x) {
      p = (int *) malloc(5*sizeof(int));  // will cause a leak of the 1st malloc
     }  
   }                                      // The 2nd malloc leaked here

重叠源和目标 (OLP)

可能的原因:指定的源、目标或长度不正确。如果源和目标重叠,则程序的行为是不确定的。

示例:

    #include <stlib.h>
    #include <string.h>
    int main() {
      char *s=(char *) malloc(15);
      memset(s, 'x', 15);
      memcpy(s, s+5, 10);
      return 0;
    }

部分初始化的读取 (PIR)

示例:

    #include <stdio.h>
   #include <stdlib.h>
    int main()
   { 
     int *p = (int*) malloc(sizeof(int));
     *((char*)p) = 'c';
     printf("*(p = %d\n",*(p+1)); // Accessing partially initialized data 
   }

堆栈越界读 (SBR)

可能的原因:读取本地数组时越过了起始或结束边界。

示例:

    #include <stdio.h>

   int main() {
     int a[2] = {0, 1};
     printf("a[-10]=%d\n",a[-10]); //  Read is beyond stack frame bounds

     return 0;
   }

堆栈越界写 (SBW)

可能的原因:写入本地数组时越过了起始或结束边界。

示例:

    #include <stdio.h>

    int main() {
     int a[2] = {0, 1};
     a[-10] = 2; //  Write is beyond stack frame bounds

     return 0;
   }

读取未分配的内存 (UAR)

可能的原因:溢出堆块边界或访问已释放堆块的迷失指针。

示例:

    #include <stdio.h>
    #include <stdlib>
   int main()
   {
     int *p = (int*) malloc(sizeof(int));
     printf("*(p+1) = %d\n",*(p+1)); // Reading from unallocated memory
   }

写入未分配的内存 (UAW)

可能的原因:溢出堆块边界或访问已释放堆块的迷失指针。

示例:

    #include <stdio.h>
    #include <stdlib>
   int main()
   {
    int *p = (int*) malloc(sizeof(int)); 
     *(p+1) = 1; // Writing to unallocated memory 
  }

读取未初始化的内存 (UMR)

可能的原因:读取尚未初始化的局部数据或堆数据。

示例:

    #include <stdio.h>
    #include <stdlib>
   int main()
   {
    int *p = (int*) malloc(sizeof(int));
    printf("*p = %d\n",*p); // Accessing uninitialized data
  }

动态内存访问警告

动态内存访问检查可查找以下类型的警告:

  • AZS:分配零大小

  • 内存泄漏

  • SMR:推测性未初始化内存读取

本节介绍可能的警告原因以及可能发生警告的代码示例。

分配零大小 (AZS)

示例:

    #include <stdlib>
    int main()
    {
      int *p = malloc(); // Allocating zero size memory block
    }

内存泄漏 (MLK)

可能的原因:分配了内存,但是在退出或终止函数之前未释放。

示例:

    int foo()
    {
     int *p = (int*) malloc(sizeof(int));
     if (x) {
      p = (int *) malloc(5*sizeof(int));  // will cause a leak of the 1st malloc
     }  
    }                                     // The 2nd malloc leaked here

推测性内存读取 (SMR)

示例:

    int i;
    if (foo(&i) != 0)  /* foo returns nonzero if it has initialized i */
    printf("5d\n", i);

编译器可能会针对上面的源代码生成下面的等效代码:

    int i;
    int t1, t2'
    t1 = foo(&i);
    t2 = i; /* value in i is loaded. So even if t1 is 0, we have uninitialized read due to speculative load */
    if (t1 != 0) 
    printf("%d\n", t2);