
Комментарии 32
да и вообще эти null-terminated string это вещь про которую можно сказать что если бы её никогда не существовало то всем на белом свете было бы легче жить)
Помню они меня так достали в C++ что я написал класс обёртку c операторами приведения во все разумные типы чтобы вообще никогда их не использовать... а потом пол года ещё дебажил сам этот класс)
null-terminated string появились во времена, когда даже 2 байт на длину строки было многовато по памяти.
А олды помнят еще и $-терминированные строки. Как по мне вопрос не в размере, вопрос в однобайтовой ASCII кодировке. В те времена, когда она была достаточной этого хватало. Сегодня... Сегодня сложно. Местами давно надо заменить, но сказать проще чем сделать.
Мне кажется кодировка тут ортогональна.
Различия просто в том как делать: length-value или null-terminated.
Да, когда памяти кот наплакал - хочется сэкономить. Но, как и с nil-ами, кроилово ведёт к попадалову. Вместо того, чтобы сделать заголовок из пары байт - получили вот это, с нулём в конце... и все проблемы с этим связанные.
Различия просто в том как делать: length-value или null-terminated.
Наверное, length-value... если мы уверены, что эта length будет подсчитываться правильно. Сколько, говорите, байтов занимает одна буква?
Или все-таки null-terminated... если мы уверены, что не забыли поставить этот null в нужном месте. Сколько, говорите, байтов занимает одна буква?
Подозреваю, что дело не только в паре байт для указания длины.
null-terminated строки позволяли делать разбор текста (например, когда его вычитали из файла в память) не тратясь на дополнительное копирование, прямо на живом буфере. Натыкал нулей вместо разделителей - и вот тебе отдельные строки (привет, strtok). В те далёкие времена (да и сейчас, в общем-то) такая экономия была существенной.
Если же строки будут с полем длины, то такой финт уже не провернёшь и придётся копировать-перекладывать много-много данных.
(По правильному, ) один из хороших вариантов: для строки хранить два указателя (типа, как структура): начало и символ-за-концом. Но что-то "не взлетает".
А олды помнят еще и $-терминированные строки
"Я не вспоминал int 21h N дней."
Сбрасываю счетчик на ноль. Снова 20-30 лет его копить буду....
Сейчас мы расплачиваемся за эту экономию бесконечными buffer overflow уязвимостями. Длина в начале строки решила бы кучу проблем с безопасностью
Ходят легенды про язык тех времен, где в строке первый байт определял ее размер.
Я думаю что это реально неплохое решение по сравнению с null terminated, сразу точно знаешь сколько памяти выделено.
Че-то прошли мимо того факта, что strncpy работает с байтами, а не с UTF-8 и поэтому может разрезать символ посредине. Хотя да, по сравнению с отсутствием нуля это мелочи. Ужасная функция :)
Хоронили strncpy, порвали два баяна
Там же вроде ядро линукса на раст переписывают? Эта проблема сама бы не ушла, если использовать не С-строки?
Ядро не равно модули ядра. Да и модули как я помню не переписываются, а пишутся новые под новое железо или специфические кейсы
Ничего там не переписывается. Добавили тулчейн чтобы можно было писать что-то в ядре на Расте да и всё.
Переписать всё ядро - понадобится, небось, миллион человеко-лет.
Проблема Си-строк никуда не уйдет, пока жив сишный ABI. Любой язык, который общается с ядром, вынужден подстраиваться под эти нули в конце
Ядро не будут переписывать на rust, только драйвера
Для тех кто хочет переписать на Rust есть https://github.com/asterinas/asterinas
то
strncpyзапишет ровноnбайт и не поставит завершающий\0. Дальше любой...уходит читать за буфер
О, спасибо, что экскурс в историю описали, как он появился. Всегда когда ещё писал на древнем до-ANSI С поражался этой разнице с strcpy. Даже был какой-то паттерн: использовать объявленные константы заданного размера и в них делать strncpy - дикое уродство, но типа безопаснее указателя с strcpy.
Это не про строки вообще.
Замена — это не «найти и поменять на безопасный аналог».
Это не баг в трекере — это код, который надо перечитать.
Постить ИИ текст — это не про качественный постинг.
Зато он избавил нас от цыган strncpy ! (С придыханием) (ц) ;)
Ну, функция стремная, да. Но она протестирована вдоль и поперек? Почему бы не оставить как есть и просто обьявить deprecated ? Она же и в glibc, и в куче программ продолжает торчать. 6 лет переписывали то что и так работает.
по нынешним временам - неизвестно работает или нет. Там могли быть скрытые неочевидные баги, если автор кода не до конца понимал все крайние случаи. Видимо решили, что функция - очевидный code smell, который нужно искоренять.
Deprecated не мешает людям копипастить старый код. Единственный способ избавиться от проблемы - физически удалить ее источник
Self-Protection Project Киса Кука,
СОВПАДЕНИЕ? НЕ ДУМАЮ! /s
Как всё запущено.
Проблема strncpy не только в терминаторе, она еще и кэш убивает своим забиванием нулями хвоста буфера, если строка короткая..
Зачем вообще кто-то придумал строки, заканчивающиеся нулём? Не лучше ли просто хранить длину строки? А ещё хорошо бы и размер буфера хранить. И тогда внезапно все эти переполнения буфера, донимающие нас уже пол-века, были бы не страшны. Не говоря уже про strlen(), выполняющийся за О(1).
С интересом наблюдаю за изобретающими Pascal-строки...
На тех граблях уже попрыгали, и перешли на нормальные null-terminated. Но нет, надо попрыгать снова, потому что кому-то лень думать о том, что делает функция, за него компилятор думать должен, и защищать от мошенников выхода за пределы буфера.
Из ядра Linux выпилили strncpy: шесть лет, 362 коммита, одна функция