3

我正在尝试使用 Visual Studio 2012 的代码分析功能。我刚刚在我现有的项目上运行了它们,并在包含我自己的 Knuth 减法 PRNG(又名 RAN3)的实现的部分上发现了一些缓冲区溢出警告(C6385 / C6386) . 但是,我不明白为什么会发生这种情况,因为它看起来很好(我看不到超出范围的读/写)。所以我对那部分做了一个简短的等价物(下),但仍然收到相同的警告,无法弄清楚它们的原因。

int main() {
  unsigned int k = 1U, seed = 12345U, randomNumbers[55];

  randomNumbers[54] = seed;
  for(unsigned int i = 1U; i <= 54U; ++i) {
    unsigned int ii = ((21U * i) % 55U) - 1U;
    randomNumbers[ii] = k;
    k = seed - k;
    seed = randomNumbers[ii];
  }

  return 0;
}

使用上面的代码,我在第 7 行收到 C6386 警告,在第 9 行收到 C6385。这段代码有什么问题?我错过了什么吗?

4

3 回答 3

1

g++ 4.8 和 clang++ 3.3 编译它没有警告或错误(使用 -Wall -Werror)。实际上,我们可以使用 C++11std::array及其at方法来进行边界检查,并且

#include <array>

int main() {
  unsigned int k = 1U, seed = 12345U;
  std::array<int,55> randomNumbers;

  randomNumbers.at(54) = seed;

  for(unsigned int i = 1U; i <= 54U; ++i) {
    unsigned int ii = ((21U * i) % 55U) - 1U;
    randomNumbers.at(ii) = k;
    k = seed - k;
    seed = randomNumbers.at(ii);
  }

  return 0;
}

正如您所声称的那样,不会产生越界访问。我认为你的代码很好。VS 担心该行((21U * i) % 55U) - 1U)可能会导致0 - 1,因为ii是 unsigned int 会溢出。如果您使用整数而不是无符号整数,VS 还会抱怨吗?

(使用 Python,您的索引映射似乎很好:

>>> sorted([21*n % 55 - 1 for n in range(1,55)])
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53]

不应该有任何越界错误,尤其是因为您不会使用无符号整数“达到”-1。)

于 2013-07-20T13:08:45.027 回答
0

打印 ii 的值,看是否超过 54 由这一行计算 unsigned int ii = ((21U * i) % 55U) - 1U;

于 2013-07-20T13:07:31.740 回答
0

首先请了解静态分析的目的,它会对代码库进行分析以检查并确保代码符合他们的行业标准。这是软件质量控制的第一步,并且始终协助动态分析以发现静态分析无法发现的细微问题和漏洞。Fuzzing 用于通过动态分析确保软件的安全性和质量。

静态代码分析也可能导致误报,代码审计员应该忽略这一点。你在这里报告的情况是虚惊一场。

#pragma warning(suppress:6385)

现在让我们深入研究您的场景,静态分析发现您的指令 ((21U * i) % 55U) 可能最终评估为零,这可能导致 ii = -1; 这可能会进一步导致您的软件潜在的崩溃甚至安全漏洞(缓冲区溢出攻击)。静态分析不会执行所有循环迭代(与动态分析不同)来断言每个代码分支都执行良好。

现在让我们谈谈你的代码,我有一些建议和改进给你。请引入一些常量或#define 来保存数组的大小。

#define _SIZE 55U

现在,不要使用硬编码数字“55”和“54”,而是开始在代码中使用 _SIZE。您可以引入实用函数来获取数组的安全边界。

int SafeBoundsInt32(int min, int max, int value)
{
    if (value < 0)
        return 0;
    if (value >= max)
        return max - 1;
    //Valid value
    return value;
}

我将根据介绍的功能更改您的代码。

int main()
{
    unsigned int k = 1U, seed = 12345U, randomNumbers[_SIZE];

    randomNumbers[_SIZE - 1] = seed;
    for (unsigned int i = 1U; i <= _SIZE - 1; ++i)
    {
        unsigned int ii = ((21U * i) % _SIZE) - 1U;
        randomNumbers[SafeBoundsInt32(0, _SIZE, ii)] = k;
        k = seed - k;
        seed = randomNumbers[SafeBoundsInt32(0, _SIZE, ii)];
    }

    return 0;
}

现在执行代码分析,它不会报告任何警告。

于 2017-04-26T16:06:38.383 回答