Будут ли какие-либо программы обнаруживать переполнение буфера в структуре C/C++?

Рассмотрим следующую программу:

struct abc
{
    int x[5];
    int y[5];
};

int main()
{
    struct abc test;
    test.y[0] = 10;
    printf("%d", test.x[5]);
}

(заимствовано у Правильно ли перебирать один элемент структуры для просмотра другого?)

BoundsChecker не обнаруживает это как переполнение. Существуют ли программы, которые обнаружат этот тип ошибки программирования?

2 ответа

clang даже без специальных флагов:

$ clang example.c -o example
example.c:13:18: warning: array index of '5' indexes past the end of an array
      (that contains 5 elements) [-Warray-bounds]
    printf("%d", test.x[5]);
                 ^      ~
example.c:5:5: note: array 'x' declared here
    int x[5];
    ^
1 warning generated.

При компиляции как C++ выводится то же предупреждение.

То, что мы видим здесь, является неприятным, малоизвестным секретом о BoundsChecker: он вообще не дает возможности видеть членов структуры. Если вы объявите массив как часть структуры, независимо от того, будет ли эта структура выделена автоматически или динамически, BoundsChecker увидит структуру как большой двоичный объект. Если вы выйдете за пределы этой структуры, она сообщит о проблеме. В противном случае нет.

Тем не менее, несколько лет назад мы написали некоторый код, который поставляется вместе с продуктом в настоящее время, и который может быть вызван скрытой опцией конфигурации. Если вы должны были вручную вставить строку EnableStructureMemberEnumeration=1 в [BC MemoryTracker] раздел файла конфигурации проекта (.dpbcd), то вы обнаружите, что продукт может видеть элементы структуры (главным образом, структуры и массивы), если эта структура выделяется автоматически (в стеке).

Однако эта опция не полностью готова к прайм-тайм. У него есть проблемы с очень сложными классами и структурами, которые можно найти в STL. Кроме того, в приведенном выше конкретном тестовом примере есть еще одна проблема. В целом он не может различить массив, который запускает структуру / класс, и сам объект класса. Оба имеют один и тот же адрес в памяти. Но рассмотрим этот код:

struct _Type {
  int Array[5];
} Objects[10];

struct _Type *pObject = &Objects[5];
int *pInt = &Objects[0].Array[5];

В обоих случаях мы видим один и тот же адрес, первый раз со смещением 100, второй раз со смещением 20. Первый, если оценивается относительно Array, является недействительным, но если оценивается по отношению к Objects, является действительным. Что за плохая программа?

Да, и еще одна вещь: BoundsChecker обычно игнорирует доступ к первому элементу за концом массива. Это потому, что существует так много кода, где итератор проходит только один элемент после конца. Это был огромный источник ложных ошибок, поэтому кто-то изменил его, чтобы жаловаться только в том случае, если переполнение переместилось в следующее место (и дальше). Проблема в том, что вы увеличили итератор, но действительно ли вы собираетесь его использовать?

Итак, ответ, на данный момент, на вопрос заключается в том, что BoundsChecker действительно поддерживает этот вид проверки, но не без недокументированной "функции" и не без проблем до сих пор.

Другие вопросы по тегам