gpt4 book ai didi

c - 为什么这段代码用 MSVS2012 触发 "Write overrun warning (C6386)"

转载 作者:行者123 更新时间:2023-12-04 09:24:48 25 4
gpt4 key购买 nike

我有以下一段 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;
}

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

错误是:

C6386 写入“res.c”时缓冲区溢出:可写大小为“4”字节,但可能写入“66052”字节。对 'res.c[66051]' 的写入无效,(可写范围为 0 到 3)

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

最佳答案

我将其记为 Microsoft 产品中的一个潜在错误。它似乎在计算数组索引时使用了 mask.l 的完整值(0x01020304 是十进制 66051),尽管事实上你显然希望将 mask.c[0] 强制为 uint8_t 值。

所以第一步是通知微软。他们可能回来告诉你你错了,并希望给你 C++ 标准部分,说明为什么你所做的是错误的。或者他们可能只是说代码分析工具是“尽力而为”。由于它实际上并没有阻止您进行编译(并且在编译过程中不会产生错误或警告),他们仍然可以声称 VC++ 是兼容的。

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


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

res.c[(uint8_t)(mask.c[0])] = (uint8_t)p[0];

无论如何都是有问题的,因为 (uint8_t)(mask.c[0]) 很可能会计算出大于 3 的值,并且您将在 union 结束后写入案例。

您可能认为确保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];

或其他东西,用于奇怪的字节排序要求。使用此方法根本不会引起分析仪的任何投诉。


如果您真的想要使用当前的mask 方法来完成它,您可以删除分析器警告(至少在我正在使用的 VS2013 中)暂时压制它(一行):

#pragma warning(suppress : 6386)
res.c[mask.c[0]] = p[0];
res.c[mask.c[1]] = p[1];
res.c[mask.c[2]] = p[2];
res.c[mask.c[3]] = p[3];

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

关于c - 为什么这段代码用 MSVS2012 触发 "Write overrun warning (C6386)",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22592110/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com