为什么这段代码会触发"写入溢出警告(C6386)"与MSVS2012

时间:2014-03-23 14:22:43

标签: c

我有以下C代码:

#include <stdint.h>

typedef union{
    uint8_t c[4];
    uint16_t s[2];
    uint32_t l;
}U4;

uint32_t cborder32(uint32_t l)
{
    U4 mask,res;
    unsigned char* p = (unsigned char*)&l;
    mask.l = 0x00010203;
    res.c[(uint8_t)(mask.c[0])] = (uint8_t)p[0]; // <-- this line gives C6386
    res.c[(uint8_t)(mask.c[1])] = (uint8_t)p[1];
    res.c[(uint8_t)(mask.c[2])] = (uint8_t)p[2];
    res.c[(uint8_t)(mask.c[3])] = (uint8_t)p[3];
    return res.l;
}

在对其运行代码分析时会触发Write overrun警告。 http://msdn.microsoft.com/query/dev11.query?appId=Dev11IDEF1&l=EN-US&k=k%28C6386%29&rd=true

错误是:

C6386写入溢出缓冲区溢出,同时写入&#39; res.c&#39;:可写大小为&#39; 4&#39;字节,但&#39; 66052&#39;可能会写入字节。 无效写入&#39; res.c [66051]&#39;,(可写范围为0到3)

我只是不明白为什么......有没有人可以解释我为什么?

1 个答案:

答案 0 :(得分:1)

我将此作为Microsoft产品中的潜在错误。在确定数组索引时似乎使用了mask.l0x01020304为十进制66051)的完整值,尽管事实上您显然希望mask.c[0]被强制为{ {1}}值。

所以第一步是通知微软。他们可能回来告诉你,你错了,并希望给你C ++标准部分,说明为什么你所做的事情是错误的。或者他们可能只是陈述代码分析工具是&#34;只做最好的努力&#34;。由于它实际上并没有阻止你编译(并且它在编译期间没有产生错误或警告),他们仍然可以声称VC ++是合规的。

我希望,当然,他们不会采取这种方法,因为他们非常有兴趣确保他们的工具是最好的。


你应该采取的第二个步骤是问你为什么要首先以这种方式做你正在做的事情。您所拥有的似乎是一个基于掩码的简单字节排序切换器。声明:

uint8_t

无论如何都是有问题的,因为res.c[(uint8_t)(mask.c[0])] = (uint8_t)p[0]; 可能会评估大于3的东西,并且在这种情况下你将在你的工会结束之后写作。

您可能认为确保(uint8_t)(mask.c[0])没有大于mask的字节可能会阻止这种情况,但可能是分析人员不知道这一点。在任何情况下,有很多方法可以切换字节顺序,例如使用3系列函数,或者,因为你的东西无论如何都是硬编码的,只需使用以下方法之一:

htons

或:

res.c[0] = p[0]; res.c[1] = p[1]; res.c[2] = p[2]; res.c[3] = p[3];

或其他,对于更奇怪的字节排序要求。使用这种方法根本不会引起分析仪的任何抱怨。


如果确实希望使用当前的res.c[0] = p[3]; res.c[1] = p[2]; res.c[2] = p[1]; res.c[3] = p[0]; 方法进行操作,您可以暂时删除分析仪警告(至少在我使用的VS2013中)压抑它(一行):

mask

(删除了强制转换,因为类型已经正确)。