我已经阅读了很多关于 Visual Studio 代码分析警告 C6386 的内容,但无法用我的代码找出这个特定问题。我已将其简化为以下小程序:
unsigned int nNumItems = 0;
int main()
{
int *nWords=nullptr;
unsigned int nTotal;
nTotal = 3 + 2 * nNumItems;
nWords = new int[nTotal];
nWords[0] = 1;
nWords[1] = 2; // this is line 18, warning C6386
delete[] nWords;
return 0;
}
分析->运行代码分析->解决方案将给出以下警告:
file.cpp(18):警告 C6386:写入“nWords”时缓冲区溢出:可写大小为“nTotal*4”字节,但可能写入“8”字节。
这是合法的吗?现在,如果我移动我的全局变量并使其成为本地变量,警告就会消失!
int main()
{
unsigned int nNumItems = 0;
...
}
但我不能像在完整代码中那样做,这是一个成员变量。
同样,如果我将 nTotal 的定义移动到“ new int ”中,我也可以删除警告:
nWords = new int[3 + 2 * nNumItems];
但我不能这样做,因为 nWords 在完整代码的其他地方被引用。
这只是 Visual Studio 静态代码分析器的问题,还是此代码的合法问题?
原文由 Tom M 发布,翻译遵循 CC BY-SA 4.0 许可协议
静态代码分析很难,跟踪像
3 + 2 * nNumItems
这样的表达式的可能值很难,跟踪 实际可能值 通常几乎是不可能的。这就是为什么它是一个 警告,而不是错误。到目前为止,显而易见。现在,看看你如何描述这个警告的行为,我会打赌一个“错误”,或者更确切地说,我应该在静态分析器中以较少的压力和缺陷说出来。
我可以在原始
nWords[1] = 2
和全局nNumItems
上看到此警告背后的一些想象中的可能原因。它们真的很奇怪,我认为合理的分析师不会将这样的规则添加到分析器中。另外,我是对的,那么您也应该在nWords[0] = 1
上看到这些警告。你没有看到它们的事实证明我的想法是错误的,所以我停在这里。
相反,我想专注于 静态代码分析很难。分析器及其规则编写得多么好并不重要。在某些情况下,它会出错,而在其他情况下,它会简单地失败,甚至无法猜测,而在其他情况下,它会超时并放手。直到我们在 AI 方面取得突破或在解决 NP 难题方面取得突破之前,您可能不得不习惯这样一个事实,即当您使用静态代码分析器时,您必须以他们可以理解的方式编写代码,不要指望他们能理解你能写的一切。
最后一个想法,当我看到这个错误时:
我注意到的第一件事是
nTotal*4
和8
。如果您使用的是硬编码值,您可能会收到类似的错误您看到
nTotal*4
的事实似乎意味着静态代码分析器实际上无法猜测nTotal
下的值,并将其保留为符号名称,形成了一个无法与8
。因此,分析器做了它唯一能做的事情——它报告了一个问题,并尽可能地描述了它。不过,这只是我的猜测。// 编辑 - 丹关于猜测的答案的注释:nNumItems <- SIZE_MAX
我实际上认为他可能与 SIZE_MAX 差不多。我玩了一些微软的 SAT 求解器,他们做得很好的一件事是求解整数域中的一组约束。实际上
unsigned int x = SIZE_MAX; std::cout << ( (3+2*x)*sizeof(int) );
打印 4(当然),这是x
的唯一值,其表达式小于 8。我很确定我玩过的 microsoft 的约束求解器可以在检查整数环域中
((3+2*x)*4) < 8
的可满足性时检测到这种情况 - 因此可能会发出警告。但是,我希望警告包含结果并打印如下内容:因为分析仪已经有了这些信息。但是,那是……可能对它期望太高了。它背后的开发人员可能不会考虑格式化如此详细的警告消息,或者认为当前的消息格式更加用户友好。