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

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

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

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

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

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

Ответы [ 2 ]

6 голосов
/ 14 декабря 2011

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 ++ выводится то же предупреждение.

2 голосов
/ 14 декабря 2011

То, что мы видим здесь, является неприятным, малоизвестным секретом о 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 действительно поддерживает этот вид проверки, но не без недокументированной «функции» и не без проблем до сих пор.

...