Почему strdup считается злом

Я видел несколько плакатов о том, чтоstrdup это зло Есть ли консенсус по этому вопросу? Я использовал его без каких-либо чувства вины и не вижу причин, почему это хуже, чем использоватьmalloc/memcpy.

Единственное, что я думаю, может заработатьstrdup репутация заключается в том, что вызывающие абоненты могут злоупотреблять ею (например, не осознавать, что им необходимо освободить возвращаемую память; попробуйте выполнить strcat до конца строки strdup). Но тогда строки в malloc также не свободны от возможности неправильного использования.

Спасибо за ответы и извинения тем, кто считает вопрос бесполезным (голосует за закрытие). Суммируя ответы, кажется, что нет общего ощущения, чтоstrdup это само по себе зло, но общее мнение, что оно, как и многие другие части C, может использоваться ненадлежащим образом или небезопасно.

На самом деле не существует «правильного» ответа, но ради его принятия я принял ответ @ nneoneo - это мог быть ответ @R ...

 Seth Carnegie20 окт. 2012 г., 05:31
Этот вопрос не был случайно вызван моим комментарием ранее, не так ли?
 William Morris20 окт. 2012 г., 17:17
@SethCarnegie, да, но я видел то же чувство, выраженное в другом месте, именно поэтому я создал вопрос, а не просто спросил вас.
 dmckee20 окт. 2012 г., 05:32

Ответы на вопрос(6)

strdup зло по нескольким причинам,

главное, что скрывает распределение. Другойstr* функции и большинство других стандартных функций не требуютfree потом такstrdup выглядит достаточно безобидным, и вы можете забыть убрать после него. dmckee предложил просто добавить его в свой список функций, которые необходимо очистить после, но почему? Я не вижу большого преимущества по сравнению двух линий средней длины до одной короткой.

Он всегда выделяет память в куче, и с V99 C (это 99?) У вас есть еще одна причина, чтобы просто использоватьstrcpy (тебе даже не нужноmalloc). Вы не можете всегда делать это, но когда вы можете, вы должны.

Это не является частью стандарта ISO (но это часть стандарта POSIX, спасибо Wiz), но это действительно небольшой вопрос, поскольку R ... упомянул, что его можно легко добавить. Если вы пишете переносимые программы, я не уверен, как вы скажете, было ли оно уже определено или нет ...

Это, конечно, несколько моих собственных причин, а не других. Чтобы ответить на ваш вопрос, нет единого мнения, о котором я знаю.

Если вы пишете программы только для себя, и вы найдетеstrdup нет проблем, тогда есть гораздо меньше причин, чтобы не использовать его, чем если вы пишете программу для чтения многими людьми с разным уровнем квалификации и возраста.

 Seth Carnegie20 окт. 2012 г., 06:24
@ Ваши собственные вещи привлекают внимание,strdup сливается. Это было главное. Спасибо за пункт о стандартах.
 Jonathan Leffler20 окт. 2012 г., 07:25
Мне очень хочется понизить голос, так как я не согласен с большей частью того, что вы говорите. Я не буду, но я официально заявлю, что думаю, что ваши возражения на самом деле не актуальны. Учитывая количество раз, люди делают ошибки, симулируяstrdup() - обычно, забывая выделить достаточно места для завершающего нуля, - наличие библиотечной функции гораздо более разумно, чем заставлять всех заново изобретать (7-строчную) функцию.
 R..20 окт. 2012 г., 14:28
7-линия? Я всегда думаю об этом как один или два ...char *new = malloc(strlen(old)+1); return new ? strcpy(new, old) : 0;
 Wiz20 окт. 2012 г., 06:21
Ваш первый пункт дискредитирует почти весь язык Си? Если вы не освобождаете strdup (), вы не освобождаете свои собственные вещи. Почему это будет отличаться? Что касается VLA, особенно для строк произвольного размера, возникает проблема и неопределенное поведение без предупреждений. Что касается последней пули: это не стандарт: да, это так. Это часть стандарта POSIX. Это просто не является частью стандарта ISO C - который достаточно переносим для большинства людей.
 William Morris20 окт. 2012 г., 17:28
@R .. лучше сmemcpyнет? то есть.size_t len = strlen(old) + 1; char *new = malloc(len); return new ? memcpy(new, old, len) : 0;
Решение Вопроса

Это не строго ANSI C, а скорее POSIX. Следовательно, некоторые компиляторы (например, MSVC) препятствуют использованию (MSVC предпочитает_strdup), а такжетехнически стандарт C может определять свой собственныйstrdup с другой семантикой, так какstr является зарезервированным префиксом Таким образом, существуют некоторые потенциальные проблемы с переносимостью при его использовании.Это скрывает распределение памяти. Большинство другихstr функции не выделяют память, поэтому пользователи могут быть введены в заблуждение (как вы говорите), полагая, что возвращаемую строку не нужно освобождать.

Но, помимо этих моментов, я думаю, что осторожное использованиеstrdup оправдано, так как это может уменьшить дублирование кода и обеспечивает хорошую реализацию для распространенных идиом (таких какstrdup("constant string") чтобы получить изменяемую, возвращаемую копию литеральной строки).

о которой не упоминалось, заключается в том, что это распределение ресурсов без естественной пары. Давайте попробуем глупую игру: я говорюmalloc, ты говоришьfree, Я говорюopen ты говоришьclose, Я говорюcreate ты говоришьdestroy, Я говорюstrdup ты говоришь ....?

Собственно, ответ наstrdup являетсяfree конечно, и функция была бы лучше названаmalloc_and_strcpy чтобы прояснить это. Но многие программисты на С так не думают и забывают, чтоstrdup требует его противоположности или «окончания»free освободить.

По моему опыту, очень часто можно найти утечки памяти в коде, который вызываетstrdup, Это странная функция, которая объединяетstrlen, malloc а такжеstrcpy.

strdup и это не хуже, чем любая другая функция в C.

POSIX являетсястандарт а такжеstrdup это не так сложно реализовать, если переносимость становится проблемой.

Освободить ли память, выделеннуюstrdup не должно быть проблемой, если кто-то потратил немного времени, чтобы прочитать страницу руководства и понять, какstrdup работает. Если кто-то не понимает, как работает функция, очень вероятно, что человек что-то испортит, это применимо кЛюбые функция, а не толькоstrdup.

В C память и большинство других вещей управляются программистом, поэтому strdup не хуже, чем забыватьсвободно mallocпамять, не в состояниинулевой конец строка, использующая неверный формат строки вscanf (и вызывает неопределенное поведение), доступ ксвисающий указатель и т. д.

(Я действительно хотел опубликовать это как комментарий, но не смог добавить ни одного комментария. Следовательно, опубликовал это как ответ).

что большая часть забот о strdup исходит из соображений безопасности, касающихся переполнения буфера и неправильно отформатированных строк. Если строка с ненулевым символом в конце передается в strdup, ей может быть выделена строка неопределенной длины. Я не знаю, может ли это быть специально использовано для атаки, но в целом это хорошая практика безопасного кодирования - использовать только строковые функции, которые принимают максимальную длину, вместо того, чтобы полагаться только на нулевой символ.

 Jonathan Leffler20 окт. 2012 г., 07:27
Если строка с ненулевым символом в конце передается какой-либо функции, которая ожидает строку с нулевым символом в конце, программист дурачит.
 Secure20 окт. 2012 г., 08:51
Если вы беспокоитесь о безопасности обработки строк (которой вы всегда должны быть), то лучше не бросать необработанныеstr* звонки по всему вашему коду. Напишите библиотеку обработки строк, которая заботится обо всех типичных проблемах и использует ее исключительно. Конечно, если вас больше беспокоят такие глупые вещи, как «соображения производительности» при использованииstrlen() вместоmy_strlen()тогда вы получите то, что заслуживаете.
 john-charles20 окт. 2012 г., 08:03
Тем не менее, это происходит, поэтому мы используем strncpy вместо strcpy, когда безопасность представляет серьезную проблему. Это также может произойти при неожиданном вводе пользователем или повреждении файлов. Как правило, в практике безопасности полагаться на явную длину, а не на нулевое завершение строки.
 Secure20 окт. 2012 г., 08:46
Массив char без нулевого завершения не является «строкой» по определению. Вы не будете ожидатьfopen() работать, когда вы даете ему http URL вместо пути к файлу. Любой программист, который предоставляет обычный массив символов для функции, которая ожидает строку, должен либо иметь RTFM, либо ему не разрешено находиться в пределах 100 метров от любого производственного кода. Скорее всего, они также забудут проверить возвращениеmalloc() для NULL.
 Jonathan Leffler20 окт. 2012 г., 08:19
Для большинства практических целей я не используюstrncpy(), Это не гарантирует нулевого завершения. Если вы копируете 5-байтовое слово в буфер размером 20 КиБ, он также записывает 20475 нулей. Ни одно поведение не приемлемо для меня. Обычно я проверяю длину строки и используюmemmove() или (иногда)memcpy(); У меня есть рецидивы и использоватьstrcpy(), но только если я знаю, что места достаточно. (Если это утешение,strncat() хуже чемstrncpy(); Я никогда не использую его!) Если я не знаю максимальную длину строки, я не смогу безопасно манипулировать ею. Я не могу сказать, где это может быть обрезано даже.

strdup описывается как зло, но некоторые возможные причины некоторым людям не нравятся:

Это не стандартный C (но в POSIX). Однако я нахожу эту причину глупой, потому что это почти однострочная функция для добавления в системы, в которых ее нет.Слепое дублирование строк повсеместно, а не использование их на месте, когда это возможно, тратит время и память и вводит случаи сбоев в код, которые в противном случае могли бы быть безотказными.Когда вам нужна копия строки, скорее всего, вам действительно нужно больше места для ее модификации или сборки, иstrdup не дает вам этого.

Ваш ответ на вопрос