Как найти (все) целые переполнения в программе на C?

Я работаю над большим проектом, который обычно работает очень хорошо, но показывает серьезные проблемы, когда размер входных данных превышает некоторые ограничения.

Эти проблемы (предположительно) возникают только из-за подписанных целых переполнений, таких как:

int a, o;
// Initialize a and o
int x = (a+o) >> 1);

Очевидно, как только сумма переполнений a и o (становится больше 2 ^ 31-1), x уже не является средним для a и o.

Есть ли общий способ найти все эти целые переполнения в запущенной программе?

Я имею в виду такой инструмент, как Valgrind или расширение GDB, которое разбивается на каждую целочисленную арифметическую команду, принимает параметры и сравнивает правильный результат (рассчитанный с использованием более крупного типа данных или арифметики произвольной точности) с фактическим результатом. Если результаты отличаются друг от друга, он должен выдать предупреждение, вызвать разрыв отладки или что-то вроде этого.

Я знаю, как проверить одну арифметическую инструкцию для переполнения (например, проверку знака для дополнений), однако из-за большого количества кода это не жизнеспособное решение для меня, чтобы пройти весь проект и вставить проверочный код везде вручную.

Ответы

Ответ 1

Для большой базы кода Coverity - хороший инструмент. Я не уверен, что обнаружит переполнение целых чисел all или нет, но стоит попробовать.

Ответ 2

Вам нужно проработать весь код и выяснить, какой предел для входа пользователя и проверить вход. Вам также может потребоваться перезаписать некоторые алгоритмы, чтобы уменьшить проблемы с переполнением.

В качестве примера, который вы даете, не работает для отрицательных значений, вы все равно должны использовать unsigned int, предоставляя вам дополнительный порядок.

Edit: gcc имеет параметр -ftrapv, но этот обычно ничего не делает работает только с -O0. Если вы используете подход переполнения ловушек, когда они происходят, вам все еще нужно хорошее знание кода, чтобы полностью его протестировать.

Ответ 3

Как насчет script, который проходит через код и заменяет все "a + b" на DEBUGADD (a, b) - где вы можете сделать:

#ifdef DEBUG
int addFn(int a, int b) {
  long long m;
  int n;
  m = (long long)a + (long long)b;
  n = a + b;
  if (m != (long long)n)
    printf("PANIC!\n");
  return n;
}
#define DEBUGADD(a,b) addFn(a,b)
#else
#define DEBUGADD(a,b) ((a)+(b))
#endif