转自: https://blog.youkuaiyun.com/ioio_jy/article/details/50576353
整数分为无符号整数以及有符号整数两种。其中有符号整数会在最高位用0表示正数,用1表示负数,而无符号整数则没有这种限制。另外,我们常见的整数类型有8位(单字节字符、布尔类型)、16位(短整型)、32位(长整型)等。关于整数溢出,其实它与其它类型的溢出一样,都是将数据放入了比它本身小的存储空间中,从而出现了溢出
1、无符号整数的下溢和上溢
无符号整数的下溢问题是由于无符号整数不能识别负数所导致
-
BOOL fun(size_t cbSize) { if( cbSize > 1024 ) { return FALSE; } char *pBuf = new char[cbSize-1]; // 存在溢出隐患 memset(pBuf, 0x90, cbSize-1); ... return TRUE; }
程序并没有对调用结果的正确性进行检测。如果cbSize为0的话,则cbSize-1的值为-1,而memset中第三个参数本身是无符号数,所以会将-1视为正的0xFFFFFFFF,系统无法操作这么大的空间,于是程序也就崩溃了。
无符号整数的上溢
-
BOOL fun(char *s1, size_t len1, char *s2, size_t len2) { if(len1 + len2 + 1 > 1024) { return FALSE; } char pBuf = new char[len1 + len2 + 1]; if(pBuf == NULL) { return FALSE; } memcpy(pBuf, s1, len1); // 存在溢出隐患 memcpy(pBuf + len1, s2, len2); ... return TRUE; }
因为len1和len2都是无符号整数,如果len1=8,len2=0xFFFFFFFF,那么对于len1+len2+1这个运算来说,len2+1会变成0,然后再加上8,那么它的结果就是8。也就是说,new可能只分配了8个字节的空间,但是却要将长为0xFFFFFFFF的字符串复制到这个空间,那么结果就会造成程序的崩溃。
无符号上溢,导致分配的缓冲区过小。
无符号下溢,导致拷贝数据过多
2、符号问题
(1)有符号整数之间的比较。
(2)有符号整数的运算。
(3)无符号整数和有符号整数的对比。
int copy_something(char *buf, int len)
{
char szBuf[800];
if(len > sizeof(szBuf))
{
return -1;
}
// 存在溢出隐患
return memcpy(szBuf, buf, len);
}
- 由于memcpy使用的是无符号整数作为第三个参数的,但是最初的len是有符号整数。假设我们赋予len一个负值,那么就一定能够通过if语句的检测,但是当这个负值被运用在memcpy函数中时,len就可能变成一个非常大的正数,导致缓冲区及其后面的内容被改写,使得程序崩溃。
3、截断问题
截断问题主要发生在高位数的整数(如32位)复制到低位数的整数(如16位)的时候,发生的溢出现象
-
BOOL fun(byte *name, DWORD cbBuf) { unsigned short cbCalculatedBufSize = cbBuf; byte *buf = new byte(cbCalculatedBufSize); if(buf == NULL) { return FALSE; } // 存在溢出隐患 memcpy(buf, name, cbBuf); ... return TRUE; }
对于fun函数来说,如果它的第二个参数cbBuf的值为0x00010020,由于cbCalculatedBufSize只能接收16位的内容,那么在赋值后,该变量的值为0x0020,因此new仅仅分配了0x20这么多的字节,但是name的大小实际为0x00010020,这就造成了缓冲区溢出情况的出现