Во-первых, strlcpy
он никогда не задумывался как безопасная версия strncpy
(и strncpy
никогда не задумывался как безопасная версия strcpy
). Эти две функции совершенно не связаны. strncpy
- это функция, которая вообще не имеет отношения к C-строкам (т.е. строкам с завершающим нулем). То, что str...
в названии есть приставка, - просто историческая ошибка. История и цель ), что на самом деле является полной чушью и приводит к плохой практике программирования. Стандартная библиотека C в ее нынешнем виде не имеет функции для копирования C-строки ограниченной длины. Вот где подходит. Это действительно настоящая функция копирования ограниченной длины, созданная для работы с C-строками.strncpy
хорошо известны и задокументированы. Это функция, созданная для работы со строками так называемой «фиксированной ширины» (не с C-строками), используемыми в некоторых исторических версиях файловой системы Unix. Сегодня некоторые программисты сбиты с толку его названием и предполагают, что strncpy
он каким-то образом должен служить функцией копирования C-строки ограниченной длины («безопасный» родственный элементstrcpy
strlcpy
strlcpy
strlcpy
правильно делает все, что должна делать функция копирования ограниченной длины. Единственная критика, на которую можно направить это, - это то, что это, к сожалению, нестандартно.
Во-вторых, strncat
с другой стороны, это действительно функция, которая работает с C-строками и выполняет конкатенацию ограниченной длины (это действительно «безопасный» брат, который заботится об этих проблемах, изменяя интерфейс так, чтобы не требовались дополнительные вычисления. (по крайней мере, в вызывающем коде). Опять же, единственное основание, которое, как я вижу, можно критиковать, это то, что функция не является стандартной. Кроме того, функции из группы - это то, что вы не увидите в профессиональном коде очень часто из-за ограниченного удобство использования самой идеи конкатенации строк на основе повторного сканирования.strcat
). Чтобы правильно использовать эту функцию, программист должен проявить особую осторожность, так как параметр размера, который принимает эта функция, на самом деле не является размером буфера, который получает результат, а скорее размером его оставшейся части (также, символа терминатора засчитывается неявно). Это может сбивать с толку, поскольку для того, чтобы привязать этот размер к размеру буфера, программист должен не забыть выполнить некоторые дополнительные вычисления, которые часто используются для критики strncat
.strlcat
strcat
Что касается того, как эти функции могут привести к проблемам с безопасностью ... Они просто не могут. Они не могут привести к проблемам безопасности в большей степени, чем сам язык C может «привести к проблемам безопасности». Видите ли, какое-то время было сильное мнение, что язык C ++ должен двигаться в направлении развития в какой-то странный вид Java. Это мнение иногда распространяется и на область языка C, что приводит к довольно невежественной и вынужденной критике функций языка C и возможностей стандартной библиотеки C. Я подозреваю, что мы можем иметь дело с чем-то подобным и в этом случае, хотя я, конечно, надеюсь, что все не так уж плохо.
strlcpy
иstrlcat
хотел сообщить какие - то условие ошибки , если они торкались ограничением размера буфера назначения. Хотя вы можете проверить возвращенную длину, чтобы проверить это, это не очевидно. Но я думаю, что это незначительная критика. Аргумент «они поощряют использование строк C, поэтому они плохие» - глупый.strcpy
выше порога и , следовательно , «небезопасных», и их предпочтительной строки копирования функции (будь тоstrlcpy
,strcpy_s
или дажеstrncpy
) ниже порога и , следовательно , «безопасный».strlcpy/strlcat
. Можно "не любить" общую концепцию строки с нулевым завершением, но вопрос не в этом. Если вы знаете «множество причин не любитьstrlcpy/strlcat
», вам, вероятно, следует написать свой собственный ответ вместо того, чтобы ожидать, что я смогу читать чужие мысли.strlcpy/strlcat
. Хотя я считаю, что понимаю, о чем идет речь, я лично отказываюсь признать это «проблемами безопасности» в области традиционного языка C, как я его знаю. Об этом я сказал в своем ответе.Критика Ульриха основана на идее, что усечение строки, которое не обнаруживается программой, может привести к проблемам безопасности из-за неправильной логики. Следовательно, для обеспечения безопасности вам необходимо проверить усечение. Это для конкатенации строк означает, что вы выполняете проверку в соответствии со следующими строками:
if (destlen + sourcelen > dest_maxlen) { /* Bug out */ }
Теперь
strlcat
эффективно выполняет эту проверку, если программист не забывает проверить результат - так что вы можете безопасно использовать его:if (strlcat(dest, source, dest_bufferlen) >= dest_bufferlen) { /* Bug out */ }
Позиция Ульриха заключается в том, что, поскольку вам нужно иметь
destlen
иsourcelen
около (или пересчитать их, чтоstrlcat
эффективно и работает), вы можете вmemcpy
любом случае просто использовать более эффективное :if (destlen + sourcelen > dest_maxlen) { goto error_out; } memcpy(dest + destlen, source, sourcelen + 1); destlen += sourcelen;
(В приведенном выше коде
dest_maxlen
это максимальная длина строки, которая может быть сохраненаdest
- на единицу меньше размераdest
буфера.dest_bufferlen
- это полный размер строкиdest buffer
).источник
memcpy
ним может быть любым типом памяти , и у меня есть дополнительное измерение , чтобы проверить, пытаясь понять код. У меня было устаревшее приложение для отладки, где все делалось с помощью memcpy, это была настоящая PITA, которую нужно было исправить. После переноса на выделенную строковую функцию ее намного легче читать (и быстрее, потому чтоstrlen
можно удалить много ненужного ).memcpy()
достаточно (и потенциально более эффективноstrcpy()
).memcpy()
это операция строки - это декларируется в<string.h>
конце концов.Когда люди говорят: «
strcpy()
Это опасно, используйтеstrncpy()
вместо этого» (или аналогичные утверждения оstrcat()
и т. Д., Но я собираюсь использоватьstrcpy()
здесь в качестве основного), они имеют в виду, что нет никаких ограниченийstrcpy()
. Таким образом, слишком длинная строка приведет к переполнению буфера. Они правы. Использованиеstrncpy()
в этом случае предотвратит переполнение буфера.Я чувствую, что это
strncpy()
действительно не исправляет ошибки: это решает проблему, которую может легко избежать хороший программист.Как программист на C, вы должны знать конечный размер, прежде чем пытаться копировать строки. Это предположение
strncpy()
и вstrlcpy()
последних параметрах: вы указываете им этот размер. Вы также можете узнать исходный размер, прежде чем копировать строки. Затем, если пункт назначения недостаточно велик, не звонитеstrcpy()
. Либо перераспределите буфер, либо сделайте что-нибудь еще.Почему мне не нравится
strncpy()
?strncpy()
- плохое решение в большинстве случаев: ваша строка будет усечена без какого-либо уведомления - я бы предпочел написать дополнительный код, чтобы выяснить это сам, а затем предпринять действия, которые я хочу предпринять, вместо того, чтобы позволить какой-то функции решить за мне о том, что делать.strncpy()
очень неэффективно. Он записывает каждый байт в целевой буфер. Вам не нужны эти тысячи'\0'
в конце пункта назначения.'\0'
если место назначения недостаточно велико. Так что вы все равно должны сделать это сами. Сложность сделать это не стоит проблем.Теперь мы подошли к
strlcpy()
. Измененияstrncpy()
делают его лучше, но я не уверен,strl*
оправдывает ли конкретное поведение их существование: они слишком специфичны. Вам все равно нужно знать размер места назначения. Это более эффективно, чемstrncpy()
потому, что он не обязательно записывает каждый байт в месте назначения. Но это решает проблему , которую можно решить, выполнив:*((char *)mempcpy(dst, src, n)) = 0;
.Я не думаю, что кто-то говорит это
strlcpy()
илиstrlcat()
может привести к проблемам с безопасностью, то, что они (и я) говорят, что они могут привести к ошибкам, например, когда вы ожидаете, что будет записана вся строка, а не ее часть.Главный вопрос здесь: сколько байтов копировать? Программист должен знать это , и если он не делает,
strncpy()
илиstrlcpy()
не спасет.strlcpy()
иstrlcat()
не являются стандартными, ни ISO C, ни POSIX. Поэтому их использование в переносимых программах невозможно. Фактически,strlcat()
существует два разных варианта: реализация Solaris отличается от других для крайних случаев, включающих длину 0. Это делает ее даже менее полезной, чем в противном случае.источник
strlcpy
работает быстрее, чемmemcpy
на многих архитектурах, особенно еслиmemcpy
копируются ненужные конечные данные.strlcpy
также возвращает, сколько данных вы пропустили, что может позволить вам восстановить быстрее и с меньшим количеством кода.n
в моем вызове memcpy указано точное количество байтов, которые нужно записать, поэтому эффективность тоже не является большой проблемой.strlcpy
каждый раз , когда вам это нужно , используяmemcpy
иstrlen
это тоже нормально, но тогда почему остановка наstrlcpy
, вам не нужно вmemcpy
функцию либо, вы можете скопировать байты один на один. Эталонная реализация в обычном случае просматривает данные только один раз, и это лучше для большинства архитектур. Но даже если лучшая реализация использовалаstrlen
+memcpy
, это все еще не причина, чтобы не повторно реализовывать безопасный strcpy снова и снова.strlcpy
вы проходите входную строку только один раз в хорошем случае (которых должно быть большинство) и два раза в плохом случае, с вашимstrlen
+memcpy
вы всегда проходите над ним дважды. Другое дело, если это имеет значение на практике.Я думаю, что Ульрих и другие думают, что это даст ложное чувство безопасности. Случайное усечение строк может иметь последствия для безопасности других частей кода (например, если путь к файловой системе усечен, программа может не выполнять операции с заданным файлом).
источник
malware.exe.jpg
доmalware.exe
.Есть две «проблемы», связанные с использованием функций strl:
Авторы проекта стандарта c1x и Дреппер утверждают, что программисты не будут проверять возвращаемое значение. Дреппер говорит, что мы должны каким-то образом знать длину и использовать memcpy и вообще избегать строковых функций. Комитет по стандартам утверждает, что безопасный strcpy должен возвращать ненулевое значение при усечении, если иное не указано
_TRUNCATE
флагом. Идея в том, что люди с большей вероятностью будут использовать if (strncpy_s (...)).Некоторые люди думают, что строковые функции никогда не должны давать сбоев, даже если они загружены поддельными данными. Это влияет на стандартные функции, такие как strlen, которые в нормальных условиях будут отключаться. Новый стандарт будет включать множество таких функций. Проверки, конечно, приводят к снижению производительности.
Преимущество предлагаемых стандартных функций в том, что вы можете узнать, сколько данных вы пропустили, с помощью функций strl .
источник
strncpy_s
это не безопасная версия,strncpy
а в основномstrlcpy
замена.Я не думаю
strlcpy
иstrlcat
считаю их небезопасными, или, по крайней мере, это не причина, по которой они не включены в glibc - в конце концов, glibc включает strncpy и даже strcpy.Их критиковали за то, что они якобы неэффективны, а не небезопасны .
Согласно статье Дэмиена Миллера о безопасной переносимости :
Вот почему они недоступны в glibc, но неверно, что они недоступны в Linux. Они доступны в Linux в libbsd:
Они упакованы в Debian, Ubuntu и другие дистрибутивы. Вы также можете просто взять копию и использовать ее в своем проекте - она короткая и под разрешающей лицензией:
источник
Безопасность не является логическим. Функции C не являются полностью «безопасными» или «небезопасными», «безопасными» или «небезопасными». При неправильном использовании простая операция присваивания в C может быть «небезопасной». strlcpy () и strlcat () можно использовать безопасно (надежно) так же, как strcpy () и strcat () можно безопасно использовать, когда программист предоставляет необходимые гарантии правильного использования.
Основным моментом всех этих строковых функций C, стандартных и нестандартных, является уровень, до которого они упрощают безопасное / надежное использование . Безопасное использование strcpy () и strcat () нетривиально; это подтверждается количеством раз, когда программисты C ошибались за эти годы, и в результате возникали опасные уязвимости и эксплойты. strlcpy () и strlcat () и, в этом отношении, strncpy () и strncat (), strncpy_s () и strncat_s () немного проще в использовании, но все же нетривиально. Они небезопасны / небезопасны? Не более чем memcpy () при неправильном использовании.
источник