Во всех сценариях копирования / перемещения строк - strcat (), strncat (), strcpy (), strncpy () и т. Д.) Дела идут намного лучше ( безопаснее ), если пара простых эвристик применяются:
1. Всегда добавляйте NUL-буфер в буфер (ы) перед добавлением данных.
2. Объявите символьные буферы как [SIZE + 1] с макрос-константой.
Например, дано:
#define BUFSIZE 10
char Buffer[BUFSIZE+1] = { 0x00 }; /* The compiler NUL-fills the rest */
мы можем использовать код как:
memset(Buffer,0x00,sizeof(Buffer));
strncpy(Buffer,BUFSIZE,"12345678901234567890");
относительно безопасно. Memset () должен появляться перед strncpy (), даже если мы инициализировали Buffer во время компиляции, потому что мы не знаем, какой мусор помещен в него другим кодом до вызова нашей функции. Функция strncpy () урезает скопированные данные до «1234567890» и не NUL-завершит их. Однако, так как мы уже заполнили NUL весь буфер - sizeof (Buffer), а не BUFSIZE - гарантированно будет окончательный NUL «вне области», заканчивающий NUL, так как мы ограничиваем наши записи с использованием BUFSIZE константа вместо sizeof (Buffer).
Буфер и BUFSIZE также отлично работают для snprintf ():
memset(Buffer,0x00,sizeof(Buffer));
if(snprintf(Buffer,BUFIZE,"Data: %s","Too much data") > BUFSIZE) {
/* Do some error-handling */
} /* If using MFC, you need if(... < 0), instead */
Несмотря на то, что snprintf () специально записывает только символы BUFIZE-1, за которыми следует NUL, это работает безопасно. Таким образом, мы «теряем» лишний байт NUL в конце буфера ... мы предотвращаем переполнение буфера и неопределенные строковые условия при довольно небольшой стоимости памяти.
Мой вызов strcat () и strncat () более жесткий: не используйте их. Трудно безопасно использовать strcat (), а API для strncat () настолько нелогичен, что усилия, необходимые для его правильного использования, сводят на нет любую выгоду. Я предлагаю следующее раскрытие:
#define strncat(target,source,bufsize) snprintf(target,source,"%s%s",target,source)
Соблазнительно создать раскрывающийся список strcat (), но не очень хорошая идея:
#define strcat(target,source) snprintf(target,sizeof(target),"%s%s",target,source)
потому что target может быть указателем (таким образом, sizeof () не возвращает нужную нам информацию). У меня нет хорошего "универсального" решения для экземпляров strcat () в вашем коде.
Проблема, с которой я часто сталкиваюсь от программистов, осведомленных о strFunc (), - это попытка защитить от переполнения буфера с помощью strlen (). Это нормально, если содержимое гарантированно завершено NUL. В противном случае сам strlen () может вызвать ошибку переполнения буфера (обычно приводящую к нарушению сегментации или другой ситуации с дампом ядра), прежде чем вы когда-либо достигнете «проблемного» кода, который вы пытаетесь защитить.