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

Tom*_*m M 5 c++ code-analysis static-code-analysis visual-studio-2015

我已经阅读了很多有关Visual Studio代码分析警告C8386的内容,但是无法弄清楚我的代码中的这个特定问题。我将其简化为以下小程序:

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;
}
Run Code Online (Sandbox Code Playgroud)

分析->运行代码分析->在解决方案中将给出以下警告:

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

这是合法的吗?现在,如果我移动全局变量并将其设置为局部变量,警告将消失!

int main()
{
    unsigned int nNumItems = 0;
...
}
Run Code Online (Sandbox Code Playgroud)

但是我不能像完整的代码那样执行此操作,这是一个成员变量。

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

    nWords = new int[3 + 2 * nNumItems];
Run Code Online (Sandbox Code Playgroud)

但是我不能这样做,因为完整代码中的其他地方都引用了nWords

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

que*_*atl 6

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

现在,看看你如何描述这个警告的行为,我会打赌一个“错误”,或者更确切地说,我应该在静态分析器中用更少的压力和缺陷来说它。

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

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

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

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

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

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

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

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

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

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

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

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

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

  • 静态分析至少与停机问题一样困难。这就是为什么静态分析仪并不总是做得很好的原因。 (3认同)

Ðаn*_*Ðаn 3

由于nNumItems是全局的,代码分析器似乎认为nNumItems在代码执行之前可能在其他地方设置为 SIZE_MAX 。您可以通过以下示例看到这一点:

size_t nNumItems = 0;

void foo()
{
    nNumItems = SIZE_MAX;
}
void bar()
{
    const size_t nTotal = 3 + 2 * nNumItems;
    auto nWords = new int[nTotal];

    nWords[0] = 1;
    nWords[1] = 2;
}

int main()
{
    foo();
    bar();

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

也许最好的解决办法是使用 来回避整个问题std::vector<int>