Недавно на SO возник вопрос (С какой стати кто-нибудь использует strncpy вместо strcpy?), на который были ответы (ответ 1, ответ 2), из-за чего я сомневался в других строковых функциях с 'n' в имени, таких как snprintf
(которые я широко использовал). Безопасно ли использовать snprintf? И вообще какие безопасные функции из семейства 'n'?
Безопасно ли использовать snprintf и друзей?
Ответы (5)
strncpy()
- это странная функция, которая действительно неправильно названа - ее первоначальная цель - гарантировать, что буфер был полностью инициализирован содержимым строки (без переполнения цели) и напоминанием о буфере с нулями. Насколько я понимаю, первоначальной целью была обработка записей в каталоге файловой системы — целевой буфер на самом деле не был строкой в том же смысле, что и другие функции strxxx()
в библиотеке C. Основная проблема с strncpy()
заключается в том, что если исходная строка больше буфера назначения, результат не будет заканчиваться нулем.
Большинство других функций 'n', которые имеют дело со строками, правильно завершают строку, но есть исключения, такие как ублюдочная _snprintf()
от Microsoft. Правильный C99 snprintf()
всегда будет завершать нулем строку назначения (пока размер буфера назначения больше 0).
Существует «Технический отчет», TR 24731, в котором предлагается набор альтернатив проверки границ для функций, которые имеют дело со строками и буферами памяти. Одна из целей TR состоит в том, чтобы параметры, результаты и поведение при ошибках функций были более схожими для всех функций. TR, кажется, имеет несколько неоднозначное признание, и я не думаю, что он широко реализован, кроме как для компилятора Microsoft (я думаю, что MS была основной движущей силой TR). вы можете получить больше информации здесь:
- Обоснование TR 24731
- TR 24731-1 (интерфейсы проверки границ)
- TR 24731-2 (функции динамического распределения)
Даже если вы не являетесь поклонником предложений, я думаю, что они полезны для чтения о проблемах с существующими функциями.
Хотя snprintf
не будет переполнять буфер, если вы дадите ему правильные аргументы, имейте в виду, что он разделяет все уязвимости строки формата с другими членами семейства *printf
. Например, спецификатор %n
опасен, потому что злоумышленники могут использовать его для записи произвольных байтов в произвольные области памяти. См. FIO30- С. Исключить пользовательский ввод из строк формата из вики CERT C Coding Standards.
Это безопасно, если вы указываете правильную длину буфера.
snprintf гарантирует, что буфер не будет перезаписан, но не гарантирует нулевое завершение. Вы можете использовать sprintf_s
в MSVC, если хотите быть нестандартным.
См. http://msdn.microsoft.com/en-us/library/2ts7cx93(VS.71).aspx
Осторожно: разные платформы по-разному относятся к нулевому завершению строки, переданной в snprintf
.
snprintf
, как указано в ISO C99, гарантированно завершается нулем.
- person Pavel Minaev; 13.08.2009