有个BUG竟然隐藏了十多年没被发现,这个BUG说起来也简单的很,有个函数接收一个指向某数据结构的指针做参数,但实际初始作者给它传了个指针的指针。形如下面的代码:
#include<stdio.h>
typedef struct DATASTR{
int i1;
int i2;
} DATASTR;
int testIfSpecial(DATASTR* d){
if(d->i1==25){
return 1;
}
return 0;
}
void main(){
DATASTR ds = {1,2};
DATASTR* pds = &ds;
if(testIfSpecial(&pds)){
printf("It's special case\n");
}else{
printf("It's normal case\n");
}
}
由于25是一种特例,大部分情况都不会是25,这样即使传错为&pds(实际判断的是pds这个变量本身的前4个字节是否是25,见下面的调试)也几乎不会影响最终结果。这个BUG估计是初始作者一个手误,竟然隐藏了10多年之久!
(gdb) p pds
$1 = (DATASTR *) 0x7fffffffe328
(gdb) s
testIfSpecial (d=0x7fffffffe320) at UNV34705.c:9
9 if(d->i1==25){
(gdb) p d->i1
$2 = -7384
(gdb) p /x d->i1
$3 = 0xffffe328
当时我们调查这个问题也竟然花了2天,主要原因是只能在AIX机器上的release版本重现,不得不看汇编代码慢慢找原因。
这个问题也给我们一个深刻的教训:
1. 要设计各种CASE,尽量覆盖所有代码。
2. 要注意编译中给出的warning, 每个warning往往预示着一个BUG。比如上面的代码编译器会友善的提醒你:
note: expected ‘DATASTR *’ {aka ‘struct DATASTR *’} but argument is of type ‘DATASTR **’ {aka ‘struct DATASTR **’}