6.60 Проверка размера объектов
6.60.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.60.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.60.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-14.2.0/gcc/Object-Size-Checking.html