6.58 Проверка размера объекта
6.58.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, и минимальным, если не равно нулю. Если определить, на какие объекты указывает 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], *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.
6.58.2 Проверка размера объекта и укрепление исходного кода
Укрепление вызовов функций с помощью макроса _FORTIFY_SOURCE является одним из ключевых применений встроенных функций проверки размера объекта. Чтобы сделать реализацию этих функций удобнее и улучшить оптимизацию и диагностику, для многих общих функций работы со строками добавлены встроенные функции, например, для memcpy __builtin___memcpy_chk предоставляет встроенную функцию. Эта встроенная функция имеет дополнительный последний аргумент, который представляет количество оставшихся байтов в объекте, на который указывает аргумент dest, или (size_t) -1 если размер неизвестен.
Встроенные функции оптимизируются в обычные функции работы со строками, такие как memcpy, если последний аргумент равен (size_t) -1 или если во время компиляции известно, что объект назначения не переполнится. Если компилятор может определить во время компиляции, что объект всегда переполнится, он выдает предупреждение.
Предполагаемое использование может быть, например:
#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.
6.58.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-13.3.0/gcc/Object-Size-Checking.html