BUG
野火烧不尽,春风吹又生
——BUG
0x00000001
1 | void inplace_swap(int *x, int *y) |
目的:使用上述reverse_array()函数实现将一个数组的元素头尾两端依次对调
漏洞:当数组长度为奇数时,该函数总会将数组中正中元素置零
原因:设数组长度为2*k+1,当first=last=k时,调用inplace_swap()函数意味着a[k]元素与自身异或,结果总为0
解决方案:
1 | for (first = 0, last = cnt - 1; first < last; first++,last--) |
0x00000002
1 | float sum_elements(float a[], unsigned length) |
目的:该函数试图计算数组a中所有元素的和,其中元素数量由参数length给出
漏洞:当length值为0时,运行该函数会遇到一个内存错误
原因:因为参数length是无符号的,计算0-1将使用无符号运算,这等价于模数加法,结果为32位最大无符号数,而任何数都是小于或等于该值的,所以该判断条件总为真,代码试图访问数组a的非法元素
解决方案:
1 | for (i = 0; i < length; i++) |
0x00000003
1 | size_t strlen(const char *s); |
目的:比较s串是否长于t串
漏洞:当s串长度小于t串长度时,比较函数会不正确地返回1
原因:由于strlen()被定义为产生一个无符号结果,差和比较都采用无符号运算计算。当s比t短的时候,strlen(s)-strlen(t)的差会为负,但是变成了一个很大的无符号数,且大于零
解决方案:
1 | int strlonger(char *s, char *t) |
0x00000004
1 | int tadd_ok(int x, int y) |
目的:测试两数相加是否溢出,无溢出返回1
漏洞:上述测试函数总返回1
原因:补码加法是一个阿贝尔群,因此无论加法是否溢出,表达式(x+y)-x求值总为y,(x+y)-y求值总为x
解决方案:
1 | int tadd_ok(int x, int y) |
0x00000005
1 | int tsub_ok(int x, int y) |
目的:测试x-y是否溢出,无溢出返回1
漏洞:该函数会给出正确的值,除了当y=TMin时
原因:当y=TMin,有-y也等于TMin,因此函数tadd_ok()会认为只要x是负数时,就会溢出;而x为非负数时,不会溢出。实际上,情况恰恰相反才对:当x为负数时,tsub_ok(x,TMin)应该为1;而当x为非负数时,它应该为0
这个例子说明,在函数的任何测试过程中,TMin都应该作为一种测试情况