В HTTP-сервере muhttpd, применяемом преимущественно в маршрутизаторах и точках доступа, выявлена уязвимость (CVE-2022-31793), позволяющая неаутентифицированному атакующему через отправку специально оформленного HTTP-запроса загрузить произвольные файлы, насколько это позволяют права доступа, под которыми выполняется HTTP-сервер (во многих устройствах muhttpd запускается с правами root). Например, атакующий может получить доступа к файлам с паролями, настройками беспроводного доступа, параметрами подключения к провайдеру и закрытыми ключами...Подробнее: https://www.opennet.me/opennews/art.shtml?num=57601
Не уязвимость, а канал доступа. Красиво, вряд ли только сейчас нашли. Это примерно как у многих сайтов ластик в интернет вывешен или VNC без пароля, только лучше.
А писали бы на единственной безопасном и быстром языке Carbon, то уязвимость они бы все равно нашил куда вставить.
Что-то подсказывает что лажаться с обработкой путей кодеры будут одинаково, хоть на брейнфаке.
Чтобы не лажаться с обработкой путей, нужна capability-based security model. Но unix-way - это продолжать жрать кактус.
> нужна capability-based security modelкоторую изобрели в unix системах
> Чтобы не лажаться с обработкой путей, нужна capability-based security model.В линухе оно даже есть. Как и контейнеры позволяющие довольно эффективно отрезать сервер в его загон когда выйти довольно проблематично.
Пара нюансов?
1) У вон тех может быть инновационный кернел типа 2.6.32 где наиболее эффективных фич конечно же нет. Оно было в каком году вообще? Я даже и не помню этого уже.
2) Насколько там всем было на безопасность - намекает пуск вебсервака под рутом. Думаете вон ТЕ станут заморачиватья чем-то более продвинутым? Плин, там фирмварь делана жоскими индусами которые рады по уши что доисторический CrapDK от вендора вообще что-то работающее выдал, все, узкоглазикам из *-link или чего там еще можно идти это продавать :)
Правильно, пока ты будешь имплементировать свою продуманную архитектуру, санитизировать каждый пук, прилетающий извне и огораживать все компоненты капабилитями, вон те выкинут на рынок дешёвую поделку, сделанную по принципу "тяп-ляп и в продакшон". И твоя железка будет интересна только кучке гиков, которые имеют неприличную манеру совать нос под капот.
> Правильно, пока ты будешь имплементировать свою продуманную архитектуру, санитизировать
> каждый пук, прилетающий извне и огораживать все компоненты капабилитями, вон те
> выкинут на рынок дешёвую поделку, сделанную по принципу "тяп-ляп и в
> продакшон". И твоя железка будет интересна только кучке гиков, которые имеют
> неприличную манеру совать нос под капот.Ну да, ну да, поэтому хомякам придется жить с д@рьмовыми железками где фирварь писана полоумными макакаами. Наслаждаясь червяками в интранете, а особо неудачливые и массажем почек от майора "потому что мсг был с твоего айпишника, с*ка!!!1111". А я пойду окучивать все же несколько менее хомякообразных, которые за каждый #$%ный цент все же не трясутся и лучше понимают что хотят. Так устроен этот мир: любую работу можно сделать быстро, дешево и качественно. Выберите любые 2 из 3.
Чтобы не лажаться с чем бы то ни было, надо думать головой. А владельцу бизнеса или лицу, принимающему решения - думать головой, чтобы наннимать разрабов, которые думают головой.
А на случай лажи, которую почему-то не получилось избежать - да, использовать в том числе и capability-based security model.
Странно, а я думал, что быстрый и безопасный это раст. Учу программирование строго по опеннету, если что.
А вот ужасный сустемдэ своим сервисом изолировал бы юзерспейс!
Он 2 метра RAM жрет, а в том крапе всей оперативы 16..32 мега и ее впритык :)
Ты бы еще в докере предложил запустить.
Ох уж эти писатели на js. Смузихлёбы. Бу-бу-бу. А хотя подождите. Неужели богоподобный с++ такое позволил. Неуто программист еа сверхязыке на такое способен?
Твой мир сейчас перевернетсяс ног на голову, но уязвимость можно оставлять даже специально, решительно на любом языке.
А где ты там C++ нашёл?
Ох уж эти писатели на js. Смузихлёбы. Бу-бу-бу. А хотя подождите-ка, смузихлёбы даже C++ от C не отличают.
> Ох уж эти писатели на js. Смузихлёбы. Бу-бу-бу. А хотя подождите-ка, смузихлёбы даже C++ от C не отличают.А разве находился хоть раз защитник сишки, способный отличить java от javascript?
Всегда тут был, но ты в это не поверишь.
И чем эти 2 интерпретируемые смузиязычка отличаются?
Там что джава рулит, а джаваскрипт сосёт.
Тут большинство умеющих в Си, умеют и в js и в java и во много ещё что.
Но не умеют в корректный hello world на Сишке;)))Это мы уже проверяли в прошлых комментариях. Undefined Behaviour в printf :)
Приблизительно также они умеют и во всё остальное.
Предлагаю различать тех кто "умеет" и "считает, что умеет". Первых тут тоже хватает.
Вон то можно влепить на любом ЯПе.Ну а если ты думаешь что офигенно умный, можешь попробовать накодить свой HTTP 1.1 сервер, хоть на жыэсе. Вместе поржом сколько вулнов будет у тебя. А их там будет, почти наверняка, и вероятно - сильно поболее чем у какого-то малоизвестного сервачка с сайтом еще аж на сорсфорже.
> разработчики подразумевали, что первый символ всегда "/"Взоржал.
Ужас какой! Вы прикрывайте дырки, а то имеет все кто хочит!
Ну и дырыще!
Вот тебе и дебиан!
Нет такого пакета в этой репе! Сектор Б на барабане. Поздравляем, Вы - банкрот!
Даже и не знал что такой сервер вообще есть.
Эффективный опенсорс...
> muhttpd (mu HTTP daemon) is a simple but versatile web server written in portable ANSI CНо это, конечно же, были ненастоящие программисты на C. Настоящие такой лажи никогда не допустили бы, такие ошибки можно на любом языке сделать и вообще в вашем смузикрипте тоже дыр полно!
Падаждите, а куда смотрели тысячи глаз? На три другие стены?
вытекли :)
Они как раз и нашли эти уязвимости.
Ахаха, ты серьезно?
"Проблема присутствует начиная с самой первой версии muhttpd ..." это с 2007 года (надеюсь, иначе вообще с 2002)!
Учитывая, что я вообще впервые слышу про такой веб-сервер, глаз там было по числу коммитеров умножить на полтора. :)
Ну ты может и в первый раз слышишь, а его используют серьезные ынтерпрайз конторы типа "AT&T, Frontier и Windstream"
На расте такой дыры не было бы?
Слышал песню от группы Ленинград под названием Дорожная?
Растишка втуда где это используется без утрамбовки не залезет.
В расте такая болезненная работа с путями, что там даже никогда не заметили бы проблемы за мишурой из бесконечных кастов OSString в String, Path в PathBuf, ResultReadDir в ReadDir в IteratorResultDirEntry в IteratorDirEntry в DisplayDirEntryPathExt и обратно.
> В расте такая болезненная работа с путями, что там даже никогда не
> заметили бы проблемы за мишурой из бесконечных кастов OSString в String,
> Path в PathBuf, ResultReadDir в ReadDir в IteratorResultDirEntry в IteratorDirEntry в
> DisplayDirEntryPathExt и обратно.В смысле, кодер за...тся кодить быстрее чем вообще сервак родит? Тоже вариант! Но если все же упрямый кодер попадется - то он тоже так сможет. А судя по конверсиям, там еще может быть и с десяток CVE уникальных для хруста, чего доброго. Поди палочкой еще никто не тыкал это счастье :)
> Поди палочкой еще никто не тыкал это счастьеRust палочкой не тыкали? Это C и C++ палочкой не тыкали, с rust'ом же всё резко серьёзнее: https://ferrous-systems.com/blog/the-ferrocene-language-spec.../
> rust'ом же всё резко серьёзнее: https://ferrous-systems.com/blog/the-ferrocene-language-spec.../Что це таке? Какие-то проприентарщики с очередным "qualified rust toolchain" который будет запроприетарен еще хуже misra C? Ну и насколько все это будет соответствовать обычным тулчейнам? И по описанию - какой-то жесточайший WIP, при том не понятно как согласованый с вон теми кодерасами дефолтной реализации.
Сишники в этом плане кстати облажались. В gcc предлагали MSIRAовский чекер добавить но редгадчики брыкались. Мол только для эмбедовки, блабла. Ну, если им CVE больше нравятся, тогда только для эмбедовки, конечно :).
Так что на самом деле опенсорсный тулчейн такого плана был бы EPIC WIN. Особенно если в популярных реализациях сразу встроен и широко используем в софте.
> В расте такая болезненная работа с путями, что там даже никогда не
> заметили бы проблемы за мишурой из бесконечных кастов OSString в String,
> Path в PathBuf, ResultReadDir в ReadDir в IteratorResultDirEntry в IteratorDirEntry в
> DisplayDirEntryPathExt и обратно.Интересно а в всем этом не будет новых бонусных вулнов как это уже было в их stdlib'е? :)
muahahahttpd
Ну конечно "разработчики" эмбедовки тоже кони ещё те. С цирком.
httpd от рута - это прелесть просто.
Да это обычно обдолбаные узкоглазики которые койкак слабали вообще и скорее продавать.
Недырявый домашний роутер - это что-то вообще из области фантастики )
Хотите за 30 баксов и еще чтоб безопасно?
Никакой фантастики. Дайте железо и дрова, а линукс и прочий софт я сам накачу. А если в линуксе найдут дыру - обновлю линукс, это не проблема. Зачем вообще из эмбед делать отдельную сущность? Все те механизмы, которые работают на десктопах и сереверах, будут обеспечивать безопасность и на эмбеде.
О существовании некоторых вебсерверов (и некоторого другого софта) узнаешь из сообщений об уязвимостях в них
muhttpd? щито?
То что модератор удалил все комментарии про то что уязвимость очевидно вставлена намеренно лишь подтверждает этот факт.
20 лет назад... иис... дежавю....
дайте угадаю,. следующая найденная там уязвимость будет
GET /../../../../../../../etc/passwd
?
потому что 'используя технику "DNS rebinding"' затруднительно пинуть именно "a/etc/passwd" - браузер надо еще както заставить такое выдать. А вот /../../../../../../../etc/passwd вообще не проблема...
> браузер надо еще както заставитьНастоящий хакер (крякер тем более) работает с сетью только через браузер.
Ты что, хакир, что ли?
extern char **environ;int clearenv(void) {
/* We would like to free previously set environment variables here,
* but at least FreeBSD 5.1 doesn't let us */
/* Create empty environment */
environ = malloc(sizeof(char*));
if(environ) {
*environ = NULL;
}return 0;
}Беллиссимо. Это не местные ыксперты писали, которые в новости про Rust бегают?
А что тебе не нравится?
Серьёзно? Местных сишников послушать - так они лучшие в мире и никогда не делают ошибок, а ты очевидных косяков не видишь :)Во-первых, вместо этой портянки
environ = malloc(sizeof(char*));
if(environ) {
*environ = NULL;
}достаточно написать
environ = calloc(sizeof(char*), 1);
т.к. NULL в C - это просто ноль, приведённый к типу void*.
Во-вторых, тут как в анекдоте: вы или штаны наденьте, или крестик снимите. Зачем clearenv() возвращать int, если она всегда возвращает ноль? Тут уж или void clearenv(), или давайте возвращать ещё что-то кроме нуля.
В-третьих, если функция возвращает некие коды, неплохо бы их объявить, а не просто return 0. Вернуть ноль любой дурак может, а вот чтобы понять, что он значит в этой функции, нужно уже лезть в исходник,
В-чертвёртых, комментарий "Create empty environment" должен комментировать функцию, а не её внутренности. И вообще, он должен быть в заголовочном файле.
В общем, как-то так:
---- clearenv.h ----
#define CLEARENV_SUCCESS 0
#define CLEARENV_FAILURE -1/* Create empty environment */
int clearenv(void);---- clearenv.c ----
int clearenv(void) {
/* We would like to free previously set environment variables here,
* but at least FreeBSD 5.1 doesn't let us */
environ = calloc(sizeof(char*), 1);
return environ ? CLEARENV_SUCCESS : CLEARENV_FAILURE;
}
Это всё, что ты перечислил, стилевые придирки. Которые совершенно нерелевантны для функции, назначение которой прозрачно из её имени, которая небось вызывается один раз и этот код выделен в функцию, только чтобы main почище был бы. Ты не читал аргументацию Кармака, почему DRY плох и почему его надо заменять на WET? Один из ключевых аргументов в том, что имея перед глазами два примера полезености куска кода, ты не можешь обобщить этот код и осмысленно выделить в функцию. Поэтому момент выделения в функцию надо откладывать как можно дольше, но за пределы WET откладывать может быть неудобно по другим причинам, поэтому WET. Здесь есть _одно_ использование функции, а значит осмысленно обобщить её не удастся. Зачем пытаться тогда совершить невозможное?Что мне непонятно в этом коде, так это нахрена нужен malloc. Видимо исходной задумкой было освободить "груду" памяти, выкинув из неё environment, а когда не нашлось кроссплатформенного способа, кроме exec'а с пустым envp, они оставили то, что оставили. При этом функция может сделать так, чтобы environ==NULL, или чтобы он указывал в кучу... Неясно, зачем выделять память, если ок и норм сделать environ=NULL.
> В общем, как-то так:
Руки отрывать за такое. Столько писанины ради двух строк функции. Это корпоративный подход, который приводит к тому, что никому не нужного бойлерплейта оказывается больше, чем реально работающего кода. Достаточно один раз договориться, какое возвращаемое мы считаем успехом по-дефолту. Для такого C, который вокруг сисколлов бродит постоянно, я б, как и ты, выбрал -1, для обозначения фейла, и >=0 для успеха. Но я б не парился декларировать какие-то там дефайны: толку от них? Ну вот кроме упёртого следования стилю, который препод с тебя требует, какой смысл?
Если уж muhttpd готов работать при environ == NULL, то это делается так:
int clearenv() {
environ = NULL;
return 0;
}Если не готов, и это отсутствие стали в хребте сделать exit(1) при обломе malloc, то:
int clearenv() {
environ = malloc(sizeof(char**));
if(environ == NULL) {
fputs("Go buy some RAM, moron\n", stderr);
abort();
}
*environ = NULL;
return 0;
}> т.к. NULL в C - это просто ноль, приведённый к типу void*.
Типа в стандарте так написано, или ты на своей системе проверил, и решил, что так везде? Я лично не очень доверяю этому. Не знаю, почему.
> Зачем clearenv() возвращать int, если она всегда возвращает ноль?
Чтобы когда и если она начнёт возвращать не только 0, вызывающий код был бы к этому уже готов. Глупость конечно же, можно найти все вхождения и поправить. Но люди делают так часто.
> И вообще, он должен быть в заголовочном файле.
Нет. В заголовочных файлах должно быть только то, что используется из других "модулей". Те же функции, которые эффективно static функции, противопоказано совать в заголовочные файлы. Вот атрибут static на неё повесить не помешало бы. Но в принципе, какая хрень. muhttpd не firefox, у него сколько там символов на круг получается по всем .o файлам? Смысла нет заботиться о снижении их числа, компиляция всё равно околомоментальна.
> Ты не читал аргументацию Кармака, почему DRY плох и почему его надо заменять на WET?...
> Здесь есть _одно_ использование функции, а значит осмысленно обобщить её не удастся. Зачем пытаться тогда совершить невозможное?Какое отношение всё это имеет к обсуждаемой функции? Какое обобщение? Я вообще об этом даже не заикался.
> Типа в стандарте так написано, или ты на своей системе проверил, и решил, что так везде? Я лично не очень доверяю этому. Не знаю, почему.
Вот вместо написания этих двух предложений лучше бы почитал стандарт и убедился. Люди уже гуглить обленились, дожили.
> Достаточно один раз договориться
Ну и как там процесс идёт? Разработчики библиотек между собой уже договорились? А с разработчиками приложений? А то здесь одни значения успеха, там другие, а потом это всё сходится в одном приложении и приходится каждый раз лазить в доки, потому что невозможно удержать в голове, какие из 200 используемых функций из разных библиотек придерживаются какого стиля.
Вообще, я уже устал дискутировать, на остальное отвечать просто лень. Всё равно понятно, что здесь собрались эксперты мирового класса, мне таких не переспорить. ВСЁ, что я пишу, постоянно оспаривается, как будто из принципа, а собственные косяки мои оппоненты или замалчивают, или преподносят как истину. Видите ли, раньше все нормальные люди писали дефайны кодов ошибок, как в тех же *nix ОС, и это считалось правильно, а сегодня пришёл Аноним и заявил, что это - корпоративное уфло. Ну ок.
> Какое обобщение? Я вообще об этом даже не заикался.Да, я знаю, именно поэтому мне пришлось об этом говорить. Если рассмотреть функцию, как способ повторного использования кода, а потом заметить, что в разных случаях немного разный код нужен, но можно вычленить общее, а вариации оставить вызывающей стороне. Или добавить аргументов функции, управляющих её поведением.
Но это возможно только тогда, когда у тебя перед глазами есть несколько кусков кода, которые можно вынести в одну функцию и обобщить. Здесь же иная ситуация, код вынесен в функцию не для повторного использования, а для того, чтобы повысить читаемость, заменив сколько-то там строк кода на одну: clearenv(), которая сразу видно что делает. В этом случае нечего обобщать. Невозможно обобщать на одном примере.
Так понятнее стало?
> Вот вместо написания этих двух предложений лучше бы почитал стандарт и убедился.
Вот ещё. Делать мне больше нечего. Мне больше нравится ptr = NULL. Я не знаю почему, но в таких вопросах я привык доверять интуиции. Она не подводит, и избавляет от нужды читать долбаные стандарты.
> Ну и как там процесс идёт? Разработчики библиотек между собой уже договорились?
Речь идёт о договорённости действующих на данной программе. На большее у C возможностей нет. Из тех решений, которые возможны в C, нет одного, которое было бы приемлимо во всех случаях. Но на одну программу, тем более размера muhttpd вполне можно иметь договорённости. И _нужно_, все разумные люди это делают, пускай и неявно, без прописывания в CoC или куда они там пишут такие правила.
> я уже устал дискутировать
Ты ещё не начал. В смысле вот это твоё сообщение -- это первый ответ в дискуссии, предыдущее сообщение было лишь постулированием твоей позиции.
Усталось всегда возникает симптомом, когда сливаешь дискуссию.
> Так понятнее стало?Нет, мне не стало понятнее, с чего вдруг ты вообще заговорил про обобщение и выделение в функции. Вот представь себе, что мы обсуждаем температуру воздуха - например, при какой человеку комфортнее заниматься физкультурой, и я внезапно начинаю говорить о том, как важны пропорции кислорода и азота, ведь если бы кислорода стало не 21%, как сейчас, а 51%, мы бы все сгорели в глобальном планетарном пожаре. Мысль, безусловно, имеющая смысл, но не имеющая никакого отношения к обсуждаемой теме.
> Вот ещё. Делать мне больше нечего.
> Я не знаю почему, но в таких вопросах я привык доверять интуиции.Я искренне не понимаю: это такой тонкий троллинг, или ты на полном серьёзе сейчас кичишься своей безграмотностью в данном вопросе?
> Усталось всегда возникает симптомом, когда сливаешь дискуссию.
Ещё она возникает после общения с десятком таких, как ты, "экспертов" с чутьём и интуицией вместо знаний, которые постоянно выдают абсолютные утверждения вроде этого, призванные впечатлить местную школоту, которая ведётся на уверенных в себе дерзких "лидеров". Главное - выглядеть уверенным, тогда схавают любую ахинею. Принцип тот же, что и в политике.
> Нет, мне не стало понятнее, с чего вдруг ты вообще заговорил про обобщение и выделение в функции.Я не знаю чем тут можно помочь. Могу ещё попробовать так: есть разные причины выделения кода в функцию, разные причины приводят к разным требованиям, которые предъявляются к функции, в частности и к разным стилям оформления функции. Скажем, зачем нужен документационный комментарий к static функции? Она всё равно не пойдёт в документацию, куда собирают внешние API.
Если это не помогает, то я сдаюсь. Я бессилен тебе что-либо объяснить. Может поймёшь, накопив опыта.
> Я искренне не понимаю: это такой тонкий троллинг, или ты на полном серьёзе сейчас кичишься своей безграмотностью в данном вопросе?
Грамотность переоценена. Вопрос в том, в состоянии ли ты написать надёжный работающий код или нет, а не в том, насколько ты грамотен или безграмотен. Мой подход позволяет мне писать код, который проходит все ревью, и потом просто работает. Насколько при этом я грамотен или безграмотен мне без разницы. И этот мой подход включает в себя отказ рыться в стандартах, если у меня есть сомнения, которые мне необходимо разрешить, я лучше с экспертом пообщаюсь, чем буду читать какой-то там стандарт. Если же я могу сомнения разрешить без эксперта и без стандарта, я их разрешу так. А если я могу обойтись без разрешения сомнений, написав ptr=NULL, то обойдусь без разрешения и напишу ptr=NULL, сэкономив кучу времени на этом.
Стандарт надо читать тогда, когда время потраченное на чтение стандарта, сэкономит тебе потом больше времени. Но я вышел из того возраста, когда мне помогало. Я отрастил интуицию, она практически всегда верна, и не бывает такого, чтобы она ошибалась не вызывая у меня чувства сомнения, ориентируясь на которое я могу дополнить интуицию дополнительными проверками.
> Скажем, зачем нужен документационный комментарий к static функции?
> Она всё равно не пойдёт в документацию, куда собирают внешние API.Намного короче и понятнее, чем предыдущие портянки текста. Более того, можно было сократить даже до одного предложения.
> Грамотность переоценена.
> Насколько при этом я грамотен или безграмотен мне без разницы.
> я лучше с экспертом пообщаюсь, чем буду читать какой-то там стандартА, ну понятно. Это "эксперты" вроде тебя, значит, комментят под новостями о Rust. Всё встало на свои места. А я и думаю, почему аргументы и факты не работают? Да потому что факты у них "переоценены".
> Намного короче и понятнее, чем предыдущие портянки текста. Более того, можно было сократить даже до одного предложения.А, у тебя проблемы с длинными предложениями? Надо простые писать? Не осложнённые всякими деепричастными оборотами, так? И уж тем более не составные. Ок.
> А, ну понятно.
Нет. Ты опять не понял. Там опять были сложные предложения. Давай я тебе простыми изложу.
Инженерное дело -- это не о том, что ты наизусть помнишь. Инженерное дело о том, какую информацию ты можешь найти. И об умении опознать ситуацию, в которой надо искать.
Наизусть запоминать -- это уровень undergraduate студента. Потому что их академическая успешность измеряется способностью воспроизводить по памяти никому не нужные заученные знания.
/* Длинное предложение получилось, да? Давай я про инженеров скажу, там короче выйдет: */
Успешность инженера определяется не тем, как много стандартов он заучил. Успешность инженера определяется качеством произведённого им продукта.
> о Rust
Кто о чём, а опеннет о расте. Речь о C идёт, ты не заметил?
> NULL в C - это просто ноль, приведённый к типу void*Вообще нет. NULL - это не ноль. NULL - это именно специальное значение NULL, которое зависит от платформы. То, что в большинстве реализаций оно является нулём, не делает его нулём.
А с таким подходом ты можешь круто обосраться при переносе кода.
Понятно, здесь не умеют гуглить. Так и быть, сделаю это за вас:
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf6.3.2.3 Pointers
An integer constant expression with the value 0, or such an expression cast to type
void *, is called a null pointer constant. If a null pointer constant is converted to a
pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal
to a pointer to any object or function.Надеюсь, никто не будет спорить с тем, что "целая константа со значением ноль" не зависит от платформы.
Теперь погугли, что делает calloc: кастует нулевые байты в нулевые указатели?
Это уже все рамки разумного переходит.Во-первых, кастовать не обязательно: "An integer constant expression with the value 0, OR such an expression cast to type void *". Во-вторых, найди мне в стандарте место, где говорится, что указатель, которому присвоили ноль, может по воле компилятора оказаться не нулевым.
Является ли блок из нулевых байтов "An integer constant expression with the value 0"?Или (чтобы не было UB) надо сперва записать в блок по адресу "нулевой указатель", чтобы потом прочитать по этому адресу тот самый "нулевой указатель"?
Знаешь, а ты прав. Я тут почитал доп. инфу и понял, что могут быть архитектуры, где null pointer не нулевой и не равен null pointer constant. При этом сравнение первого со вторым будет возвращать true, несмотря на фактически разные значения. И вообще, получается, что ты присваиваешь чему-то ноль, а там после этого не ноль. Пожалуй, это хорошо, что я уже давно не пишу на C - не только для пользователей, но и для моей психики.
Вот ты лучше расскажи своей логикой растомана. Почему, записывая массив байтов из нулей, хочешь из этого массива байтов прочитать (валидный) указатель? Раст позволяет такие вольности с преобразованиями типов?
Вообще-то, это обычная логика. По-твоему, логично, что сущность с названием null pointer может быть не равна нулю? Почему-то null pointer constant всегда равна нулю, а null pointer - нет. Логично то, что можно получить не ноль, присвоив чему-то ноль в языке без перегрузки операторов? Логично то, что сравнение ненулевого значения с нулём возвращает true? Все смеются над JavaScript с его неявными преобразованиями, но кода это касаеться C - "это другое". Это не моя логика "неправильная", а в C логика не работает, потому что комитет стандартизации решил использовать ноль для обозначения невалидного указателя, а потом оказалось, что где-то нулевой адрес вполне легитимен, и теперь мы имеем терминологию, имеющую лишь косвенное отношение к реальности, и поведение компилятора, которое в народе называется ugly hacks. Но, конечно, это моя вина, что я не прочитал ВЕСЬ стандарт, а там наверняка где-то написано, что null pointer - это не всегда null. Ну и, конечно, всё-таки, лучше использовать специальную константу NULL и не выпендриваться, учитывая количество подводных камней в C.Что касается Rust, там в 99.9% случаев вообще нет необходимости в сырых указателях, и код, аналогичный по смыслу clearenv(), будет написан совершенно иначе, примерно так:
use std::sync::Mutex;
pub enum ClearEnvError {
MutexLock
}pub fn clear_env() -> Result<(), ClearEnvError> {
extern {
static ENVIRON: Mutex<Vec<String>>;
}unsafe { ENVIRON.lock() }
.map(|mut environ| environ.clear())
.map_err(|_| ClearEnvError::MutexLock)
}Здесь есть и обработка ошибок и примитив синхронизации, необходимый для вызова функции из других потоков. Самое прекрасное - компилятор практически заставит всё это сделать, и чтобы накосячить, придётся дополнительно постараться.
Но если всё же понадобится иметь дело с сырыми указателями, то я просто прочитаю соответствующие главы документации и Rustonomicon, прежде, чем приступать к делу. И, конечно, споткнувшись в этой ветке на приколы с сишным понятием null pointer, на этот раз я буду читать доки внимательнее, хоть они и намного понятнее, чем стандарт C.
> По-твоему, логично, что сущность с названием null pointer может быть не равна нулю?Ты прочитал, что делает calloc?
Правильно. Выделяет массив байт и обнуляет этот массив байт.
Где ты увидел (нулевой) указатель? Причем тут "null pointer constant", который имеет смысл только во время компиляции?
Что надо сделать, чтобы появился указатель? Надо сперва записать указатель в то место, откуда потом будешь читать. Обнуление байтов - это не запись указателя.
Общее правило: перед тем как читать из памяти данные определенного типа, надо туда записать данное того же типа.
Конечно, есть некоторые правила бинарного представления типов данных: типа целые - в дополнительном коде, си-строки - последовательность ненулевых байт заканчивающаяся нулевым байтом и т.п.
Итак, после обсуждения ниже выяснилось, что в C, когда имеешь дело с указателями, ноль может стать не нулём, а не ноль может быть равным нулю. Простой язык, говорили они. Ну что же, получается, с calloc я сел в лужу, и код принимает такой вид:int clearenv(void) {
/* We would like to free previously set environment variables here,
* but at least FreeBSD 5.1 doesn't let us */
environ = malloc(sizeof(char*));
if (environ)
*environ = NULL;
return environ ? CLEARENV_SUCCESS : CLEARENV_FAILURE;
}
Он как ыксперт по безопасным каракулям руст не разобрался в опасных каракулях си и увидел обнуление после malloc, и хотел сказать, что ржавчина на серебряных пулях уничтожает таких монстров до полного обнуления.
Очередной бессмысленный комментарий от очередного недалёкого анона. Бессмысленный он хотя бы потому, что оставлен уже после обсуждения того, что конкретно мне не нравится в коде. Я там факты привожу, почитай. Ты же умеешь читать код на C?
Ожидал всего что угодно, но такого. Они просто читают файл по относительному пути без каких либо проверок. Этот сервер писали школьники на уроках информатики?