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

时间:2017-01-30 19:19:49

标签: c++ visual-studio-2015 code-analysis static-code-analysis

我已经阅读了很多关于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;
}

Analyze->运行代码分析 - > On Solution将发出以下警告:

  

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静态代码分析器的一个问题,还是这个代码的合法问题?

4 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:2)

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

现在,看看你如何描述这个警告的行为,我会赌一个&#34; bug&#34;或者更确切地说,我应该在静态分析器中用更少的压力,缺陷来说明。

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

你没有看到他们的事实证明我的想法是错的,所以我就此止步。

相反,我想专注于静态代码分析很难。分析仪及其规则的编写顺序并不重要。在某些情况下,它会产生错误,而对于其他情况,它会简单地失败并且甚至无法猜测,而对于其他情况,它会超时并且放开。在我们在人工智能方面取得一些突破或在解决NP难题方面取得突破之前,你可能必须习惯这样一个事实:当你使用静态代码分析器时,你必须以他们能够理解的方式编写代码,不要指望他们能理解你能写的一切。

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

  

file.cpp(18):警告C6386:在写入&n;&#39;时,缓冲区溢出:可写的大小是&n;总长* 4&#39;字节,但是&#39; 8&#39;可能会写入字节。

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

的错误
  

file.cpp(18):警告C6386:在写入&n;&#39;时,缓冲区溢出:可写大小为&#39; 1024&#39;字节,但是&#39; 8192&#39;可能会写入字节。

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

//编辑 - 请注意Dan关于猜测的答案:nNumItems&lt; - SIZE_MAX

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

我非常确定我在使用微软的约束求解器在检查整数环域中x的可满足性时可以检测到这种情况 - 因此可以发出警告。但是,我希望警告包含结果并打印如下内容:

  

nTotal * 4&lt; 8当{nTotal = 1,nNumItems = 4294967295}`

因为分析仪已经有了这些信息。但那时候,那可能是对它的期待太多了。它背后的开发人员可能不会考虑格式化这样详细的警告消息,或者认为消息的当前格式更加用户友好。

答案 2 :(得分:0)

使全局变量为常量:

const unsigned int nNumItems = 0;

答案 3 :(得分:0)

这可能不是一个常见的解决方案,但就我而言,VS正在生成我认为是误报的警告。重新启动VS后,警告消失了。