在整数溢出的结果是什么的 (unsigned int) * (int) ? unsignedint?什么类型阵列操作者索引(operator[])采取为 char*: int, unsigned int 或其他什么东西?

我是审计的下列功能,并突然这个问题出现了。该职能具有的脆弱性在线17。

// Create a character array and initialize it with init[] 
// repeatedly. The size of this character array is specified by 
// w*h.
char *function4(unsigned int w, unsigned int h, char *init)
{
    char *buf;
    int i;

    if (w*h > 4096)
        return (NULL);

    buf = (char *)malloc(4096+1);
    if (!buf)
        return (NULL);

    for (i=0; i<h; i++)
        memcpy(&buf[i*w], init, w);  // line 17

    buf[4096] = '\0';

    return buf;
}

考虑两个 wh 是非常大的未签名的整数。乘法在第9行有机会通过验证。

现在的问题是在线17。乘 int iunsigned int w:如果结果是 int, 可能的是,该产品是否定的,得到在访问的位置之前 buf.如果结果是 unsigned int, ,该产品将始终是积极的,导致在访问这一职位是之后 buf.

很难编写代码,以证明这一点: int 是太大。任何人都不会有思想上这个吗?

是否有任何文件,指定类型的产品?我们搜索它,但是迄今为止还没有找到任何东西。

我想尽可能的漏洞感到关切的是,是否 (unsigned int) * (int) 产生 unsigned intint 不要紧,因为在编制目文件,他们只是字节。以下代码工作上的相同类型的产品:

unsigned int x = 10;
int y = -10;

printf("%d\n", x * y);  // print x * y in signed integer
printf("%u\n", x * y);  // print x * y in unsigned integer

因此,不管是什么类型的乘法运算的回报。它的事项,是否消费者功能的需要 intunsigned.

这里的问题是 怎么不好的功能,或者如何提高职能做的更好。功能无疑具有的脆弱性。问题是有关确切的行为的功能,根据规定的行为标准。

有帮助吗?

解决方案

要回答您的问题:表达式乘以一个int和一个unsigned int类型将在C / C ++一个unsigned int

要回答你的问题暗示,一个体面的方式来应对整数运算可能出现溢出的是使用“IntSafe”从微软设定程序的:

http://blogs.msdn.com/michael_howard /archive/2006/02/02/523392.aspx

这是在SDK中提供,并且包含内嵌的实现,所以你可以研究他们在做什么,如果你在其他平台上。

其他提示

做W * H计算在长长,检查是否比MAX_UINT更大

编辑:替代:如果溢出(W * H)/ H = W(?!?是这样总是如此应,右侧)

确保W * H通过限制w和h不会溢出。

在型w*i的你的情况是无符号的。如果我正确读取的标准,规则是,操作数被转换为更大的类型(与它的符号类型),或对应于该符号的类型无符号的类型(这是在你的情况unsigned int)。

然而,即使是无符号的,它不会阻止环绕(buf之前写入到内存),因为它可能是这种情况(在i386平台,它是),即p[-1]相同p[-1u]。不管怎样,在你的情况下,两个buf[-1]buf[big unsigned number]将是不确定的行为,所以符号/无符号的问题并不重要。

请注意签署在其他情况下/无符号的问题 - 如。 (int)(x*y/2)给出不同的结果取决于类型xy的,甚至在没有未定义的行为。

我将通过检查在第9行溢出解决问题;由于4096是一个非常小的常数,4096 * 4096不会对大多数体系结构(您需要检查),我会做

溢出
if (w>4096 || h>4096 || w*h > 4096)
     return (NULL);

这省去了当wh是0,你可能会想,如果需要检查它的情况。

在一般情况下,你可以检查这样溢出:

if(w*h > 4096 || (w*h)/w!=h || (w*h)%w!=0)

在C/C++的 p[n] 符号是真的快捷方式,以书面方式 *(p+n), 和这个指针算术考虑的迹象。所以 p[-1] 是有效的,并指价值,立即前 *p.

所以,标志真正的问题在这里,结果的算术运算与整数按照一套规则所定义的标准,这被称为整数的促销活动。

看看这个页面: INT02-C。了解整数,转换规则

2度的变化使得它更安全的:

if (w >= 4096 || h >= 4096 || w*h > 4096)  return NULL;

...

unsigned i;

另请注意,这不是少一个坏主意,写入或从过去的缓冲区读取结束。所以,问题是不i是否 w可以变成负的,但无论0 <= I H +瓦特<= 4096成立。

所以它不是重要的类型,但H *我的结果。 例如,它不有所作为这是否是(无符号)为0x80000000或(INT)0x80000000的,该程序将SEG-故障无论如何。

有关C,请参阅 “通常的算术转换”。(C99:章节6.3.1.8,ANSI C K&R A6.5)关于如何数学运算符的操作数进行处理细节

在您的例子,适用下列规则:

C99:

  

否则,如果操作数的类型   与符号整数类型可以表示   所有类型的值   操作数与无符号整型,   然后用无符号整数操作数   类型被转换为的类型   操作数与符号整数类型。

     

否则,两个操作数都转换   到无符号整数型   对应于所述的类型   操作数与符号整数类型。

ANSI C:

  

否则,如果操作数是无符号的int,则另一个被转换成无符号整型。

为什么不直接宣布我为unsigned int?然后问题消失。

在任何情况下,我* W是保证是<= 4096,作为用于此的代码测试,所以它永远不会溢出。

的memcpy(&BUF [I W> -1 I 瓦特<4097 I 瓦特:0:0]时,init,W); 我不认为三重计算第i 瓦特确实降低性能比较)

W * H可能溢出当w和/或h是足够大的和下面的验证可以传递。

9.      if (w*h > 4096)
10.         return (NULL);

在INT,无符号整型混合运算,INT被升高到无符号整型,在这种情况下,负的值“I”将成为大的正值。在这种情况下

&buf[i*w]

将访问一个外边界值的。

无符号算术的模块化进行(或环绕式),因此,两个大的无符号整数的乘积可以很容易地小于4096 int和无符号整型的乘法会导致一个unsigned int(见的第4.5节C ++标准)。

因此,给定大w和h的合适的值,可以确实陷入困境。

确保整数算术不会溢出是困难的。一个简单的方法是将转换为浮点并做了浮点乘法,看到如果结果是在所有合理。至于QWERTY建议,长长的将是可用的,只要您的实现。 (这是在C90和C ++的共同延伸,在C99确实存在,并且将在C ++ 0X。)

有在当前的C1X草案3段上在6.3.1.8常见算术coversions计算(UNSIGNED TYPE1)X(SIGNED TYPE2),N1494,

WG 14:C - 项目状态和里程碑

  

否则,如果具有无符号整数类型的操作数的秩大于或   等于其它操作数的类型的秩,则与操作数   符号整数类型被转换为无符号的操作数的类型   整数类型。

     

否则,如果操作数的与符号整型类型可以表示   所有与无符号整型操作数的类型的值,则   与无符号整数类型操作数转换为的类型   操作数与符号整数类型。

     

否则,两个操作数被转换为无符号整数型   对应于与符号整型操作数的类型。

因此,如果一个是无符号的int和b为INT中,(a * b)中解析应该生成代码(A *(无符号整型)b)中。会溢出,如果B <0或A * B> UINT_MAX。

如果一个是无符号的int和b为长较大尺寸的,(A * B)应该产生((长)的a *(长)b)中。将溢出如果A * B> LONG_MAX或A * B

如果一个是无符号的int和b为长的大小相同,(A * B)应该产生((无符号长)的a *(无符号长整数)b)中。会溢出,如果B <0或A * B> ULONG_MAX。

在您的关于由“索引”期望的类型的第二个问题,回答出现的“整数型”,其允许任何(签名)的整数索引。

  

6.5.2.1数组下标

     

约束

     

1其中一个词语具有类型“‘指针来完成对象类型’”时,其它   表达应具有整数类型,并且将结果的类型是“‘类型’”。

     

语义

     

2后缀表达式后跟表达式在方括号[]是一个下标   阵列对象的元素的指定。下标操作符的定义[]   是,E1 [E2]是相同的(*((E1)+(E2)))。由于转换规则的那   适用于二元+运算,如果E1是一个数组对象(等同地,一个指针到   E2阵列对象的初始元件),并且是一个整数,E1 [E2]指定E2个   E1(从零计数)。元素

它是由以执行静态分析和警告缓冲区溢出的可能性的显影剂当指针表达是一个数组变量和所述索引可以是负的编译器。也是一样关于可能的阵列大小超支警告即使当索引为正或无符号的。

要真正回答你的问题,而无需指定你运行的硬件,你不知道,在准备移植的代码,你不应该依赖于任何特定的行为。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top