编译器、discover 和 uncover 可在您的代码中查找静态代码问题、动态内存访问问题以及覆盖问题。本附录介绍了由这些工具发现并由代码分析器分析的特定问题类型。
代码覆盖检查可确定哪些函数未被覆盖。在结果中,发现的代码覆盖问题会标记为 "Uncovered Function"(未覆盖的函数),并且带有潜在覆盖百分比,此百分比是指在添加覆盖相关函数的测试后要添加到应用程序总覆盖中的覆盖百分比。
可能的原因:任何测试都无法执行您的函数,或者您可能忘记了删除死代码或旧代码。
ABR:数组越界读
ABW:数组越界写
DFM:双重释放内存
ECV:显式强制类型转换违规
FMR:读取释放的内存
FMW:写入释放的内存
INF:无限空循环
MLK:内存泄漏
MFR:缺少函数返回值
MRC:缺少 malloc 返回值检查
NFR:返回未初始化的函数
NUL:NULL 指针解除引用,泄漏指针检查
RFM:返回释放的内存
UMR:读取未初始化的内存。未初始化的内存读取位操作
URV:未使用的返回值
VES:超出范围的局部变量使用
本节介绍可能的错误原因以及发生错误的代码示例。
可能的原因:试图读取超出数组边界的内存。
示例:
int a[5]; . . . printf("a[5] = %d\n",a[5]); // Reading memory beyond array bounds
可能的原因:试图写入超出数组边界的内存。
示例:
int a [5]; . . . a[5] = 5; // Writing to memory beyond array bounds
可能的原因:多次使用同一指针调用 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
示例:
int *p = (int*) malloc(sizeof(int)); free(p); . . . // Nothing assigned to p in between printf("p = 0x%h\n",p); // Reading from freed memory
示例:
int *p = (int*) malloc(sizeof(int)); free(p); . . . // Nothing assigned to p in between *p = 1; // Writing to freed memory
示例:
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
可能的原因:沿某些路径退出时缺少返回值。
示例:
#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)); }
可能的原因:访问 C 中 malloc 或 C++ 中新运算符的返回值时未执行 null 检查。
示例:
#include <stdlib.h> int main() { int *p3 = (int*) malloc(sizeof(int)); // Missing null-pointer check after malloc. *p3 = 0; }
可能的原因:访问可能为 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. }
示例:
#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; }
可能的原因:读取尚未初始化的局部数据或堆数据。
示例:
#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" }
可能的原因:读取尚未初始化的局部数据或堆数据。
示例:
int foo(); int main() { foo(); // Return value is not used. }
可能的原因:读取尚未初始化的局部数据或堆数据。
示例:
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:读取未初始化的内存
本节介绍可能的错误原因以及发生错误的代码示例。
可能的原因:试图读取超出数组边界的内存。
示例:
int a[5]; . . . printf("a[5] = %d\n",a[5]); // Reading memory beyond array bounds
可能的原因:试图写入超出数组边界的内存。
示例:
int a [5]; . . . a[5] = 5; // Writing to memory beyond array bounds
可能的原因:向 free()() 或 realloc()() 传递了一个非堆数据指针。
示例:
#include <stdlib.h> int main() { int *p = (int*) malloc(sizeof(int)); free(p+1); // Freeing wrong memory block }
示例:
#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 }
可能的原因:写入超出了动态分配的数组末尾,或者在“红色区域”中。
示例:
#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; }
可能的原因:多次使用同一指针调用 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
示例:
int *p = (int*) malloc(sizeof(int)); free(p); . . . // Nothing assigned to p in between printf("p = 0x%h\n",p); // Reading from freed memory
示例:
int *p = (int*) malloc(sizeof(int)); free(p); . . . // Nothing assigned to p in between *p = 1; // Writing to freed memory
示例:
#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 }
可能的原因:分别从那些没有半字对齐、单字对齐或双字对齐的地址中读取 2 个、4 个或 8 个字节。
示例:
#include <stdlib.h> int main() { int *p = 0; int i = *p; // Read from invalid memory address }
可能的原因:分别从那些没有半字对齐、单字对齐或双字对齐的地址中写入 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
可能的原因:指定的源、目标或长度不正确。如果源和目标重叠,则程序的行为是不确定的。
示例:
#include <stlib.h> #include <string.h> int main() { char *s=(char *) malloc(15); memset(s, 'x', 15); memcpy(s, s+5, 10); return 0; }
示例:
#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 }
可能的原因:读取本地数组时越过了起始或结束边界。
示例:
#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; }
可能的原因:写入本地数组时越过了起始或结束边界。
示例:
#include <stdio.h> int main() { int a[2] = {0, 1}; a[-10] = 2; // Write is beyond stack frame bounds return 0; }
可能的原因:溢出堆块边界或访问已释放堆块的迷失指针。
示例:
#include <stdio.h> #include <stdlib> int main() { int *p = (int*) malloc(sizeof(int)); printf("*(p+1) = %d\n",*(p+1)); // Reading from unallocated memory }
可能的原因:溢出堆块边界或访问已释放堆块的迷失指针。
示例:
#include <stdio.h> #include <stdlib> int main() { int *p = (int*) malloc(sizeof(int)); *(p+1) = 1; // Writing to unallocated memory }
可能的原因:读取尚未初始化的局部数据或堆数据。
示例:
#include <stdio.h> #include <stdlib> int main() { int *p = (int*) malloc(sizeof(int)); printf("*p = %d\n",*p); // Accessing uninitialized data }
AZS:分配零大小
内存泄漏
SMR:推测性未初始化内存读取
本节介绍可能的警告原因以及可能发生警告的代码示例。
示例:
#include <stdlib> int main() { int *p = malloc(); // Allocating zero size memory block }
可能的原因:分配了内存,但是在退出或终止函数之前未释放。
示例:
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
示例:
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);