整数算术溢出问题的分析
Posted 灬F灬
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了整数算术溢出问题的分析相关的知识,希望对你有一定的参考价值。
这篇对整数的一些基本运算产生的溢出问题进行分析。
当你进行加减乘除运算的时候,如果这个数字很大,运算产生的结果就可能会出乎你最初设计程序的预料,这对程序来说是一种很可怕的漏洞,这让一些恶意的访问者对程序作出一些破坏性的事情,这样造成的危害可能是很大的。
这里先定义一些宏定义作为返还值:
#define OVERFLOW 1 //算术溢出(正溢出) #define NOT_OVERFLOW 0 //未溢出 #define NEGATIVE_OVERFLOW -1 //负溢出
当进行无符号整数加法计算的时候。
无符号整数的范围是 0 ≤ x ≤ UMax ,UMax = 2w - 1 (w是当前类型的位数) ,如果两个数相加的结果小于任何一个数,那么就可以判断算术溢出。判断的代码如下:
int uadd_ok(unsigned x, unsigned y) { unsigned uadd=x+y; if( uadd < x || uadd < y) return OVERFLOW; return NOT_OVERFLOW; }
当进行有符号整数加法计算的时候。
有符号整数的范围是 TMin ≤ x ≤ TMax ,TMin = -2w-1 ,TMax = 2w-1 - 1 那么为什TMax的绝对之为什么会比TMin的绝对之小一,那么假设 w= 4 观察一下。因为有符号数的最高位是符号位,所以TMax的最高位就是 0 ,为了让数字更大那么其余就应该是 1 ,那么 TMax (4) = 0111 = 22+21+20=23-1=2w-1-1。有符号数的负数部分一般都是用补码表示的 TMin 最高位就需要是 1 因为只有最高位是代表负数,其余位都是正数,最后这个数的值是各个位的值的加和得到的,所以其余位都需要是 0 ,那么 TMin(4)=1000= -23 = -2w-1 。那么判断有符号数加法的代码一种错误如下,它利用了阿贝尔群得知补码加法的时候,(x+y)-y=y 在溢出的情况下是成立的。所以就有可能出现如下的代码:
int tadd_ok(int x, int y) { int sum=x+y; return (sum - y == y) && (sum - x == y) ; }
但是这个代码的返回值永远是 1, 因为在不溢出的情况下表达式成立是显而易见的。
所以就需要考虑多方面的因素了,两个数都大于零的时候,如果结果是负数那么可判断溢出。如果两个数都是负数,结果为正数那么判断也溢出。
代码如下:
int tadd_ok(int x, int y) { int tadd=x+y; if( x > 0 && y > 0 ) if( tadd < 0 ) return OVERFLOW; if( x < 0 && y < 0 ) if( tadd >= 0 ) return NEGATIVE_OVERFLOW; return NOT_OVERFLOW; }
当进行有符号减法运算的时候。
这个时候你可能想像这样调用写好的 tadd_ok( x, -y ); 函数,但是实际上在一些情况下这是错误的,因为 TMin = -TMin ,这样你想要的 -TMin 就没有变成 | TMin | 却变成了TMin 所以就需要增加一些判断。
代码如下:
int tsub_ok(int x, int y) { if( y != 0 && y == -y ) { if( x >= 0 ) return OVERFLOW; return NOT_OVERFLOW; } return tadd_ok(x,-y); }
当是乘法运算的时候不论有符号还是无符号,溢出的部分都是直接截掉的。
当然乘法是可以使用 ( x * y ) / x = y 进行判断的因为溢出的时候这是不成立的,当然你需要保证 x , y 不是零 ,如果是零作为除数是不合理的。
所以可以写出如下代码:
int tmult_ok(int x, int y) { int tmult=x*y; if( x != 0 && y!= 0 ) { if( tmult / x == y ) return NOT_OVERFLOW; return OVERFLOW; } return NOT_OVERFLOW; }
以上是关于整数算术溢出问题的分析的主要内容,如果未能解决你的问题,请参考以下文章