这里没有软件测试的泛泛理论,只有博主的最佳实践。 博主的研究方向为静态分析和性能测试,致力于各种测试工具的引入、评估和开发。 本博的测试文章均为作者原创,转载请务必注明出处。

C/C++ 代码错误总结(1)

上一篇 / 下一篇  2008-01-24 14:39:32 / 个人分类:静态分析

C/C++代码错误总结(1

今天看了一个公司产品的视频介绍,正好最近要总结C/C++项目中经常发现的代码错误,特写出来与大家分享。

1 FORWARD_NULL

通常发生的情况是,一个指针先被判断是否等于NULL,然后指针被非法引用。

非法引用NULL的指针会导致程序崩溃。程序员在判断指针是否等于NULL时,没能正确的处理好,或者是忘记了NULL在代码路径的情况。

举例说明:

int forward_null_example1(int *p) {

int x;

if( p == NULL ) {

x = 0;

} else {

x = *p;

}

x += fn();

*p = x; // ERROR: p is potentially NULL

return 0;

}

 

2 USE_AFTER_FREE

使用已被释放的内存、同一指针被释放多次。

当内存被释放后,就不能再被安全的使用。而同一内存的多次释放通常会导致未定义的行为,包括内存冲突和程序崩溃。

引用已释放的指针也是非常危险的,因为指针的值不确定或者指针指向任意内存的位置。

在多线程的程序中,多次释放同一内存非常危险,因为已释放的内存可能已被另一线程申请,再次释放可能导致该线程的内存也被释放,在这种情况下,该线程使用已释放的内存,可能导致紊乱,同时很难被编译器跟踪。

举例说明:

void fun(int * p) {

free (p);

int k = *p; // p is dereferenced after it is freed.

}

int f(void *p) {

if(some_error()) {

free(p);

return -1;

}

return 0;

}

void g() {

void *p = malloc(42);

if(f(p) < 0) {

free(p); // double free of pointer "p"

// previously freed in call to "f".

}

use(p);

}

3      RESOURCE_LEAK

资源泄漏(内存泄漏)指变量在出了自己的作用范围后,占用的资源仍然驻守在内存里,没有被释放。

严重的内存泄漏能导致进程崩溃,即便是很小的内存泄漏,在系统长时间运行没有重启后,也会产生错误。如果内存泄漏是由用户输入或者网络数据触发,还会成为“拒绝服务攻击”的对象。

文件句柄或者网络套接字的泄漏会导致程序崩溃、拒绝服务攻击或者打开其他文件或套接字失败。操作系统通常会限制进程的文件句柄和套接字个数。当达到限制的最大值时,进程要申请新的资源时,首先要关闭一些已打开的资源。如果进程中存在资源泄漏,进程自己将没有办法回收这些资源,除非强行终止该进程。

多数情况下,这些泄漏通常发生在某个错误的路径,比如说,某个异常处理的分支。这种情况下,正确的做法应该是将程序跳转(GOTO)到该函数的出口,出口处应释放这些资源。

C++中,RAIIthe Resource Acquisition Is Initialization)机制能够自动的释放资源。RAII包括类的一个申请资源的构造函数和释放资源的析构函数。当一个类的局部变量声明后,当离开该变量的作用范围后,RAII会自动调用其析构函数释放资源,这同样也会保护throw异常导致的泄漏。

举例说明:

int leak_example(int c) {

void *p = malloc(10);

if(c)

return -1; // "p" is leaked

/* ... */

free(p);

return 0;

}

int wrong_error_check() {

void *p = malloc(10);

void *q = malloc(20);

if(!p || !q)

return -1; // "p" or "q" may be leaked if the other is NULL

/*...*/

free(q);

free(p);

return 0;

}

int test(int i) {

void *p = malloc(10);

void *q = malloc(4);

if(i > 0)

p = q; // p is overwritten and is the last pointer

else  // to the allocated memory

free(q);

free(p);

return 0;

}

void test(int c) {

FILE *p = fopen("foo.c", "rb");

if(c)

return; // leaking file pointer "p"

fclose(p);

}

4      NULL_RETURN

函数的返回值可能是NULL,所以使用函数返回值的变量一定要首先检查是否是NULL,否则就可能出错。

程序员经常不会去检查函数的返回值,而是直接以危险的方式去使用,可能会由于对NULL的非法引用,导致程序崩溃。

举例:

void bad_malloc() {

// malloc returns NULL on error

struct some_struct *x = malloc(sizeof(*x), GFP_KERNEL);

// ERROR: memset dereferences x

memset(x, 0, sizeof(struct some_struct);

}

 

今儿先写这么多,以后再续。

TAG: 静态分析

 

评分:0

我来说两句

Open Toolbar