С одной поправкой - если программируешь под *BSD ибо к счастью они были благополучно посланы найух сообществом потому что порождают на порядок больше трудно обнаружимых ошибок.
Если программируешь по-человечески, а не windows^Wlinux-only
> были благополучно посланы найух сообществом
Сообществом красноглазых линуксоидов? Ой, вейли-вейли-вейли, беда-беда-беда... 8))) Ну хотят радостно жрать кактус -- флаг в руки.
> потому что порождают на порядок больше трудно обнаружимых ошибок
Угу, например? Не дают сделать переполнение буфера? Ужас какой, а? Или дают возможность спокойно проверить, а не обрезан ли результат? Вообще кошмар, да?
strn?(cat|cpy) -- defective by design. Только идиот может сделать их ещё более defective, как было с успехом проделано в glibc.
> А кто тебя лишил возможности спокойно проверить достаточно ли длины буфера для результата перед вызовом стандартных ф-ий ?
Как? strlen 1-2 раза вызвать? Офигеть прямое и красивое решение, два раза по одной строке бегать... И это оправдание генетической кривизны strcat/strncat вообще, и дважды кривизны реализации в glibc? С ума сойти...
И я всё-таки жду примеров "на порядок больше трудно обнаружимых ошибок".
>Как? strlen 1-2 раза вызвать? Офигеть прямое и красивое решение
Ты бы хоть на исходники своего активно пропагандируемого "прямого" решения глянул прежде чем газифицировать
/* Find the end of dst and adjust bytes left but don't go past end */
while (n-- != 0 && *d != '\0')
d++;
dlen = d - dst;
ничем тебе это strlen не напоминает ?
>И я всё-таки жду примеров "на порядок больше трудно обнаружимых ошибок"
когда ты забудешь сделать проверку на усечение результата твой код благополучно проглотит потенциальный баг - что он породит дальше зависит от ситуации, в лучшем случае твоя программа выведет hello wo на экране :) в более крупных проектах баг может быть не таким очевидным.
> Как? strlen 1-2 раза вызвать? Офигеть прямое и красивое решение, два раза по одной строке бегать.
коряво это выполнить strlcat, а потом узнать, что оказывается для результата нет места и мы получили ненужный огрызок, при этом потратив время, а результат от strlen прекрасно можно использовать для более быстрого объединения строк:
size_t len1 = strlen( buf1 );
size_t len2 = strlen( buf2 );
if( len1 + len2 < sizeof( buf1 ) - 1 )
memcpy( buf1 + len1, buf2, len2 + 1 );
else
...
> Ты бы хоть на исходники своего активно пропагандируемого "прямого" решения глянул прежде чем газифицировать
Вылезь из анабиоза, посмотри в код твоей любимой кривизны, и лезь в биореактор. Потому что там примерно то же самое. Потому что реализовать strcat, не вычисляя длину dst, невозможно. А я говорил про strlen(src).
> когда ты забудешь сделать проверку на усечение результата твой код благополучно проглотит потенциальный баг
Твой код с strcat породит SIGSEGV в лучшем случае, с strncat -- породит тот же SIGSEGV в том же лучшем случае (если, как и для всего остального, не столь альтернативно-одарённо спроектированного, ты напишешь strncat(dst, src, sizeof(dst)), тривиально забыв, что альтернативно-одарённым функциям размер надо передавать как sizeof() - 1), плюс точно такое же обрезание результата, как и в strlcat, плюс совершенно неведомую фигню там, где не гарантируется завершение dst нулём в случае переполнения (это про strncpy).
> мы получили ненужный огрызок, при этом потратив время
Это если огрызок не нужен. Как вариант -- можно взять strl(cat|cpy) из солярки, там поведение как раз нужное тебе.
> а результат от strlen прекрасно можно использовать для более быстрого объединения строк
А будет ли оно заметно быстрее, бенчмарки есть?
Один хрен, использовать strn?(cat|cpy) -- диверсия. Дальше каждый выкручивается как хочет, strl-функции -- просто одно из готовых рабочих проверенных решений.
Ты тупишь как и бсдшники которые были посланы найух.
>> strlcpy for gnu libc.
>This is horribly inefficient BSD crap. Using these function only
leads to other errors. Correct string handling means that you always
know how long your strings are and therefore you can you memcpy
(instead of strcpy).
Половина уязвимостей как раз связаны с переполнением строк(буферов итп). Поэтому и сделали strlcpy. Она не для тех кто умеет программировать а для тех кто не умеет или же кому такое поведение как раз и нужно.
Кстати, покрывать оппонентов матюгами и называть всё что не linux crap-ом как раз в духе воинствующих линуксойдов :)
>забудешь сделать проверку на усечение
strl(cat|cpy) применяют там, где такая проверка не нужна по определению! (т.е. усечение допускается, потому что имеем дело как раз с выводом "hello world" на экран)
там, где такая проверка была бы необходима, использовать эти функции глупо, прибегают к вычислению необходимого размера буфера заранее и выделяют его динамически.
учись программировать с умом!
Ulrich Drepper is a software developer who works for Red Hat. Drepper is the lead contributor to and maintainer of the GNU C Library (glibc). He was also one of the leaders of 86open.
>Половина уязвимостей как раз связаны с переполнением строк(буферов итп). Поэтому и сделали strlcpy. Она не для тех кто умеет программировать а для тех ... кому такое поведение как раз и нужно.
+1.
> strl(cat|cpy) применяют там, где такая проверка не нужна по определению!
> учись программировать с умом!
вы невнимательны, kemm написал, что str(n)cat дефективен и надо использовать Ъ strlсat без всяких оговорок, думаю imhotep не согласен именно с такой точкой зрения
Как обычно. Это ненужно и вредно, потому что я не понимаю, кому это нужно. Причём в качестве альтернативы предлагает использовать нестандартную функцию (mempcpy), маладэц. Причём с тем же косяком, что и strncat -- забить нулём байт, следующий за переданным размером буфера.
Гуру тоже могут ошибаться, ага.
> А вообще нафиг оно надо, если оно не посикс и не кроссплатформенное?
Оно реализовано на чистом С без какой-либо BSD-специфики. Никто не мешает взять реализацию и таскать за собой. Это раз. Если по каким-либо религиозным причинам включать код под BSD лицензией не хочется -- реализация, аналогичная BSD'ишной или соляркиной (в зависимости от требований) пишется за полторы минуты даже без заглядывания в оригинальный код. А идея здравая.
> вы невнимательны, kemm написал, что str(n)cat дефективен и надо использовать Ъ strlсat без всяких оговорок, думаю imhotep не согласен именно с такой точкой зрения
В случаях, когда используется str(n)cat, надо вместо него использовать strlcat безо всяких оговорок. Это не очевидно? Я не говорил, что всегда надо использовать strlcat. Есть случаи, когда лучше делать так, как было предложено Unknown. str(n)cat -- дефективен _всегда_.
нет тут никакого косяка
> Оно реализовано на чистом С без какой-либо BSD-специфики. Никто не мешает взять реализацию и таскать за собой
оно не нужно, т.к. годится разве-что для корявого вывода на экран, потому-что использование обрезанной строки вместо корректного результата - баг в программе
Да-да-да, это очень естественно, в одни стандартные функции передавать 'sizeof(buffer)', в другие -- 'sizeof(buffer) - 1'... Похапе-way во всей красе, ога.
> оно не нужно, т.к. годится разве-что для корявого вывода на экран, потому-что использование обрезанной строки вместо корректного результата - баг в программе
Ещё один апологет идеи "если мне непонятно, для чего что-то нужно -- значит это что-то не нужно никому". Ещё раз -- простая замена str(n)cat на strlcat даже без проверки возвращаемого значения -- минус дофига потенциально ошибочных мест. Проверка возвращаемого значения из strlcat -- минус все ошибочные места данного типа. Замена strlcat на вычисление размера + memcpy + обнуление последнего байта -- уже оптимизация (?), которая нужна далеко не всегда.
> Вредно не знать длины своих строк, а strlncat это поощряет.
А с чего это строки мои?
> Уж если хочется безопасности, лучше g-strconcat
Линковаться с glib не всегда удобно. Ну и у g_strconcat совсем другая семантика, если кто не заметил. А то так лучше вообще APR взять с его пулами. 8))
А вот есть ещё g_strl(cat|cpy) -- ни на какие мысли не наводит? 8))))
> Да-да-да, это очень естественно, в одни стандартные функции передавать 'sizeof(buffer)', в другие -- 'sizeof(buffer) - 1'... Похапе-way во всей красе, ога.
наоборот - пишешь на С, значит должен понимать, что происходит
> Ещё раз -- простая замена str(n)cat на strlcat даже без проверки возвращаемого значения -- минус дофига потенциально ошибочных мест.
как уже писали - если человек не проверяет размеры строк, то это его проблемы, и при "strlcat даже без проверки" - да креша не будет, будут более веселые и трудно отлавливаемые баги - "случайное" удаление не тех данных, мусор в данных, порча содержимого файлов и т.д.
> наоборот - пишешь на С, значит должен понимать, что происходит
Что "наоборот"? Либо везде передаём sizeof(buffer), либо везде передаём sizeof(buffer) - 1. Любой другой вариант (тут передаём одно, там -- другое) дефективен по определению. Это похапе-way.
> как уже писали - если человек не проверяет размеры строк, то это его проблемы
Ещё раз -- есть случаи (и их довольно много), когда обрезание строки не фатально. И когда в таких случаях вместо обрезания строки происходит работа str(n)cat/str(n)cpy -- вылезают дыры в безопасности. Причём это не высосано из пальца, а ровно такая дырка где-то была года два назад -- в формировании строки для лога. Если ты этого не понимаешь -- это твои проблемы, str(n)-семейство менее дефективным от этого не становится.
Ну если строки появились из libastral, то да, но, как правило, строки из ниоткуда не берутся; и про них многое известно. Если имеет место переполнение, то не тупо забивай буфер мусором, а будь добр, прореагируй как-нибудь; до того, как начать бездумное копирование.
Строки могут появляться из генератора псевдослучайных последовательностей aka "пользователь". Ему, например, можно предложить выбор -- ввести строку заново или использовать обрезанный вариант (предварительно его показав, ага). Со strlcat/strlcpy это сделать проще. 8))
> Что "наоборот"? Либо везде передаём sizeof(buffer), либо везде передаём sizeof(buffer) - 1. Любой другой вариант (тут передаём одно, там -- другое) дефективен по определению. Это похапе-way.
лучшего варианта нет
> Ещё раз -- есть случаи (и их довольно много), когда обрезание строки не фатально.
вы не хотите читать, такие "случаи" - это вывод текста для чтения человеком, я же писал про работу с данными, или вы всегда ограничиваетесь "hello, world"?
Лучший вариант -- это всегда передавать sizeof(buffer). Такое откровение в голову не приходило?
> я же писал про работу с данными
Мне наплевать, про что вы писали. Я писал про то, что str(n)cat использовать может только камикадзе. В тех случаях, когда применимо использование этих функций, ВСЕГДА лучше вместо них использовать strlcat. Учитесь читать то, на что вы отвечаете.
> Ещё один не способен читать код на языке C. Там вычисляется длина только dst до копирования. Смотри на функцию внимательнее.
Ещё один не способен читать. Где я написал, что в том коде два раза вычисляется конец строки? да - один раз, зато потом идет побайтовое копирование, которое не эффективно - всегда быстрее копировать блок памяти