Spec-Zone.ru › GCC 15

7.10 Проверка размера объектов

  • Встроенные функции проверки размера объектов
  • Проверка размера объектов и защита исходного кода

7.10.1 Встроенные функции проверки размера объектов

GCC реализует ограниченный механизм защиты от переполнения буфера, который может предотвратить некоторые атаки с переполнением буфера, определяя размеры объектов, в которые собираются записать данные, и предотвращая запись, если размер недостаточен. Встроенные функции, описанные ниже, дают наилучшие результаты при совместном использовании и включённой оптимизации. Например, для определения размеров объектов на границах функций или отслеживания присваиваний указателей при нетривиальном потоке управления они полагаются на различные проходы оптимизации, включаемые параметром -O2. Однако в ограниченной степени их можно использовать и без оптимизации.

Встроенная функция: size_t __builtin_object_size (const void * ptr, int type)

Эта встроенная конструкция возвращает постоянное количество байтов от ptr до конца объекта, на который указывает указатель ptr (если это известно во время компиляции). Для определения размеров динамически выделяемых объектов функция полагается на то, что функции выделения памяти, вызываемые для получения хранилища, объявлены с атрибутом alloc_size (см. Общие атрибуты функций). __builtin_object_size никогда не вычисляет аргументы, имеющие побочные эффекты. Если такие эффекты есть, она возвращает (size_t) -1 для type 0 или 1 и (size_t) 0 для type 2 или 3. Если указатель ptr может указывать на несколько объектов и все они известны во время компиляции, возвращаемое число представляет собой максимальное количество оставшихся байтов в этих объектах, если type & 2 равно 0, и минимальное, если оно не равно 0. Если во время компиляции невозможно определить, на какие объекты указывает ptr, __builtin_object_size должна возвращать (size_t) -1 для type 0 или 1 и (size_t) 0 для type 2 или 3.

type — целочисленная константа от 0 до 3. Если младший бит сброшен, объектами считаются целые переменные; если он установлен, объектом считается ближайший окружающий подобъект, на который указывает указатель. Второй бит определяет, вычисляется ли максимальное или минимальное количество оставшихся байтов.

struct V { char buf1[10]; int b; char buf2[10]; } var;
char *p = &var.buf1[1];
int *q = &var.b;

/* Here the object p points to is var.  */
assert (__builtin_object_size (p, 0) == sizeof (var) - 1);
/* The subobject p points to is var.buf1.  */
assert (__builtin_object_size (p, 1) == sizeof (var.buf1) - 1);
/* The object q points to is var.  */
assert (__builtin_object_size (q, 0)
        == (char *) (&var + 1) - (char *) &var.b);
/* The subobject q points to is var.b.  */
assert (__builtin_object_size (q, 1) == sizeof (var.b));
Встроенная функция: size_t __builtin_dynamic_object_size (const void * ptr, int type)

Эта встроенная функция подобна __builtin_object_size: она возвращает количество байтов от ptr до конца объекта, на который указывает указатель ptr, но возвращаемый размер не обязательно является константой. Это позволяет успешно вычислять оценки размера объектов в более широком диапазоне случаев и может обеспечить большую точность, чем __builtin_object_size, но снижает производительность, поскольку вычисление размера может создавать дополнительную нагрузку во время выполнения. Семантика type, а также возвращаемые значения в случае, когда во время компиляции невозможно определить, на какие объекты указывает ptr, совпадают с поведением __builtin_object_size.

7.10.2 Проверка размера объектов и защита исходного кода

Усиление защиты вызовов функций с помощью макроса _FORTIFY_SOURCE — один из основных способов использования встроенных функций проверки размера объектов. Чтобы упростить реализацию этих возможностей и улучшить оптимизацию и диагностику, добавлены встроенные функции для многих распространённых функций работы со строками; например, для memcpy предоставлена встроенная функция __builtin___memcpy_chk. У этой встроенной функции есть дополнительный последний аргумент — количество байтов, оставшихся в объекте, на который указывает аргумент dest, либо (size_t) -1, если размер неизвестен.

Если последний аргумент равен (size_t) -1 или во время компиляции известно, что переполнения объекта назначения не произойдёт, встроенные функции оптимизируются до обычных функций для работы со строками, таких как memcpy. Если компилятор может определить во время компиляции, что объект всегда будет переполнен, он выдаёт предупреждение.

Пример предполагаемого использования:

#undef memcpy
#define bos0(dest) __builtin_object_size (dest, 0)
#define memcpy(dest, src, n) \
  __builtin___memcpy_chk (dest, src, n, bos0 (dest))

char *volatile p;
char buf[10];
/* It is unknown what object p points to, so this is optimized
   into plain memcpy - no checking is possible.  */
memcpy (p, "abcde", n);
/* Destination is known and length too.  It is known at compile
   time there will be no overflow.  */
memcpy (&buf[5], "abcde", 5);
/* Destination is known, but the length is not known at compile time.
   This will result in __memcpy_chk call that can check for overflow
   at run time.  */
memcpy (&buf[5], "abcde", n);
/* Destination is known and it is known at compile time there will
   be overflow.  There will be a warning and __memcpy_chk call that
   will abort the program at run time.  */
memcpy (&buf[6], "abcde", 5);

Подобные встроенные функции предоставлены для memcpy, mempcpy, memmove, memset, strcpy, stpcpy, strncpy, strcat и strncat.

  • Проверка функций форматированного вывода

7.10.2.1 Проверка функций форматированного вывода

Встроенная функция: int __builtin___sprintf_chk (char *s, int flag, size_t os, const char *fmt, ...)
Встроенная функция: int __builtin___snprintf_chk (char *s, size_t maxlen, int flag, size_t os, const char *fmt, ...)
Встроенная функция: int __builtin___vsprintf_chk (char *s, int flag, size_t os, const char *fmt, va_list ap)
Встроенная функция: int __builtin___vsnprintf_chk (char *s, size_t maxlen, int flag, size_t os, const char *fmt, va_list ap)

Добавленный аргумент flag передаётся без изменений функциям __sprintf_chk и другим и может содержать зависящие от реализации флаги, указывающие, какие дополнительные меры безопасности может применять проверяющая функция, например, особую обработку %n.

Аргумент os — это размер объекта, на который указывает s, как и в других встроенных функциях. Однако поведение немного отличается: если os равен (size_t) -1, встроенные функции оптимизируются до функций без проверки только в том случае, если flag равен 0; в противном случае вызывается проверяющая функция, которой в качестве аргумента os передаётся (size_t) -1.

Кроме того, существуют проверяющие встроенные функции __builtin___printf_chk, __builtin___vprintf_chk, __builtin___fprintf_chk и __builtin___vfprintf_chk. У них есть только один дополнительный аргумент — flag, расположенный непосредственно перед строкой формата fmt. Если компилятор может оптимизировать их до функций fputc и других, он это делает; в противном случае вызывается проверяющая функция и ей передаётся аргумент flag.

© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-15.3.0/gcc/Object-Size-Checking.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API