Visual Studio 2015 代码分析 C6386 警告缓冲区溢出

我已经阅读了很多关于 Visual Studio 代码分析警告 C8386 的内容,但无法找出我的代码的这个特定问题.我将其简化为以下小程序:

I've read a lot about the Visual Studio Code Analysis warning C8386, but can't figure out this particular issue with my code. I've reduced it to the following small program:

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;
}

Analyze->Run Code Analysis->On Solution 会给出如下警告:

Analyze->Run Code Analysis->On Solution will give the following warning:

file.cpp(18):警告 C6386:写入nWords"时缓冲区溢出:可写大小为nTotal*4"字节,但可能写入8"字节.

file.cpp(18): warning C6386: Buffer overrun while writing to 'nWords': the writable size is 'nTotal*4' bytes, but '8' bytes might be written.

这合法吗?现在,如果我移动全局变量并将其设为本地变量,警告就会消失!

Is this legit? Now, if I move my global variable and make it local, the warning disappears!

int main()
{
    unsigned int nNumItems = 0;
...
}

但是我不能像在完整代码中那样这样做,这是一个成员变量.

But I can't do this as in the full code, this is a member variable.

同样,如果我将 nTotal 的定义移动到new int"中,我也可以删除警告:

Likewise, if I move the definition of nTotal into the 'new int', I can also remove the warning:

    nWords = new int[3 + 2 * nNumItems];

但我不能这样做,因为 nWords 在完整代码的其他地方被引用.

But I can't do this as nWords is referred to in other places in the full code.

这只是 Visual Studio 静态代码分析器的问题,还是此代码的合法问题?

Is this just an issue with the Visual Studio static code analyzer, or is it a legitimate issue with this code?

推荐答案

静态代码分析很难,追踪像 3 + 2 * nNumItems 这样的表达式的可能值很难,追踪 实际可能的值通常几乎是不可能的.这就是为什么它是警告,而不是错误的原因.到目前为止,显而易见.

Static code analysis is hard, tracing possible values of an expression like 3 + 2 * nNumItems is hard, and tracing actual possible values is often near to impossible. This is why it is a warning, not error. So far for the obvious.

现在,看看您如何描述此警告的行为,我敢打赌是错误",或者更确切地说,我应该在静态分析器中以较少的压力和不足来说.

Now, looking at how you describe that this warning behaves, I would bet on a "bug", or rather, I should say it with less stress, deficiency, in the static analyzer.

我可以在原始 nWords[1] = 2 和全局 nNumItems 上看到此警告背后的一些想象的可能原因.它们真的很奇怪,我认为一个合理的分析师不会向分析器添加这样的规则.另外,我是对的,那么您也应该在 nWords[0] = 1 上看到这些警告.

I can see some imaginary possible causes behind this warning on original nWords[1] = 2 and global nNumItems. They are really weird and I don't think a reasonable analyst would add such rules to the analyzer. Also, I were right, then you should have these warnings on nWords[0] = 1 as well.

你没有看到它们的事实证明我的想法是错误的,所以我到此为止.

The fact that you don't see them on that proves my ideas wrong, so I stop here.

相反,我想专注于静态代码分析很难.分析器及其规则编写得有多好并不重要.在某些情况下,它会出错,而在其他情况下,它只会失败甚至无法猜测,而在其他情况下,它会超时并放手.直到我们在 AI 方面取得突破或在解决 NP 难题方面取得突破,您可能不得不习惯这样一个事实,即当您使用静态代码分析器时,您必须以他们可以理解的方式编写代码,不要指望他们能理解你能写的一切.

Instead, I would like to focus on that static code analysis is hard. It does not matter how well-written the analyzer and its rules are. For some cases, it will make errors, and for other cases it will simply fail and won't be even able to guess, and for other cases it will timeout and just let go. Until we have some breakthrough in AI or breakthrough in solving NP-hard problems, you will probably have to get used to the fact, that when you are using static code analyzers, then you have to write code in a way that they can comprehend, not count on that they can comprehend everything you can write.

最后的想法,当我看到这个错误时:

Last thought, when I see this error:

file.cpp(18):警告 C6386:写入nWords"时缓冲区溢出:可写大小为nTotal*4"字节,但可能写入8"字节.

file.cpp(18): warning C6386: Buffer overrun while writing to 'nWords': the writable size is 'nTotal*4' bytes, but '8' bytes might be written.

我注意到的第一件事是nTotal*48.如果您使用的是硬编码值,您可能会收到类似

the first thing that I notice is nTotal*4 and 8. If you were using a hardcoded values, you would probably get an error like

file.cpp(18):警告 C6386:写入nWords"时缓冲区溢出:可写大小为1024"字节,但可能会写入8192"字节.

file.cpp(18): warning C6386: Buffer overrun while writing to 'nWords': the writable size is '1024' bytes, but '8192' bytes might be written.

您看到 nTotal*4 的事实似乎暗示静态代码分析器实际上未能猜测 nTotal 下的值,而是将其保留为符号名称,形成了8无法比拟的表达.因此,分析仪做了它唯一能做的事情――它报告了一个问题,并尽可能地描述了它.不过,这只是我的猜测.

The fact that you see nTotal*4 seems to imply that the static code analyzer actually failed to guess the value under nTotal and it left it as symbolic name, which formed an expression incomparable to 8. Therefore, the analyzer did theonly thing it could - it reported a problem, and described it as well as it could. Still, it's just my guess.

//编辑 - Dan 关于猜测的回答的注释:nNumItems <- SIZE_MAX

// EDIT - note for Dan's answer about guessing: nNumItems <- SIZE_MAX

我实际上认为他可能对 SIZE_MAX 很感兴趣.我玩了一些微软的 SAT 求解器,他们做得很好的一件事是解决整数域中的一组约束.实际上 unsigned int x = SIZE_MAX;std::cout <<( (3+2*x)*sizeof(int) ); 打印 4(当然),这是 x 的唯一一个表达式小于 8 的值.

I actually think that he's may be quite about the SIZE_MAX. I played a bit with some SAT solvers from Microsoft, and one thing they did well was solving set of constraints in integer domain. Actually unsigned int x = SIZE_MAX; std::cout << ( (3+2*x)*sizeof(int) ); prints 4 (of course), and that is the only value of x for which the expression is less than 8.

我很确定我玩过的微软约束求解器在检查 ((3+2*x)*4) < 的可满足性时可以检测到这种情况.8 在整数环域中 - 因此可能会发出警告.但是,我希望警告包含结果并打印如下内容:

I'm pretty sure that the constraint solver from microsoft I played with can detect this case when checking satisfiability of ((3+2*x)*4) < 8 in integer ring domain - hence the warning could be issued. However, I would expect the warning to include the result and print something like:

nTotal*4 <8 当 {nTotal=1,nNumItems=4294967295}`

nTotal*4 < 8 when {nTotal=1,nNumItems=4294967295}`

因为分析器已经有了这些信息.但是,那是......可能对它期望过高.其背后的开发人员可能不会想到格式化如此详细的警告消息,或者认为消息的当前格式对用户更友好.

since the analyzer had would have this information already. But then, that's.. probably expecting too much from it. Developers behind it probably wouldn't have thought of formatting such detailed warning message, or considered current format of the message to be more user-friendly.

相关文章