Почему этот код генерирует предупреждения о переполнении буфера (C6385 / C6386) при анализе кода в Visual Studio 2012?

Я пытаюсь использовать функцию анализа кода в Visual Studio 2012. Я просто запустил их в моем существующем проекте и обнаружил некоторые предупреждения о переполнении буфера (C6385/C6386) на части, которая содержит мою собственную реализацию вычитающего PRNG Кнута (он же RAN3). Тем не менее, я не могу понять, почему это происходит, потому что это выглядит хорошо (я не вижу вне чтения / записи). Поэтому я сделал короткий эквивалент (ниже) этой части, но все еще получил те же предупреждения и не могу выяснить причину их.

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

С кодом выше я получил предупреждение C6386 в строке 7 и C6385 в строке 9. Что не так с этим кодом? Я что-то пропустил?

2

Решение

g ++ 4.8 и clang ++ 3.3 компилируют это без предупреждения или ошибки (используя -Wall -Werror). На самом деле, мы можем использовать C ++ 11 std::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 является неподписанным 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, используя неподписанные целые.)

1

Другие решения

выведите значение ii, посмотрите, выходит ли оно за пределы 54
Рассчитано по этой строке
без знака int ii = ((21U * i)% 55U) — 1U;

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

Выполните анализ кода сейчас, и он не будет предупрежден.

-1