Обновить

Комментарии 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 в нужном месте. Сколько, говорите, байтов занимает одна буква?

С нулем прелесть в том, что некоторые функции гарантируют 0 в конце буфера, некоторые нет, некоторые забивают нулями буфер до конца. Походу проектировались они разными людьми.

Подозреваю, что дело не только в паре байт для указания длины.

null-terminated строки позволяли делать разбор текста (например, когда его вычитали из файла в память) не тратясь на дополнительное копирование, прямо на живом буфере. Натыкал нулей вместо разделителей - и вот тебе отдельные строки (привет, strtok). В те далёкие времена (да и сейчас, в общем-то) такая экономия была существенной.

Если же строки будут с полем длины, то такой финт уже не провернёшь и придётся копировать-перекладывать много-много данных.

(По правильному, ) один из хороших вариантов: для строки хранить два указателя (типа, как структура): начало и символ-за-концом. Но что-то "не взлетает".

А олды помнят еще и $-терминированные строки

"Я не вспоминал int 21h N дней."

Сбрасываю счетчик на ноль. Снова 20-30 лет его копить буду....

Сейчас мы расплачиваемся за эту экономию бесконечными buffer overflow уязвимостями. Длина в начале строки решила бы кучу проблем с безопасностью

Стек адресов возврата, отделённый от стека данных, решил бы кучу проблем с безопасностью...

Ходят легенды про язык тех времен, где в строке первый байт определял ее размер.

Я думаю что это реально неплохое решение по сравнению с null terminated, сразу точно знаешь сколько памяти выделено.

256 байтов тогда всем хватало ;)

Зато любая операция со строками == неочевидная пляска с выделением памяти под капотом. Или как там оно внутри устроено?

Че-то прошли мимо того факта, что strncpy работает с байтами, а не с UTF-8 и поэтому может разрезать символ посредине. Хотя да, по сравнению с отсутствием нуля это мелочи. Ужасная функция :)

Не думаю, что в 95% кода всего ядра нужно что-то кроме ascii

Хоронили strncpy, порвали два баяна

Там же вроде ядро линукса на раст переписывают? Эта проблема сама бы не ушла, если использовать не С-строки?

Ядро не равно модули ядра. Да и модули как я помню не переписываются, а пишутся новые под новое железо или специфические кейсы

Ничего там не переписывается. Добавили тулчейн чтобы можно было писать что-то в ядре на Расте да и всё.

Переписать всё ядро - понадобится, небось, миллион человеко-лет.

Проблема Си-строк никуда не уйдет, пока жив сишный ABI. Любой язык, который общается с ядром, вынужден подстраиваться под эти нули в конце

Ядро не будут переписывать на rust, только драйвера
Для тех кто хочет переписать на Rust есть https://github.com/asterinas/asterinas

то strncpy запишет ровно n байт и не поставит завершающий \0. Дальше любой ... уходит читать за буфер

О, спасибо, что экскурс в историю описали, как он появился. Всегда когда ещё писал на древнем до-ANSI С поражался этой разнице с strcpy. Даже был какой-то паттерн: использовать объявленные константы заданного размера и в них делать strncpy - дикое уродство, но типа безопаснее указателя с strcpy.

Это не про строки вообще.

Замена — это не «найти и поменять на безопасный аналог».

Это не баг в трекере — это код, который надо перечитать.

Постить ИИ текст — это не про качественный постинг.

Зато он избавил нас от цыган strncpy ! (С придыханием) (ц) ;)

Ну, функция стремная, да. Но она протестирована вдоль и поперек? Почему бы не оставить как есть и просто обьявить deprecated ? Она же и в glibc, и в куче программ продолжает торчать. 6 лет переписывали то что и так работает.

по нынешним временам - неизвестно работает или нет. Там могли быть скрытые неочевидные баги, если автор кода не до конца понимал все крайние случаи. Видимо решили, что функция - очевидный code smell, который нужно искоренять.

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

Как всё запущено.

Проблема strncpy не только в терминаторе, она еще и кэш убивает своим забиванием нулями хвоста буфера, если строка короткая..

Зачем вообще кто-то придумал строки, заканчивающиеся нулём? Не лучше ли просто хранить длину строки? А ещё хорошо бы и размер буфера хранить. И тогда внезапно все эти переполнения буфера, донимающие нас уже пол-века, были бы не страшны. Не говоря уже про strlen(), выполняющийся за О(1).

А что ещё Вы хотите похранить на машине с 16 КБ памяти?

И что, теперь куча старого софта тупо перестала компилироваться?

Нет, функцию убрали из кода ядра. В libc она никуда не делась.

С интересом наблюдаю за изобретающими Pascal-строки...

На тех граблях уже попрыгали, и перешли на нормальные null-terminated. Но нет, надо попрыгать снова, потому что кому-то лень думать о том, что делает функция, за него компилятор думать должен, и защищать от мошенников выхода за пределы буфера.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации