#include
void * alloca(size_t size);
Подобно malloc()
, alloca()
выделяет область памяти длиной size
байтов и возвращает указатель на начало этой области. Вместо использования памяти из программной кучи этот метод распределяет память из вершины стека, из того же места, где хранятся локальные переменные. Первое преимущество данной функции перед локальными переменными состоит в том, что необходимое количество байтов точно вычисляется в программе, а не определяется приблизительно. Превосходство над malloc()
заключается в том, что при завершении работы функции память освобождается автоматически. Все это позволяет охарактеризовать alloca()
как легкий способ распределения памяти, которая требуется только временно. До тех пор, пока размер буфера вычисляется должным образом (не забудьте учесть '\0'
в конце каждой строки С!), можно не бояться переполнения буфера [161] Функция alloca() не является стандартным средством языка С, однако компилятор gcc предоставляет alloca() в большинстве поддерживаемых операционных систем. В более старых версиях gcc (до версии 3.3) alloca() не всегда должным образом взаимодействовала с массивами динамических размеров (другое расширение GNU), поэтому примите во внимание, что использовать нужно только одну из версий.
.
Есть еще также несколько других функций, которые помогают избежать переполнения буфера. Библиотечные методы strncpy()
и strncat()
легко предотвращают перегрузки буфера при копировании строк.
#include
char * strncpy (char * dest, const char * src, size_t max);
char * strncat (char * dest, const char * src, size_t max);
Обе функции ведут себя как их родственники, называемые аналогично, strcpy()
и strcat()
, но они возвращают за один раз только max байт, копируемые в строку назначения. Если достигнут предел, то результирующая строка не завершается '\0'
, поэтому обычные строковые функции не смогут с ней работать. По этой причине необходимо явно завершить строку после вызова одной из подобных функций.
strncpy(dest, src, sizeof(dest));
dest[sizeof(dest) - 1] = '\0';
Частой ошибкой при использовании strncat()
является передача общего размера dest
в качестве параметра max
. Это приводит к потенциальному переполнению буфера, так как strncat()
добавляет до max
байт в dest
; она не прекращает копировать байты, когда общая длина dest
достигает max
байтов.
Несмотря на то что эти функции могут сделать выполнение программы некорректным при передаче длинных строк (из-за усечения этих строк), данный прием хорошо предотвращает перегрузки в буферах статических размеров. Во многих случаях это приемлемый компромисс (во всяком случае, при этом не произойдет ничего хуже того, что может случиться из-за переполнения буфера).
Функция strncpy()
решает проблему копирования строки в статический буфер без переполнения его. А функции strdup()
автоматически выделяют буфер, достаточный для хранения строки, до начала копирования в него исходной строки.
#include
char * strdup(const char * src);
char * strdupa(const char * src);
char * strndup(const char * src, int max);
char * strndupa(const char * src, int max);
Первая из приведенных функций, strdup()
, копирует строку src
в буфер, выделенный методом malloc()
, и возвращает буфер вызывающему оператору. Вторая функция, strdupa()
, выделяет буфер с помощью alloca()
. При этом обе функции выделяют буфер, в точности достаточный для хранения строки и замыкающего символа '\0'
.
Остальные две функции, strndup()
и strndupa()
, копируют не более чем max байтов из str
в буфер вместе с замыкающим '\0'
(и выделяют не более чем max
+1 байтов). При этом выделение буфера происходит при помощи метода malloc()
(для strndup()
) или alloca()
(для strndupa()
).
Функция sprintf()
также входит в число тех, которые часто вызывают переполнение буфера. Так же как strcat()
и strcpy()
, функция sprintf()
имеет разновидность, позволяющую облегчить защиту от перегрузок.
#include
int snprintf(char * str, size_t max, char * format, ...);
Попытки определить размер буфера, необходимый для sprintf()
, могут оказаться слишком сложными. Он зависит от таких элементов, как значения всех форматируемых чисел (для которых могут быть нужны или не нужны знаки чисел), используемые аргументы форматирования и длины всех строк, которые были затронуты форматированием. Для того чтобы избежать переполнения буфера, функция snprintf()
помещает в str
не более чем max символов, включая замыкающий '\0'
. В отличие от strcat()
и strncat()
, функция snprintf()
корректно завершает строку, при необходимости пренебрегая символом из форматируемой строки. Она возвращает количество символов, которые будет занимать конечная строка при наличии доступного пространства. Также сообщается, нужно ли усекать строку до max
символов (не считая последний '\0'
) [162] В некоторых устаревших версиях библиотеки С вместо этого возвращается -1 (если строка не помещается). Старая версия библиотеки С уже не поддерживается и не используется в защищенных программах, однако на man-странице по функции snprintf() демонстрируется код, обрабатывающий оба варианта.
. Если возвращаемое значение меньше чем max
, значит, функция успешно завершила свою работу. Если же равно или больше, значит, предел max
превышен.
Читать дальше