Pull to refresh

Comments 470

уязвимости будут всегда, пофиг какой язык

Вопрос в количестве уязвимостей.

Если язык способствуют созданию ошибок, то количество уязвимостей всегда будет больше, чем если используется относительно безопасный язык. Даже у очень умных и опытных программистов.
Если какой то язык становится популярным, то на нем начинаю программировать люди разной квалификации. И те у которых она не высокая, смогут завсегда сделать что то такое что приведет к уязвимости. И что то мне кажется хотя я возможно и не прав, но чем популярней язык тем больше в нем низкоквалифицированных людей(ничего плохого, это норма) и значит больше которые совершенны при помощи него. И то что там memory safe не спасёт их от другой кучи ошибок, которые порадят уязвимости.
Вот да. Уязвимость — в первую очередь ошибка и/или допущение в алгоритме. Не важно, на каком языке, например, писать веб-форму для записи в бд. Если запросы к бд строятся конкатенацией строк да без фильтрации — однажды обязательно прилетит DROP DATABASE; как значение поля и выполнится.
Ну теоретически можно уменьшить вероятность этого техническими средствами. Например, если входящие строки имеют тип ExternalString, а строковые константы из исходников InternalString, и их можно приводить друг к другу без создания нового объекта, но только явно, то компилятор покажет ошибку типа «Cannot concat InternalString with ExternalString». Автор задумается и поищет информацию почему так, и уязвимость появится только из-за намеренных действий.
И автор найдёт, как прикастить ExternalString к InternalString и добавит один каст и всё будет работать. Как будто вы не видели небезопасный код, проходящий проверку всеми статическими анализаторами.
Ну это и будут намеренные действия. Большинство SQL-инъекций все-таки не намеренно делают, а потому что «работает же».
Где вы видите намеренные действия? Низкоквалифицированный программист написал код с инъекцией, например так:
ExternalString userInput = myWebSocketClient.receive();
InternalString query = "SELECT password FROM `users` WHERE username = " + userInput;
myDatabase.query(query);

Компилятор рассказал ему, что нельзя конкатить ExternalString и InternalString, на что программист ответил «ну ладно» и написал
ExternalString userInput = myWebSocketClient.receive();
InternalString query = "SELECT password FROM `users` WHERE username = " + (InternalString) userInput;
myDatabase.query(query);

Вот и уязвимость.

Добавление (InternalString) само произошло, или все-таки программист намеренно написал? Кто-то просто напишет, а кто-то задумается и поищет информацию, почему возникает ошибка, и найдет что конкатенировать внешние данные с внутренними приводит к инъекциям. То есть это уменьшает вероятность появления инъекции в коде на этом языке. Низкоквалифицированные программисты низкоквалифицированны потому что не знают, а не потому что специально вносят баги. А если компилятор ничего не говорит, то и нет повода что-то узнавать.

Кто-то просто напишет, а кто-то задумается и поищет информацию, почему возникает ошибка,

Один то может задумается, а потом придет «обезьянка» и тупо у себя в коде точно так-же нафигачит, потому что Большой Тим Лид тоже ваяет именно так. Это никак не решает проблему.
Проблему не решает, а вероятность уменьшает. Тесты тоже можно неправильно написать, это ведь не значит, что тестами не надо пользоваться.

А еще обезьянка может по умному совету со StackOverflow rm -rf / куда-нибудь вставить.

Вы так говорите, будто этого никто не делал.
sudo только не забудьте.
Инсталлятор NVidia-драйверов запускался с root-правами )))
UFO just landed and posted this here

Естественно, делал.
Более того, недавно я даже стал этому свидетелем)
Но это же не повод отменить разграничение прав?
Аналогично, возможность понаделать небезопасных кастов не повод отказаться от защиты от инъекний на уровне типов.

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

Но при прочих равных условиях (в т.ч. квалификации программистов) на условном C уязвимостей будет больше, чем на условной Java.

Можно попытаться сравнить число уязвимостей в проекте, написанном супер-профессионалами на C с числом уязвимостей в проекте, написанном средними программистами на Java. Тут непонятно, как выйдет. Но те же супер-профессионалы, перейдя на Java, допустят меньше ошибок, чем сами же на C.

[зануда_mode on]
Напомню, что в любом реальном проекте на сотню тысяч строк уязвимости точно есть. Вопрос только в количестве и трудности поиска.
И да, сторонние библиотеки точно так же содержат уязвимости и, вообще говоря, их строки надо добавлять к строкам проекта. Они могут быть лучше написаны и протестированы, и ошибок в них может быть меньше, но в достаточно объемной библиотеке они точно есть.
[зануда_mode off]
А можно взять PHP который вроде тоже memory safe и поглядеть число дырявых движков на нем написанных.

Зато спасет от memory unsafe.

Да причём тут квалификация, Си нужно было развивать, как это сейчас пытаются развить плюсы(с переменным успехом).
Что за глупость заморозить язык на десятилетия, я этого совершенно не понимаю.
Столько очевидных источников ошибок.
Си и С++ стоило развивать в тандеме, чтобы не терялась обратная совместимость, но при этом было развитие и устранение врождённых недостатков.
Микробы будут всегда, пофиг мыть или не мыть руки.
А что Вы думаете по этому поводу?

Я тоже, как и этот Гейнор, борец за всё хорошее против всего плохого,
и точно знаю, что лучше быть богатым и здоровым, чем бедным и больным.
Экономика? Не, не слышал.


А какую воду вы предпочитаете пить? Дешёвую – из-под крана, или значительно более дорогую – бутилированную?
Не важно, что предпочитает один человек. Важно заставить всех перейти на хорошую воду. В том числе и при приготовлении продуктов, которые употребляет человек, выбравший себе бутилированную воду (а пирожки для него, например, готовят на воде из-под крана, а он даже и не подозревает).
Согласен. Но для начала нужно прийти к согласию, что есть вещи, которые более вредны, а есть те, которые менее. Как и с курением: вы не снизите уровень курильщиков в стране, пока в общественном сознании не закрепятся медицинские факты, что курение реально повышает шасны преждевременно умереть из-за рака.
И сразу ошибки, которые можно выявить на этапе тестирования.
1) Про вред курения. Если сравнивать курение человека, который живет на природе в чистой среде и питается исключительно чистыми продуктами (иных нет), живя далеко в Сибири, в Африке и т.д. с человеком, который ни разу не курил в жизни, но живет через дорогу от металлургического комбината, хим.завода или даже все вместе. Про всякие тепловые электростанции молчу. То я бы не сказал, что курение вредно, оно даже может быть полезно, вроде прививок, при количестве 1-2 сигареты в месяц или год. Особенно, если человек из природной среды поедет к человеку города или живущему рядом с промышленностью. так сказать — заблаговременная подготовка к нахождению в опасных условиях.
Был даже забавный случай, когда некоторых знакомых пытались убедить бросить курить, аргументируя вредом здоровью. Особенно смешно звучало для металлургов и сварщиков, особенно для сварщика, который варит без какой либо защиты для органов дыхания. Покупка защиты отложена до лучших времен, а сейчас банально з/п не хватит, ныне платят за такой труд всего лишь около 6 тыс руб (инфа 2-х летней давности по з/п, но я не слышал о кардинальных подъемах з/п).

2) про воду. Скоро бутилированный воздух будут продавать. А, нет, уже продают. Немного глупо, т.к. проще взять баллоны кислорода, азота и потихоньку выпускать в изолированном пространстве. Или с водой — дистиллированную + минеральные добавки (тот же магний). Или вообще провести чистый газ — и можно получать углекислый газ (который питание растением, а не для грантоедов глобального потепления) и воду. В природном газе различные добавки, а вот производить метан на электространциях — это одновременно будет и хорошим аккумулятором, т.к. инфраструктура уже есть, это не с водородом, для которого инфраструктура только строится. Мало того — углекислый газ не является ядовитым для человека, мы им вообще дышим, хотя и не чистым, а газом с содержанием углекислого газа — доли процента.

Отсюда — приходим к известному «все лекарство и все яд. Зависит от дозы». Слишком много с/с++ стало ядом, причем на подобии медленно действующего токсического яда. В небольших дозах незаметен, а позже ошибки накапливаются и могут вызвать смерть пациента (тут ссылку про разорение кого-либо из-за ошибки программиста)
1) Идея про «прививки для подготовки к городу» интересная. У вас есть данные, что она помогает, или это только идея?

2) С выпусканием воздуха скорее проблема в том, что в существующем в городе есть процент нежелательных примесей. Скажем, угарного газа в воздухе 40 мг/м3 (вдвое выше ПДК). Чтобы заменить половину воздуха в комнате 20м2, надо выпустить ~62 кг смеси азота с кислородом (на самом деле больше, т.к. выходить из комнаты будет смешанный воздух, где есть и чистый, и «грязный»).

В общем, не очень практичный метод — слишком много его надо привозить очищенного.
В далекие доинтернетные годы читал японское исследование, утверждавшее, что в группе курящих до 5 сигарет в день заболеваемость обычно связываемыми с курением болезнями ниже, чем в сопоставимой по демографическим показателям группе некурящих. Но уж очень давно это было, так что ссылку не найду и за что купил, за то и продаю.
Риск рака, как показывает практика, не работает.
Лучше продвигать очевидную истину, что курильщик при прочих равных глупее, безвольней, больнее, беднее.
Ух, сейчас курильщики набросятся на объективную реальность! Наркотик давит на мозг.
Важно заставить всех перейти на хорошую воду

Важно заставить

Зачем заставлять?

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

Есть санитарные нормы. Вряд ли можно ожидать что-то лучше них, если не брать випобслуживание. Надеяться на культуру можно, но не ясно, как это могло бы выглядеть. Промышленный фильтр в ресторане? Это возможно, но без требования санитарных норм всё равно каждый второй владелец будет игнорировать.
Расходы же.

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

Хотел сказать, что рассчитывать на что-то лучше, чем гарантируется санитарными нормами в большинстве случаев бесполезно.


Нормы ужесточать не предлагал. Вокруг и так слишком много "заставлятелей", я к ним не отношусь.

А вы уверены, что в бутылке качественная вода?
… и вода ли…
Вот например, спирт этиловый и спирт метиловый. На запах/вкус/цвет одинаковы, даже эффект по началу одинаковый…
Я правильно понял вашу аналогию, что может быть «С++, идентичный натуральному»?

Ну тут вопрос философский. Что такое натуральный ароматизатор и идентичный натуральному? И то и то химия. Где-то все лишнее убрали или где-то все нужное добавили.

Аналогия была к воде. С виду одно, а последствия могут быть всякие — не сразу и поймешь, что случилось.
К слову, на «С++, идентичный натуральному», действительно, тоже ложится. Всякие rust'ы и swift'ы, конечно, здорово, — а с производительностью там что? Не в масштабе поделки-микросервиса, а по-больше и по-ответственнее. Взять то же ядро линукса: сетевая подсистема, менеджер памяти — как они себя поведут?..
У нас другой случай был. Покупали качественную бутылированную воду, а в один прекрасный день увидели в бутылке мусор. Производителья сменили, но где гарантия?
Простые действия — звоните конкурентам этого производителя (только уточните, что это конкуренты, а не борьба нанайских мальчиков) и выгодно продаёте эту бутыль. А уж соперник, поверьте, отработает ситуацию по-максимуму.

Хм… Вариантов больше чем два. Вода из-под крана фильтрованная. Вода из-под крана кипяченная. :) бутилированая тоже может быть из крана с нашлепкой "из артезианского источника на глубине пяти километров".

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

Там где я живу, вода из под крана — качественная. Так что бутилированная мне дома не нужна.
А есть районы города, где вода из под крана — ржавая и им приходится пить бутилированную и на ней же готовить еду.
Проблема с качеством дорогой бутилированной воды всё равно останется. Если все перестанут потреблять дешёвую воду из под крана, то качество дорогой воды вероятнее всего снизится.
Экономика? Не, не слышал.
UFO just landed and posted this here
Ой, вечно Вы со своей JVM влезете куда не следует. Безопасность на уровне, описанном в статье, нужно реализовывать через Rust, а не через Java. Любая жабоось будет серверным решением худшим, чем серверные решения мелкомягких — адекватного тюнинга в жизнь не добиться.
Статья формулирует проблему, которую не решить — переписать код ядра *nix. По человеко-часам это займёт приблизительно… лет 30, при том, что текущее ядро параллельно с этим не перестанет развиваться.
И даже если кто-то всерьёз скажет, состроив злобную гримасу и стукнув кулаком по столу, «срочно совершаем [ре|э]волюцию!» — ничего не произойдет. Это как с IPv6 — «… а воз и ныне там...»
там скорее не в переписывании как таковом, а в наследии. Существуют системы, в которых уже залиты ядра линукса. И им обновления уже никогда не прилетят. Например, какой-нибудь медицинский прибор. Но вот поддерживать такой аппарат — вполне нужны те, кто будут ориентироваться в ядре линукса, чтобы избавить уж совсем критические ошибки, которые могут повлиять на пациентов. А утечка данных иной раз с таких аппаратов не опасна, т.к. физически невозможна — аппарат может банально не включен в интернет-сеть за ненадобностью.
Весь сыр-бор в первую очередь из-за утечек данных, а часть индустрии на это клала. Образование (те же школы), медицина (кроме данных пациентов), многие бюрократические организации (особенно на просторах СНГ). Еще есть те, у которых компьютеры к сети просто не подключены.
В медицинских приборах запросто может быть какой-нибудь Windows 2000 Embedded.
Кстати, мы решали проблему с УЗИ аппаратом. Врачи хотят в него втыкать флэшки, а куст реестра в 2000 имеет ограничение, по-моему, 64МБ, иначе система падает в BSOD. Решение: регулярно чистить раздел с подключенным когда-либо устройствам.
С точки зрения же безопасности… Ну, есть «золотой» образ системы, снятый механизмом типа ghost/acronis. Ну, и всегда такие штуки нужно защищать по периметру снаружи, т.к. в них самих почти наверняка настройка файрволла и т.п. запрещена.
Вот ведь дичь… Ответственные системы, конечно, должны загружаться исключительно с ROM носителя. Всё в ОЗУ. Если очень надо сохранять пользовательские конфиги/параметры от вкл к вкл, то другая память, отдельная от системной с контролем целостности.
Никто таким не заморачивается. Даже не под рутом и хотя бы 2 раздела на диске (С — системный и Д — пользовательский, с разными правами на доступ) — даже такое в условиях старой ОС, маленького HDD, проблем с администрированием (как аппаратные/программные, так и низкая квалификация администратора) — полностью уничтожает безопасность.
Самому было лень настраивать полноценно подобные компьютеры на волонтерских началах. Поэтому со временем туда и вирусы попадали, и всякие игры устанавливались третьими лицами.
По человеко-часам это займёт приблизительно… лет 30

То бишь, 30 разработчиков справятся за год? И не надо только про 9 женщин и ребенка за месяц, ок?)
Там зависимость нелинейная. То что один разработчики в идеальном случае сделает за 30 лет, то 30 разработчиков сделают года за два минимум, т.к. нужно учитывать накладки на синхронизацию и управление командой. Да и не все задачи параллелятся
Еще есть эффект «вторых глаз» и «второго мозга» — когда новый человек может что-то увидеть / посоветовать, до чего первый так никогда и не догадался бы.

Хотя, конечно, после подключения 3-го человека расходы на синхронизацию обычно превышают этот эффект.

Если этот год не будут спать, есть и как-либо отрываться от кода, при этом зная Pure C, Rust, архитектуру ОС и архитектуру ВМ и сетей и частное — отдельные конкретные реализации и воркараунды для железячных мест, где воркараунды нужны и почему на уровне способности "читать и писать без подсказок в 90% случаев и знать где быстро найти для остальных 10%" — то да, года будет достаточно. Утрированно, конечно, у каждого из этих тридцати своя нечеткая специализация, и 90% можно даже превратить в 70%, уух, задачу облегчили уже! Четкой специализации для команды в 30 человек не нужно, но понятие о всех остальных отраслях у них должно быть. Найдете 30 таковых по всему миру?

UFO just landed and posted this here

"Переписали" — всё же громко сказано, это был PoC операционной системы на Rust, сделанный с нуля и после этого уже несколько раз переписанный с пониманием "как делать не надо". Изначально Redox позиционировался как игрушечный проект и на вопрос "это замена Linux?" авторы давали определённый отрицательный ответ.

UFO just landed and posted this here

Добро пожаловать в Android. Одни проблемы решились, другие появились.

UFO just landed and posted this here
Сам посыл, звучит как: «У яйца могут быть серьёзные проблемы из-за курицы»…

Я думаю, нужно начинать переписывать *nix и другие критически важные для сети вещи на Rust.

UFO just landed and posted this here

Rust не может быть верифицирован на данный момент, потому что у него даже спецификации нет.


То, что верифицировано в этой статье, это некоторое пожножество системы типов Раста, как его понимают авторы статьи.


Если говорить о реальности, то известно, что Раст в текущей реализации небезопасен (содержит десятки "багов", самому старому из которых >5 лет).


Так что ситуация хоть и несравненно лучше, чем с C и C++, но далека от той идиллии что рассказывает Rust-пропаганда.

Прокомментирую расхождение в наших комментариях, чтобы не думали, что у нас разброд и шатание.


Конкретно в https://people.mpi-sws.org/~dreyer/papers/rustbelt/paper.pdf формально доказывается, что система типов Раста, владение, заимствование и прочее — корректны. Доказывается, что программа безопасна, если написана на безопасном подмножестве Раст. Доказывается, что программа безопасна, если в ней есть вкрапления unsafe, в которых программист не допустил ошибки, UB.


Кроме того, проект RustBelt на текущем этапе занимается формальной верификацией библиотеки std, но полная проверка требует времени. Поэтому библиотеку проверяют по кускам. Да, были найдены и исправлены 2 ошибки в unsafe коде (что показывает, что ребята делом занимались), тем не менее все эти thread, mutex, Arc/Rc формально безопасны.

Ну хорошо, язык и компилятор пускай корректны. Но ведь большинство проблем не в компиляторе, который многократно перепроверен и оттестирован. Большинство проблем в коде, который пишут прикладные программисты. На корректном языке можно написать некорректную программу. Чтобы решить проблему, поставленную в статье, нужно верифицировать не раст, а программы, на нём написанные.
Чтобы решить проблему, поставленную в статье, нужно верифицировать не раст, а программы, на нём написанные.

Давайте я подробнее распишу свою цитату:


Доказывается, что программа безопасна, если написана на безопасном подмножестве Раст. Доказывается, что программа безопасна, если в ней есть вкрапления unsafe, в которых программист не допустил ошибки, UB.

Эта означает, что формально доказано, что в программе, написанной на Rust без unsafe, отсутствуют проблемы с памятью, нет use after free, нет buffer overflow, то есть всех этих memory unsafety. И гонок данных тоже нет.


Проверка всех правил и контрактов в блоке unsafe { } ложится на плечи программиста. Потому что unsafe означает: заткнись, компилятор, я знаю, что я делаю, хватит меня поправлять. Никто не запретит вам вызвать два раза подряд libc::free на один и тот же указатель, вопрос в том, что ручное освобождение с помощью free возможно только внутри unsafe.


И тут мы приходим к статистике: в 99.9999999% случаев вам не понадобится ручное управление памятью в Rust (ну прям как в CppCoreGuidelines, используйте RAII). В 99.9999999% случаев вам не нужен unsafe. А если он и нужен, то он строго локализован (иначе на ревью надо отрывать руки). unsafe — это явное ключевое слово, его можно грепать по проекту, на него можно настраивать триггеры, любое появление unsafe в проекте — эпохальное событие, которое необходимо проверить. Ибо внутри unsafe можно выстрелить себе в ногу. И люди стреляют. Надеюсь, вы понимаете разницу между двумя проектами в 300 KLOC, но один написан на Rust с 1 строчкой unsafe, а второй написан на C++. Как говорится, happy debugging.


Большинство проблем в коде, который пишут прикладные программисты.

Ну это правда, и Rust не позиционирует себя как язык, защищающий от int getRand() { return 42; }. Он защищает от целого класса ошибок, связанных с памятью, что доказано формально, т.е. математически =)

Так вроде понятно. А как можно было трактовать ваше Доказывается, что программа безопасна, если написана на безопасном подмножестве Раст. Я решил, что это отсутствие ошибок.

От логических ошибок не защищает =)

UFO just landed and posted this here

Я надеюсь, вы понимаете разницу между формальной верификацией конечных программ, формальной верификацией компилятора и формальной верификацией системы типов языка?

UFO just landed and posted this here

Да, вы правы. Необходимо уточнение исходного вопроса.


aeeneas, не могли бы вы уточнить, что вы имели ввиду под:


Как там у Rust с формальной верификацией?
UFO just landed and posted this here
Programming Defeatism: No technique will remove all bugs, so let's go with what worked in the 70s.
UFO just landed and posted this here
Ну тут мужик в корне не прав. Это не С++ виноват. Это мышка не того цвета, клавиатура не так клацала, фазы луны не те…
Тут JS может из браузера вломится в соседнюю вируальную машину. Тоже С++ виноват?
Может архитектуру безопасности ОС пересмотреть, раз такие косяки ОС допускает сделать?

А на чем написан JS?))

Ахаха, даёшь безопасный браузер на джаваскрипт, с js движком на питон) Раст ещё сырой, чуть что быстрое надо — используй unsafe, за синтаксическим сахаром — в ночные сборки компилятора. Вобщем выбор без выбора.
Автор не понимает вещей о которых он рассуждает. Действительно зачем разбираться в теме, если можно сделать пару угодных публике заявлений, в духе: cтарые ЯП ужасны, ведут к ошибкам, поэтому вы их даже не учите. Расслабьтесь с нашим новым модным ЯП, где ошибок нет. Поэтому не напрягайте голову, а пополняйте ряды нашей секты. Все кто думают иначе еретики.
Давайте сразу так:
Кроме того, большинство микропроцессорных архитектур, даже самых важных для безопасности Интернета, не являются новыми. Они были запущены десят лет назад, если не больше. X86 например, более тридцати лет. И они не разделяют команды и данные «memory unsafely». Для масштабных проектов, подобных этим, замена всего оборудования потребует десятки лет…
X86 например, более тридцати лет. И они не разделяют команды и данные «memory unsafely»
Так-то запрет исполнения кода из сегмента данных (NX bit) возник лет 15 назад, а на архитектуре x64 он вообще обязателен.

Я понимаю, им надо пиарить rust, но все же современный C++ далеко не так плох, как его описывает автор. Другое дело, что адаптация новых стандартов идет медленно. Но все равно, куда проще плавно перевести код с C++98 на C++17, чем на rust.


Ну а C — там да, нужно только по спец разрешению пускать людей писать на нем код, только с десятикратным code review. Тк за кажущейся примитивностью и понятностью языка, скрывается возможность понаделать таких ляпов…

«Адаптация» — простите, наверное, «внедрение»?
Ну, просто английское «adoption» — действительно плохой друг переводчика.

Насчёт «проще перевести на С++17»… Спорно. Зависит от объема проекта.
Шаблонно (т.е. автоматизированно) это все равно не сделаешь. А выгоды какие? Только переиспользование существующего кода?

Русский у меня, хоть и родной язык, на данный момент — далеко не самый используемый мной, так что бывают такие вот "англицизмы" в моей речи.


Про C++17 — как минимум 3 из 4 названных основных проблем, указанных в статье, за исключением целочисленного переполнения, в современных плюсах проблемами не являются.


Сам по себе, конечно, переход от C++98 ко всяким там умным указателям, лямбдам, итп — задача не из тривиальных. Уж тем более с учетом того, что нельзя перевести только часть проекта на те же умные указатели, да конкретного типа объектов. Либо все, либо ничего. Плюс придется еще поотдавливать всякие возможные циклические зависимости. Но по своему опыту скажу, стабильность кода, даже от простого перехода на умные указатели, поднимается в разы. Ну а более современные фишки, вроде той же move semantic, позволяют проводить оптимизации, которые раньше можно было сделать только хардкорно, вручную.

в современных плюсах проблемами не являются

Ну не прям так категорично. Уверен, что в условиях многопоточности, все эти проблемы все равно всплывут даже если прям вообще все на stl и умных указателях. Решаются такие вещи только кардинально — либо как раст, либо сборщиком мусора и кучей компиляторных вставок с проверками, где вообще любое действие с памятью обернуто в безопасную конструкцию. Даже целочисленное переполнение будет уже не страшно, т.к. сработает проверка выхода на за границы.
Да можно и по частям на умные указатели проект переводить. От умных указателей выиграть может даже отдельный метод.
так что бывают такие вот "англицизмы" в моей речи.

В английском слова adapt и adopt тоже имеют совершенно разный смысл, и путать их не стоит.

i.kym-cdn.com/photos/images/newsfeed/000/111/795/Image1.png

адаптация новых стандартов идет медленно.

Адаптация, простите, к чему?!
Я понимаю, им надо пиарить rust, но все же современный C++ далеко не так плох, как его описывает автор.

Именно настолько плох. Чего стоит только нескончаемый перечен CVE, в котором встречаются слова «buffer overflow», «double free», «use after free»,…

Другое дело, что адаптация новых стандартов идет медленно. Но все равно, куда проще плавно перевести код с C++98 на C++17, чем на rust.

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

Могу сказать, что разница в 50 раз на производительности, в зависимости от того как вы напишете код того стоит. Напишете 100% безопасно с «автоматикой» — будет x1, напишете грамотно с «ручным управлением» — будет x50 скорость.
Да во втором случае придется немножко почитать логи на предмет утечек памяти в отладке и протестить корректно. Да, для этого нужна квалификация.
Но С++ то тут причем ?!
Нефиг браться мокрыми руками за оголенные провода под напряжением. Они от этого ржавеют…
Напишете 100% безопасно с «автоматикой» — будет x1, напишете грамотно с «ручным управлением» — будет x50 скорость.

Есть ссылка откуда такие числа, особенно в контексте Rust'а?

Могу сказать, что разница в 50 раз на производительности, в зависимости от того как вы напишете код того стоит.

В 50 раз? Если не брать в расчет встраиваемые системы, то какая реальная программа для центрального процессора работает в 50 раз быстрее, чем программа на .Net/Java?


Не синтетическая, а именно реальная.

Даже синтетика настолько не отличается
Даже синтетика настолько не отличается

2005/6 год. Notebook CPU Core2Duo и Ram 4 GB DDR2.
Алгоритм кеширования (нюансы не помню) и цель была выжать максимальную производительность.
С++: Замена double на double* и _smart_ptr на IFn* в сигнатурах функцияй ну и управление памятью (изменено были на ручное new/delete) при сохранении алгоритма.
Сам удивился результату. Сейчас, думаю, результат будет поскромнее. Надо будет проверить на досуге.
Простите что вклиниваюсь, но не могу удержаться, и мой ответ — сравнение C# со сборкой мусора и кучей аллокаций vs С# реализация той же системы с оптимизацией памяти на выделенные буферы и их переиспользование и ручное освобождение с пул аллокаторами и явными зонами ответственности… так вот как минимум на сборку мусора по скорости дало раза в 5-10 ускорения (зависит от условий теста) — на том же самом языке, кроме прочего потребление памяти снизилось, и это было и на ПК и в WebGL — основа на unity. Я могу предположить что при нормальной оптимизации скорость по C++ должна быть еще чуток выше. До 50 раз — может быть а может и нет.
Вопрос то сложный. Насколько много мусорит приложение. Ведь если чисто вычисления, то оптимизируй сколько влезет, но не в сборщике дело. Unity, игровая логика — тут как раз на сборщик весь упор может быть, если каждый кадр тонны объектов пересоздавать. Собственно, даже без сборщика кучу трюков в плюсах используют по памяти.
Уточняю — в нашем проекте не игрорвая логика каждый кадр, а один очень толстый pipeline по генерации кое-чего в рунтайме, и испольщзующий кучу алгоритмов и данных, как исходных так и промежуточных, в таком случае — применять собственные менеджеры памяти — очень помогает как ускорить так и снизить потребление памяти. Но задача не из частых.
Просто как пример привел.

В том же С++ или любом другом языке может быть задача с кучей обрабатываемых данных, причем разных структур и промежуточных, с долгой обработкой, а не раз 1 алгоритм запилил и оптимизий. Очень часто данные надо гонять, и объекты в доменной области есть.

Что до юнити — да можно переиспользовать игровые объекты классически — чтоб не создавать каждый раз новый, но речь не только об этом.

Вот например есть либа для триангуляции, вот она при написании на Си имела производительность Х, потом при переписывании на С++ стала Y, потом на C# стала в разы быстрей чем была на Си, изза аллокаций памяти неоптимальныъх в Си, а в C# сборщик памяти ускорил дело, представляете (можно было бы использовать как контр-пример что мол круто сборка мусора ускоряет). Но потом ее еще оптимизировали на пулы и она стала быстрей чем была, на всех платформах, т.е. на C# с ручным менеджментом памяти стала быстрей чем на C# со сборкой мусора, и быстрей чем на Си с ручным менеджментом.
Либа эта LibTessDotNet на C# и при желании нагуглите ее версии На Си и С++ и т.п.
А в моем проекте кроме ее я юзаю еще кучу разного.
автор исследовал кодобазы возрастом 10+ лет. Rust вышел в 15-м году, после c++14. Может хватит уже сравнивать Rust 2015 с с++03?

Если хотя бы новый функционал не писать на С и С++

перепишите мне все используемые мной API с с++ на Rust и я подумаю. Только в моей конторе это тысячи человеколет кода
А зачем все API переписывать с C++ на Rust?
Если у системы достаточная степень decoupling'а, все в разделяемых библиотеках, или что лучше — коммуникация между модулями по протоколу типа REST, то все же прекрасно переписывается?
а если нет? У нас например монорепа, статическая линковка и куча API на шаблонах.
Ну, я думаю, что основная проблема все-таки не в «монорепа» и «куча API на шаблонах» (это вообще можно трактовать совершенно по-разному), а в «статическая линковка»
UFO just landed and posted this here
UFO just landed and posted this here
То, что вы привели, как Eigen — реализация поиска собственных чисел из GSL.

Имелась в виду вот эта библиотека: eigen.tuxfamily.org/index.php?title=Main_Page, которая, как назло, линкуется статически с C++ кодом, ибо header-only на шаблонах :P

Вообще, прям очень любопытно было заодно увидеть биндинги для OpenCV и PCL для Rust'а, вот только это как-то очень долго делать, имхо.

P.S. по вашим ссылкам в части GSL все вызовы плюсовых функций помечены как unsafe. В чем в таком случае будет преимущество использования Rust, если у меня какой-нибудь суровый математический модуль с gpu-оптимизациями? Проще уж тогда к этому моему C++ модулю писать Rust биндинг. Но вызовы модуля мне придется точно так же помечать как unsafe…

P.P.S. Как, кстати, у Rust'а с Cuda/OpenCL?
автор исследовал кодобазы возрастом 10+ лет. Rust вышел в 15-м году, после c++14. Может хватит уже сравнивать Rust 2015 с с++03?

Ну, автор не совсем прав в таком сравнении, но новые версии не сильно улучшают ситуацию. На хабре же была статья про std::visit, там подробно рассказывается про то, почему он не является полноценной заменой нормальному матчингу.

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

перепишите мне все используемые мной API с с++ на Rust и я подумаю. Только в моей конторе это тысячи человеколет кода

Так я не говорю переписывать всё с плюсов. Переписывания кода на новый язык «просто потому что» это бездумно и не нужно. Вопрос в том, какие плюсы дает версия на новом языке, и насколько легче написать всё на нем с нуля, чем дописывать существующую версию. Иногда профит есть, и смысл имеется. Иногда — нет. Вопрос в том, чтобы не ударяться в обе крайности.

Ну и да, я обычно пишу на C#, у нас обычно проект — это десятки-сотни отдельных модулей, линкуемых динамически, которые могут быть даже на разных языках, и которые спокойно можно менять/заменять по одному. Ситуация статически линкуемых шаблонов мне действительно чужда, и тут нужно сильно увеличивать стоимость внедрения. И если она превышает некоторый порог — говорить «нет, у нас плюсы. Да, это плохо, но профит от переписывания на раст никогда не окупит затрачиваемые усилия».
и все равно там будут ошибки этого класса

а можете привести пример ошибки памяти в хромиуме, в модуле, написанном на «распоследних» плюсах?

А статическая линковка решает очень много проблем с зависимостями и версионированием библиотек, а также с воспроизводимостью конфигурации. В расте, емнип, именно статическая сборка является вариантом по умолчанию
Проблема подобных ошибок — непонимание логики работы, особенно в нетипичных ситуациях. Работа в нетипичных ситуациях вообще приводила к падениям ракет, когда новая ракета падала из-за старого кода. «Ariane 5». Хотя ошибки аэропорта Хитроу куда жестче.

Системы нынче стали настолько сложные, что даже болванка (заготовка) игры на новомодном движке может весить 200 МБ! Проблема в том, что человечество до этого момента не сталкивалось ни с чем подобным. До этого приходилось управлять максимум небольшими командами либо огромными однотипными системами. Или вообще пускать все на самотек и придерживаться традиций. А цена ошибки не была большой, т.к. часть людей вполне официально можно было считать даже рабами, как в той же Америке до 1865г.
Проходит 150 лет (+3) и системы усложнились на порядки. Ладно бы просто найти решение, но что делать с Legacy/наследием? Раньше решалось проще — повоевали и все, строй заново, без Legacy.

На этом моменте в книгах про известную личность пишут — и тут эта личность создала комитет/общественную организацию/свою книгу/другие варианты. С помощью чего и занимался подобными проблемами.

Может, стоит подумать в направлении такого созидательства? Посмотреть, что уже существует и делать свое, развивать. Типа «общество сложных систем», который позже станет институтом/университетом. На самом деле не взлетит, т.к. нужны будут финансы. Требовать финансирования глупо — можно перейти в режим грантоедов. Поэтому нужно подумать и в сторону о пользе, которую можно получить уже сейчас, пускай и другим путем.
UFO just landed and posted this here

… и это хорошо. У этой библиотеки открытый исходный код, как и у любой библиотеки на Go. Это классно! Вливайтесь! Размер 1мб тем не менее позволяет запуститься в Docker-образе scratch, т.е. с нуля, без всего. А минимальный java-образ весит сотню мегабайт несколько я знаю.

Этот неловкий момент, когда Lazarus (открытый аналог Delphi) дает exe-файл в десятки мегабайт (10-20МБ). Но там тащутся оконные библиотеки для получение Windows (или Linux) окошечка.
А вот консольная программа того же, да и еще с выключенным дампом откладки дает уже в районе сотни килобайт, причем часть можно сэкономить, если не использовать некоторые системные библиотеки, типа SysUtils.

Почему не пропагандируется Lazarus? Открытый развивающийся язык, куча библиотек. Можно писать даже драйвера. Можно даже GNU Pascal вспомнить.

Хотя уже существует KolibriOS, которая написана на ассемблере. Там нет упора на безопасность, но разработка на ассемблере намекает, что на ассемблере писать можно даже ОС, только не все осилят.
У меня Lazarus даёт 2 мегабайта для гуя. ЧЯДНТ? Включаю релиз сборку вместо дебаг?
2мб это тоже очень много. как насчет сравнить с 10-50Кб для родных С-приложений
родные С-приложения с окошками? Наверняка про чисто консольные, без всяких Qt и Gtk, которые явно не 10кб займут.
Если без GUI в консоли, то получаем 32КБ. Сравниваем с С-приложениями и как-то порядок особо не различается.

DevCpp х64 для простенького консольного HelloWorld на C++ c iostream дает приложение 1,83Мб
Lazarus 1.8.0 x64 для консольного приложения с расширенными возможностями (включен объект App) дает приложение 278 Кб
FPC 3.1.1 x64: для HelloWorld с библиотеками Classes и SysUtils дает 162 Кб,
без библиотек дает 32 Кб (первая библиотека дает несколько встроенных классов, вторую либу использовал только ради функции перевода из Str в Int и обратно вместо процедуры для того же самого результата).
родные С-приложения с окошками?

Например на WinAPI.


DevCpp х64 для простенького консольного HelloWorld на C++ c iostream дает приложение 1,83Мб

Там же gcc, который тянет свой рантайм.

Например на WinAPI.

и потеря кроссплатформенности.
Опять же — реализовывать можно по-разному. Для Lazarus:
1) не парясь что под капотом. LCL, создавая кнопочки как в Delphi. WinApi, Qt или GTK выбирается переключателем в настройках проекта. Но итоговое приложение будет в районе 2МБ.
2) делая с готовыми обертками на WinAPI, но прирост все равно будет — в районе 300-600КБ, т.к. линкуются библиотеки
3) найдя усеченные библиотеки отрисовки (уже не помню как называется), направлены на минимизацию итогового размера приложения. Итоговое приложение 150-400 Кб
4) Писать все ручками, в том числе обертки для DLL. Можно уложиться до 150 КБ
У меня все цифры примерные и иногда указаны в большую сторону. Например, думал что минимальное консольное приложение 52Кб, а оказалось — всего 32Кб, т.е. я в 1,5 раза завысил.

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

Доходя до размеров, сопоставимых с размерами дискет в 1,44Мб, я перестаю задумываться о дальнейшем уменьшении размеров минимально компилируемой программы. К сожалению, у многих современных разработчиков эта планка превышает 100Мб и вовсю стремится к гигабайтным высотам.
Я не улавливаю твою мысль. В целом, Лазарус не такое уж и масштабное зло, а если сравнивать с текущими тенденциями — то даже весьма на передовой.

Но до идеала ему как до Луны (особенно в качестве, ну и размере генерируемого кода). Потому твое бахвальство неуместно.
Согласен что много, в дельфях это было меньше, и я знаю что и там много мусора лишнего.
При сравнимом удобстве написания гуя Qt и Wx дают по ~50/~25 мегабайт (емнип), они включают фреймворк. На Qt ещё и станцевать надо для получения дистрибутива (в бесплатной версии).

На чистом WinAPI не пишу, зачем это в 2к18? Если со скуки, то можно и на FPC написать с вызовами WinAPI, а лучше — на ассемблере.

Или вы знаете некий секретный вариант с Си?
Какие там секреты. Чтобы программа быстро запускалась и была компактной, достаточно брать встроенный в систему фреймворк, например MFC или .NET.
Дебаг сборка = включение дампа (для) отладки.
В дебаг сборке еще можно поставить флажок «файл отладки отдельно» и тогда отладочный файл генерируется, но не включается в готовый exe-файл.
Все равно размер будет гулять ± несколько процентов из-за версии Lazarus и ОС, но это уже не так заметно.

Fortran тоже в некоторых применениях просто идеален, оптимизированный и быстрый, но время языка прошло, ровно как и время pascal. Этим языкам даже поддержка корпорации не поможет. Я дорабатывал проект на Delphi, и объективно и непредвзято могу сказать, что он устарел. Я пару раз уже писал об этом на Хабре. А если субъективно, то меня ничто не заставит на нем больше работать, даже, скажем, оффер х2 от текущей денежной компенсации.

Я пишу для души на Pascal, типа хобби и ностальгии. Или надо что-то быстро простенькое и одноразовое создать — тут Lazarus/FreePascal у меня делит место с Python. Или для различных извращений, вместо Brainfuck.
Вообще нужно выбирать инструмент исходя из задач. У меня:
— 1С для бухгалтерии
— Python для веб-сервера (ранее использовал PHP)
— C# (Unity) для разработок игр/приложений на телефон
— Lua для скриптов (тут еще Python и Bash, скриптов много)
— Visual Basic for Application для Microsoft Word/Excel/Access
— SQL для баз данных
— JS для клиентских браузерных скриптов
и прочее.
И тут я солидарен с автором статьи, что от С/С++ стоит отказываться во многих направлениях.
А если субъективно, то меня ничто не заставит на С/С++ больше работать, ибо полиформизм инструкций в зависимости от контекста как у тех же звездочек — очень сильно бесит, а про код в стиле регулярок я даже не расписываю. Про указатели упомянуто у автора статьи. И я не собираюсь пихать С/С++ в бухгалтерию, веб-разработку, скрипты, базы данных и т.д.

про время принятия решения
Надо учитывать время принятия решения о разработке. Если это были в первом десятке лет этого века (нулевые, до 2010), то ни о каком Rust и Swift даже близко не могло быть и речи, на тот момент эти два языка (а также некоторые другие) были в крайне ужасном состоянии. И человек, который собирался тогда писать на этих языках серьезные приложения с необходимостью получить минимальным результатом через пару лет, но не участвовал в разработке этих языков — явно псих, которого нельзя допускать к программированию. Основание? Первое десятилетие закончилось в 2010 году, а первые стабильные версии этих языков выйдут только через 4-5 лет. Соответственно, разработка того приложения могло зависнуть на 4-15 лет! Либо разработчик хитросделанный и хотел эти 4-15 лет получать з/п просто за ожидание, пока выйдет «достойный язык».
Я уже не буду рассказывать про рекомендации в сторону NASA выбрать Rust/Swift для разработки, если решение принималось в 90-е! Там вообще клиника.
Ну не знаю, я люблю на C++ писать именно для души. Можно рисовать такие штуки, за которые rust даст по рукам.

Например, я хочу организовать иерархические слои данных. Выделяю мегабайт памяти и располагаю там свои любые данные. Выделяю следующий мегабайт и располагаю там новый слой данных, со ссылками на предыдущий слой. И так далее. Следующие слои ссылаются на предыдущие, но не наоборот. Можно удалить N последних слоёв и вся структура останется ссылочно корректной. На расте так не сделаешь.
Для души можно писать на любом языке и под любую архитектуру, даже несуществующую. Сложнее, когда нужно в продакшен, тут уже выбор иногда между:
1_) текущим знанием
2_) легкостью обучения для опытных и для новичков, кривые обучения
3_) з/п специалистов и предложения на биржах труда — влияет на стоимость поддержки
4_) уровень и планируемая длительность поддержки
5) доступность исходного кода
6) лицензии
7) возможности языка
8_) доступные компоненты/библиотеки
9) поддерживаемые целевые ОС и архитектуры
10_) количество изменений в новых версиях языка и влияние на предыдущие
11_) предсказуемость языка, т.е. предсказуемость поведение готовой программы
12) защита от ошибок на уровне языка
13) возможности языка по отстрелу ног и уничтожению всей вселенной
14_) развитость IDE
15_) доступность отладчиков (стандартных для языка, а не сторонних)
16) читабельность
17_) легкость установки от «запустил exe, установил и можно кодить» до «скачай, скомпилируй, исправь ошибки компиляции, скомпилируй более новую версию, настрой конфигурацию, докупи оборудование...»
и т.д.
Например, си допускает в конструкции if присвоение вместо сравнения, а это — частая ошибка, которая отслеживается только некоторыми IDE, в блокнотах можно и пропустить. Про «докупить оборудование» намекнула Unity, которая для создания приложения для Android требует самую новую видеокарту (DirectX 9 уже не устраивает) и х64 систему.

И все языки хоть где-то, но накосячат, т.е. не являются идеальными, поэтому п.1-4, 8, 10, 11, 14, 15, 17 вполне могут быть провалены, особенно новичками п.2,8,14,17
UFO just landed and posted this here
А зачем, если это замедлит компиляцию, а значит и цикл разработки (написал код — запустил — проверил — внёс изменения). Кроме того, большой исполняемый файл не является проблемой для современных ОС, т.к. в память загружаются только страницы, по которым действительно прошло исполнение кода.
Большой файл-долгая линковка, тоже удлиняет цикл разработки.

Кроме того, пример Дельфи, Явы, да и впрочем любого приложения со сплеш-скрином «гружусь» показывает, что проблема загрузки никуда не делась.

Много сейчас программ с мгновенным временем запуска <200мс?
Ява так долго грузиться может именно из-за динамической линковки всего и вся. Пока в память загрузятся десятки и сотник jar файлов, пройдет целая вечность. А после этого их еще надо через JIT пропустить. Один большой нативный бинарник же ерунда — маппинг в память и готово.
Большой файл-долгая линковка, тоже удлиняет цикл разработки.
Нет, потому что для си-шной линковки нужно прочитать большой блоб .lib-файл, нарезать его на кусочки, сшить эти кусочки заново в маленький файл, поправив ссылки (не говоря об обязательной для такого действия оптимизации «link-time code generation», когда после сшивания в другом порядке неплохо бы заново код перегенерить). А для го-шной линковки один большой блоб, уже хорошо оптимизированный, сшить с кодом программы и поправить ссылки только в программе на блоб.
Тогда почему линкуется неиспольщуемый код?
Не использует, у него свой компилятор и линкер. Тулчейн нужен только для cgo, что совершенно отдельная хрень сбоку.
у программ длительный запуск может быть вызван следующими причинами:
1) нужно кучу страниц загрузить в оперативу. Т.е. пока не загрузятся картиночки для отрисовки кастомной кнопочки — приложение будет грузиться.
2) инициализация переменных. Причем всех и сразу, даже в принципе неиспользуемых
3) различные проверки. Вышла новая версия? У пользователя активирована лицензия?
4) Дергать реестр. Либо INI-файлы. Хорошо, если там десяток параметров
5) п.4 расширенный — подгрузить последнюю пользовательскую сессию
6) проверить совместимость системы (встречались и такие программы)

Это некоторые причины. Но программисты не стоят на месте, поэтому ожидайте (а где-то уже появилось):
— телеметрия
— интеграция с другими приложения, которые надо тоже тут же запустить
— 100500 сервисов/микросервисов (у видеокарты NVidia драйвер притащил около десятка программ, в том числе «стримминг», «3д навороты, недоступные на обычном мониторе, но всегда автивные» и прочее.)
— синхронизация с облаком. Если инет затупит, то и приложения тоже замедлится
— высококачественные текстуры 4к для отрисовки курсора мышки
и т.д.
а не надо додумывать и теоретизировать

— в одной из моих хабрастатей есть утилитка замера, чего и сколько как быстро грузится. с исходниками.
Супер-инженеры гугла наелись плюсами в своих проектах и захотели, чтобы новый язык был лишен всех проблем статической и динамической линковки, коих великое множество. Расплата за это небольшая — небольшое увеличение бинарника.
судя по их же статьям, «небольшое» это до 100Мб

там же и время сборки можно посмотреть.
вроде на хабре было
Время сборки занимает считанные секунды.
UFO just landed and posted this here
А часто ли вы запускаете «Hello, world» на проде? Для более крупных программ относительное увеличение размеров будет куда меньше.
UFO just landed and posted this here
Не имеет никакого значения, сколько весит бинарник, если он будет работать на серваке с терабайтом оперативы и обслуживать миллионы запросов. Go делался под совсем другие задачи и большой бинарник это ничтожная плата за то удобство, что дает отсутствие зависимостей. Go идеально влился в мир контейнеров, т.к. может запускаться даже в scratch, а иная поделка на плюсах или си потребует тащить за собой половину линукса.
UFO just landed and posted this here
Мне трудно представить, какие преимущества
А какие недостатки? Но не абстрактные «большой файл получается», а реальные, из-за которых бизнес несёт убытки.
в то время как проверенные альтернативы, такие как Rust, Swift,

Это шутка такая?

2 июня 2014 года на конференции WWDC Swift был официально представлен (википедия)

После нескольких лет активной разработки первая стабильная версия (1.0) вышла 15 мая 2015 года (википедия)

Проверенные альтернативы — это «мы целый месяц тестили, все ок». А также намек на то, что до 2014 года у пользователей не должно быть этих самых браузеров, потому как «проверенный временем» язык программирования еще даже не родился

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

UFO just landed and posted this here
переходим на китайский, там соцкап уже готов
Судя по иронии, вы не согласны с поднятым вопросом?
«Проверенные альтернативы вроде Rust» — ну это вообще смех. При всем уважении к хайпу вокруг Rust'а, у него еще молоко на губах не обсохло, а на C++ люди писали задолго до рождения Алекса Гейнора. И если уж вообще по-честному, большая часть «memory safety» Rust'a спокойно реализуется в C++, а к моменту его рождения уже подъезжала в стандарт.
Любую фичу любого языка можно добавить в любой другой язык, было бы желание. Только вот их нет и не видно. Исправить С++ уже невозможно. Во-первых, никто в него не добавит ничего подобного расту, потому что обратная совместимость. Во-вторых, никуда не исчезнут все небезопасные конструкции из языка, потому что, опять же, обратная совместимость.

А Rust действительно проверен. Он безопасен по-определению, т.к. все перечисленные проблемы в нем конкретно решены в самом языке. Не имеет никакого значения, сколько он пробыл на рынке.
А Rust действительно проверен. Он безопасен по-определению, т.к. все перечисленные проблемы в нем конкретно решены в самом языке.

Он (сам по себе) не решает более серьезные проблемы — валидации [внешних] данных, не говоря уже про логические ошибки.

К примеру, если (предположим) писать веб-сайты на Rust, он никак не спасёт ни от SQL injection, ни от кучи других проблем имеющих отношение к Web Application Security, равно как и вообще любых проблем которые выходят за рамки безопасных указателей и безопасной работы с памятью.

Ради интереса, пройдитесь по CVE и посчитайте долю уязвимостей связанных с неправильной работы с памятью, и долю всех остальных — результат явно укажет что «безопасный» язык проблему не решит.

не решает более серьезные проблемы — валидации [внешних] данных
Но ведь он навязывает создание типов и трейтов на каждую мелочь. Чужие трейты нельзя реализовать для чужих типов, таким образом, если хотите пользоваться чужим кодом (я имею ввиду, не данные, а зависимости), необходимо создавать свои типы, а это уже намекает на валидацию, хотя и не обязывает, это да.
посчитайте долю уязвимостей связанных с неправильной работы с памятью, и долю всех остальных
А вот Гейнор насчитал более половины.
Да сколько можно. Автор говорит о конкретных уязвимостях связанных с памятью. При чем здесь SQL инъекции? Да, давайте все бросим, плюнем на все предосторожности, ведь если мы не можем предотвратить вообще все уязвимости, то надо не пытаться это сделать даже для некоторых особо опасных и страшных. Или все, или ничего. Это глупый подход, надеюсь это не надо объяснять. Автор агитирует к отказу от этих языков, чтобы исключить отдельный класс очень опасных уязвимостей. Да, есть другие проблемы, только вот данные конкретные вызваны именно языками, их очень сложно найти, очень легко допустить, и это надо как-то решать. SQL инъекции более очевидны, но тоже решаются, только другими методами — более качественными библиотеками. И аргумент будет тот же самый — долой устаревшие способы работы с SQL, биндинг параметров в массы. Вот такой подход и нужен — каждой проблеме свое решение. Небезопасная работа с памятью должна уйти в прошлое и остаться там, где это действительно нужно. Там, где используется С++, это не нужно от слова совсем. Даже ядро ОС и то спокойно пишется на полностью безопасном языке, т.к. мизерное количество кода напрямую работает с памятью. Если уж на Go смогли, то и на Rust тем более смогут, заодно еще не в ущерб скорости.
Даже ядро ОС и то спокойно пишется на полностью безопасном языке, т.к. мизерное количество кода напрямую работает с памятью.

Рискну предположить, что в этом случае ядро будет очень сильно тормозить. Как пример — безопасный язык просто обязан проверять соответствие индекса размерам массива, это несколько лишних операций, больно бьет по кэшу и т.п. — а в ядре ОС таких операций немало, причём в довольно критичных местах.

Ни одна проверка не обходится даром, за это приходится платить либо производительностью, либо памятью, либо и тем и другим — для ядра это очень расточительно.

А для остальных приложенией — да посмотрите на мир Java, типа супер-безопасный язык (с точки зрения указателей как минимум), и сколько уязвимостей уже было в продуктах на нём писанных.

Не поймите неправильно, я не утверждаю что не нужны безопасные языки, или что не нужно жертвовать производительностью ради безопасности — просто проблему нужно решать с другой стороны.

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

Пока все лицензии на софт (включая коммерческий, и даже критичный, типа ОС) содержат явный отказ от ответственности, или, в лучше случае, «мы вернем вам деньги за покупку», у производителей почти нет никакого стимула делать его свободным от уязвимостей или ошибок.

С другой стороны, возьмём софт который работает в борткомпах каждого современного автомобиля, самолёта etc — часто там обнаруживают уязвимости? А удаленные? Да хотя бы просто баги, такие, которые не позволяют нормально пользоваться техникой — часто? А ведь он чуть меньше чем полностью писан на C, а то и ассемблере. Автомобили сами не тормозят и не ускоряются (только давайте не будем про Tesla & co), не мигают фарами, самолёты не меняют высоту, и т.п. Отдельные фейлы случаются, но это исключительно редкий случай. Дело же просто в том, что как раз баги и уязвимости в таком софте приводят к реальной ответственности — поэтому их там почти нет, по крайней мере не такие какие были бы заметны обычным пользователям.

Так что, повторюсь — язык это дело десятое.
UFO just landed and posted this here
Если законодательно ввести штраф за каждую обнаруженную уязвимость, т.е. ответственность разработчика за качество кода, вот тогда проблемы начнут решаться

… тогда проблемы начнут решаться при помощи счёт и абаков. Потому что софт будет стоить не просто не дорого, а очень дорого. И идти только в виде узкоспециализированной железки. Вот вам отдельный опечатанный ноутбук с вордом, вот вам отдельный опечатанный ноутбук с экселем, ну и да — вот вам dvd плеер для дисков с порнухой.
Лучше опечатанный ноутбук с вордом, но при этом уверенность в том что никакой левый файл, открытый в этом ворде, не сможет натворить дел, а также уверенность в том что он не угробит работу нескольких дней при попытке сохранения (такое тоже бывало, очень много лет назад).

Да, написание качественного софта стоит денег и времени, но вы посчитайте все убытки связанные с уязвимостями и критичными багами — во многих случаях они явно превышают затраты на разработчиков, которые потребовались бы для написания софта без таких багов, которые приводят к этим самым убыткам.
Лучше опечатанный ноутбук с вордом, но при этом уверенность в том что никакой левый файл, открытый в этом ворде, не сможет натворить дел
В чём проблема? Заказывайте себе такой ноутбук с вордом за пару миллиардов долларов, заключайте договор со всеми штрафами и санкциями за ошибки. Но зачем остальным это навязывать?
Ответ на вопрос «зачем» очень прост — если кто-то берет деньги за свой продукт, он обязан нести за это ответственность, или, как минимум, заранее огласить весь список возможных проблем.

Вы не купите автомобиль если не будете уверены что его тормозная система тщательно проверяется и работоспособна, а если вдруг в конкретном случае она будет глючить, то производитель будет нести полную ответственность — так почему с программными продуктами должно быть иначе?
так почему с программными продуктами должно быть иначе?
Потому что нет платёжеспособного спроса. На надёжные автомобили есть спрос, на надёжные офисные программы — нет.
UFO just landed and posted this here
В этом-то и проблема. В случае осязаемых продуктов (техника, лекарства etc) есть и другие обязанности, которые невозможно исключить никаким договором (гарантия, например, или ответственность за причинение вреда).
UFO just landed and posted this here
На госуровне это решается по другому — введением обязательного лицензирования и сертификации. Как в той же промышленности и строительстве.

Например, тогда тебя не возьмут на работу или вообще не допустят к клавиатуре, если ты не сдал экзамен и не имеешь сертификата «Уверенный пользователь Word со знанием VBA»…

Это еще не говоря даже про программирование, где программу придется сдавать госкомиссии. За свой счет.

Точно этого хочешь?
В строительстве у нас уже не обязательно, это ведь не такое серьёзное дело как предоставление телематических услуг, например.
> Если законодательно ввести штраф за каждую обнаруженную уязвимость
то все коммиты в компании начнет совершать «программист» нанятый из дворников, а все люди пишущие код вдруг станут консультантами.
Неважно кто будет совершать коммиты — штраф получит компания, и пусть сама разбирается со своими сотрудниками. Несколько крупных штрафов — и политика найма дворников сойдёт на нет. Или хитрая компания сойдёт на нет.

Просто вы не сможете пользоваться софтом, как сейчас, а бизнес так или иначе найдёт выход.
Например, чтобы попользоваться программой, вы будете подписывать договор платного бета-тестирования (ага, сами будете доплачивать за возможность тестирования неготового софта). Обязанность тестировщика — сообщать обо всех найденных ошибках производителю. Не хотите — не участвуйте, но выбора у вас большого не будет.
Мне кажется очевидным что такие договора подпишут единицы, так что компании придётся искать другие источники дохода, соответственно, выбора не будет у них.

Хотя проще, вероятно, будет сделать иначе — не берёшь денег — не несёшь ответственности, берёшь — несёшь в полной мере и никак не можешь её исключить в лицензии.

При таком раскладе, компании которые изначально озаботятся качеством, окажутся однозначно в выигрыше — да, их продукция будет стоить дороже, но зато у них будет гарантированный доход. Остальные могут давать свои продукты тестировать бесплатно, пока не вылижут до возможности брать деньги.

Любой пользователь коммерческих программных продуктов должен иметь обеспеченную законом гарантию, причём на уровне покрытия доказуемых понесенных убытков, а не просто «вернём деньги» или «заменим бесплатно» — тогда дело сдвинется с мёртвой точки.

Софт, даже большой и сложный, и даже на C или ассемблере, можно писать без багов, просто весьма ограниченное число компаний (и людей) на это способно и имеет желание, и ещё меньше имеет достаточно денег.
Любой пользователь коммерческих программных продуктов должен иметь обеспеченную законом гарантию
Есть гарантия, обеспеченная законом, достаточно заключить такой специальный договор. Никто вам не мешает покупать софт на таких условиях.
«Гарантия, обеспеченная законом» — это как раз гарантия, которая не требует «специального договора», т.е. гарантия по умолчанию.

Когда вы покупаете автомобиль или дом, вы заключаете специальный договор? Сомневаюсь. Но производитель всё равно несет ответственность если откажут тормоза, или если дом рухнет потому что плохо построен или спроектирован.
В принципе, если это убьёт платную разработку ПО, я был бы не против (за бесплатное ПО вроде как по-вашему не надо нести ответственность). Я вообще не люблю всю эту копирастию. Заодно можно избавиться от исключительных прав на аудио-визуальную продукцию и литературу, а то ждать почти 100 лет до истечения прав слишком долго.
Просто вся разработка будет в виде «задонатьте мне 200.000 и я, может быть, напишу вам ещё одну фичу в своё бесплатное ПО».
Посмотрите на sqlite — он вообще public domain, фичи регулярно добавляются, баги фиксятся, да и код вылизан покруче чем у большинства.

Да, сейчас у него много донатов, но вначале было не так — тем не менее на качество это не влияло.

Можно и ещё найти примеры, но их можно на пальцах пересчитать, хотя сам факт их наличия (при отсутствии у авторов кучи денег) говорит о том что для качественного кода совсем не нужны миллиарды и сотни лет разработки.
Не понимаю, к чему вы клоните. Есть крутые разработчики, типа вышеупонянутых. А есть криворукие, которые тоже пишут бесплатный slack, whats up или того хуже, facebook.

И что теперь, вообще запретить криворуким программировать? Или запретить им выкладывать свои программы на публику? Не много ли вы на себя берёте?
Я клоню к тому же что и раньше — никакие инструменты не изменят качество кода (сами по себе), а вот пряморукие разработчики — изменят.

И да, если бы я был законодателем — ввёл бы экзамены на качество кода и лицензию на коммерческое программирование. В конце концов, за руль без прав не пускают, врачебную практику тоже лицензируют, почему тут должно быть иначе?

А для хобби, за бесплатно — пусть себе пишут без лицензии, так уж и быть :)
Лицензии что обозначают? Что кодеры вызубрили теоретический материал и кое-как сдали. Но это совершенно не значит, что они будут писать хороший код. Можно и писателям-поэтам-журналистам тоже ввести проф. экзамен, но улучшится ли качество литературы от этого?

Кроме того, вы хотите со всех сторон индустрию зажать: компании штрафовать за недоработки их продуктов, программистов экзаменовать, или уже от первой идеи отказались?
Лицензии можно выдавать компаниям, ЧП и фрилансерам.

В Германии есть хороший пример в этом плане (в других областях), называется Meisterbrief. Это сертификат, выдаваемый профессионалу (с необходимостью доказать свои знания в теории и практики), и дающий ему право на осуществление соответствующей деятельности и открытие фирмы по профилю. Он может нанять «подмастерьев» и вообще кого угодно для выполнения работы, с образованием или без, но отвечать за работу будет лично он. Для ряда профессий наличие этого сертификата является обязательным условием для оказания услуг на коммерческой основе (и даже «просто так» — для врачей и юристов, например).

Эта система, увы, не идеальна и не свободна от недостатков, но сама идея довольно здравая — если кто-то хочет быть врачом, электриком, сантехником, то он обязан доказать свою профпригодность, и должен нести ощутимую ответственность за свои ошибки. При правильном подходе можно исключить (или сильно уменьшить) варианты когда «зубрилы» получают такие лицензии, реально не обладая необходимым опытом или знаниями.

А теперь представьте, что система таки реализована. Вы — владелец лицензии, и вам нужно нанять программистов. Зная, что за их ошибки с вас могут снять либо голову либо много денег, вы примете все меры чтобы они были очень крутыми, либо сами будете перепроверять их работу по десять раз, пока не убедитесь что они не накосячили. Тяжко? Тяжко, зато на выходе будет качественный продукт. Ну или придётся заняться чем-то ещё, чтобы с голоду не умереть.

К сожалению, всё это только теория. На практике скорее ИИ научат писать программы не хуже людей, чем произойдут такие законодательные изменения, а до этого момента будем страдать.
Нет, на практике просто никто не будет продавать софт, а будет оказывать услуги вместо этого.

Нужна бухгалтерия? Вот вам услуга — бухгалтер-фрилансер, который будет использовать наш софт и наш хард и никогда на нас не подаст в суд за ошибки в этом софте, потому что он оформлен как соавтор программы. Наёмный бухгалтер будет отвечать за итоговый результат работы (вы ведь ради этого всё затевали), но точно так же и сейчас бухгалтер отвечает за результаты бух. программы, а программисты снова типа не при чём.
С бухгалтерией и похожими вещами я ещё могу представить такую схему, но как быть с ОС, смартфонами, играми, текстовыми редакторами, СУБД, браузерами и IoT? Хотя в случае с IoT это уже потихоньку начали регулировать, по крайней мере в ЕС (и это хорошо).

Фрилансер-оператор ОС, выполняющий распоряжения пользователя для работы с ней, при этом не могущий подать в суд на разработчика ОС, поскольку является её соавтором — вы примерно так себе это представляете?
С бухгалтерией и похожими вещами я ещё могу представить такую схему, но как быть с ОС, смартфонами, играми, текстовыми редакторами, СУБД, броузерами и IoT?
Всё очень просто. Весь мир останется на продуктах больших корпораций, а страна, которая дошла до такого маразма, останется отрезанной от мирового ИТ. В белую будет вынуждена использовать открытое ПО (от ОС до браузеров и офисов) — и тут некому будет предъявить за косяки, т.е. ваша цель не достигнута, а в серую продукты корпораций, естественно тоже без права предъявить претензии.
Это для программ общего назначения, которые можно взять открытые или спиратить. А если специализированный софт, заточенный под заказчика — то через посредников-операторов.
Есть ещё вариант, наплевать на законы, и работать в серую по старой схеме. То есть, платить умеренные деньги разработчикам (проводить по любой статье расходов, хоть как менеджерам по продажам), а они пилят софт, предприятие использует софт без претензий.

Либо как вариант контора разрабатывает бесплатный софт (но не открытый), предприятие является безвозмездным спонсором, и пользуется разработанным софтом опять же без претензий.
Мне кажется, даже в худшем случае это не приведет к таким проблемам, хотя и поколбасит некоторое время.

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

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

Так что в долгосрочной переспективе это win-win, хотя может быть и неприятно некоторое время, особенно для криворуких.
Во-вторых, это стимулирует разработки в области ИИ для автоматизации либо написания программ, либо их качественной проверки на косяки
Авто-проверка да, улучшится. Но безглючный софт — не значит быстрый и оптимальный. Скорее наоборот, будут перепроверять каждое действие тремя разными алгоритмами, а ошибки тщательно скрывать от пользователя. Сейчас программа упала — core dump и багрепорт. А будут все такие случаи тщательно заметать под ковёр. Данные повреждены? А вы докажите, что это из-за программы, а не пользователь их удалил.
можно сделать качественные песочницы для популярных ОС, дабы минимизировать (или вообще убрать) последствия багов и уязвимостей, так чтобы никакой вирус или троян не смогли ничего сделать без явного разрешения пользователя (прощайте, вымогатели и вирусы)
И сейчас можно (белый список EXE и DLL-файлов, разрешённых к загрузке), но никто не делает, т.к. работать неудобно.
а ошибки тщательно скрывать от пользователя

Трудно скрыть воспроизводимые ошибки типа «выполнил ряд действий — программа вылетела», а также уязвимости. В крайнем случае можно это задокументировать в присутствии нотариуса (или другим признаваемым законом способом, включая видеозапись).
Доказать что данные повреждены не пользователем тоже можно, как минимум косвенно, иначе бы Microsoft не признали что их апдейт удаляет данные, а Quora бы заявили что пользователи сами свои данные отдали.

И сейчас можно (белый список EXE и DLL-файлов, разрешённых к загрузке), но никто не делает, т.к. работать неудобно.

Там где критично — делают. Но можно сделать это так чтобы было максимально удобно и незаметно, хотя это и потребует усилий.
Трудно скрыть воспроизводимые ошибки типа «выполнил ряд действий — программа вылетела»
В том-то и дело, что «программа вылетела» будут явно запрещать. Это несложно, установив глобальный перехватчик исключений. При этом, проблема может и правда быть незначительной, просто её никто не увидит и не починит.
иначе бы Microsoft не признали что их апдейт удаляет данные
Потому что им выплачивать компенсации не надо, а иначе сказали бы — доказывайте сами, мы против себя не будем свидетельствовать.
Но можно сделать это так чтобы было максимально удобно и незаметно, хотя это и потребует усилий.
Это потребует денег, потому что настройкой должен заниматься администратор. А бизнес не хочет платить (в том числе за договоры, гарантирующие финансовую отвественность поставщика ПО), потому везде всё и уязвимо.
При этом, проблема может и правда быть незначительной, просто её никто не увидит и не починит.

Если проблема настолько незначительна, что просто незаметна и не мешает программе выполнять свои функции — то какая же это проблема? Но вот «перехватить» порчу данных из-за неправильной работы с памятью (или алгоритма обработки) ой как непросто — данные таки будут испорчены, и скрыть это будет трудно. Равно как и «перехватить» уязвимость с проникновением — тоже практически нереально, она либо есть либо нет (и доказуема легко, если обнаружена).
Если проблема настолько незначительна, что просто незаметна и не мешает программе выполнять свои функции — то какая же это проблема?
Это не проблема, если бы не ваши предлагаемые драконовские меры. Например, при закрытии окна выкидывается исключение, потому что какой-то ресурс освобождается дважды. Вы же — «ага, попался подлый капиталист, теперь заплатишь штраф за глюки». А погасил все ошибки, и проблемы якобы нет, и никто её не решает.
Но вот «перехватить» порчу данных из-за неправильной работы с памятью

Google sanitizers(AddressSanitizer, ThreadSanitizer, MemorySanitizer), Intel MPX, The Application Verifier всякого рода туллинга завались

> Во-первых, пряморукие разработчики всё же останутся,

И первая же ошибка уровня heartbleed пустит их по миру, а остальных заставит заранее уехать туда, где нет подобных гениальных идей.

> ИИ для автоматизации либо написания программ

Будут как ясновидящие в разведке — добывают сведения старым проверенным способом, а этих выставляют как ширму. «Мы не отвечать, эта программа ИИ написать, не наш программист, у нас и нет такой».

> Трудно скрыть воспроизводимые ошибки типа «выполнил ряд действий — программа вылетела», а также уязвимости.

Программа не будет вылетать, будет песочница в песочнице в песочнице. И работать будет в разы медленнее. Если что-то падает — возвращаемся ко входу в программу и говорим что «система подозревает что пользователь не тот и требует повторного логина, это требование безопасности». Что при этом не сохранились данные, так пользователь сам виноват и чинить не будут.
Уязвимости? А в чём выражаются? Данные утекли, а как это доказать? Может, пользователь продал. Или не будет обмена через сеть. Надо обменяться — печатай и вбивай руками, зато уязвимости нет.

> иначе бы Microsoft не признали что их апдейт удаляет данные, а Quora бы заявили что пользователи сами свои данные отдали.

Вы же сами сетуете что им за это ничего не было, а даже сейчас есть скрывающие до последнего утечки, тогда давайте штрафовать комании за утечки по вине персонала, чтобы добить окончательно.
Тем более компьютеров у пользователей рядовых и не будет — не смогут себе позволить столь дорогое удовольствие, а если и будут, то несовместимые с корпоративными (на текущих ОС и софте, в отличии от проверенных систем, которые не должны тащить ошибки прошлого, а совместимость — уже не конкурентное преимущество). Это сейчас софт берёт массовостью, деля цену на всех, а в вашем случае производитель будет не заинтересован в массовости (больше вариантов иска), но заинтересован в прежней выручке (и даже большей), потому цена вырастет кратно.
> но как быть с ОС, смартфонами, играми, текстовыми редакторами, СУБД, браузерами и IoT?

Зачем вам ОС? У бухгалтера она есть, а вам не надо, вам надо будет снова становиться законодателем, чтобы обязать бухгалтера не сливать ваши данные (а то вы снова понадеялись законодательство и не включили эти пункты в договор).

Смартфон не нужен, есть домашний телефон как услуга, есть таксофон, смартфон — пережиток прошлого, дикой эпохи ненадёжного софта. Как и эти ваши гадкие автомобили, в которых тоже был софт. Пользователь доехал на лошади до таксофона и звонит. Текстовый редактор тоже бесовское изобретение, достаточно дойти до бюро машинисток, которые предоставляют соответствующие услуги.

> вы примерно так себе это представляете?

И ещё немного подпольного софта, который не требует гарантий и можно использовать на свой страх и риск, зато не платя миллионы.
UFO just landed and posted this here
Как я слышал, sqlite просто разрабатывают глубоко верующие люди...))))
Ради интереса, вы поузнавайте, сколько у них лицензия стоит.
Результат вас, скорее всего, удивит.
Лицензия там не даёт преимуществ, даже приоритета в поддержке. Или это как сувенир (бумага с живыми подписями), или как способ задонатить, проведя через бухгалтерию по нормальной статье, не вызывая батхёрта акционеров.
> Мне кажется очевидным что такие договора подпишут единицы

И получат конкурентное преимущество над теми, кто не подпишет и останется со счётами и логарифмической линейкой.

Можете попробовать начать с себя — заказать для своей деятельности софт (начиная с ОС, хотя лучше начать с прошивки железа, а ещё лучше с самого железа).

Вам не кажется очевидным, что к вам выстроится очередь желающих продать свои услуги?

> Посмотрите на sqlite — он вообще public domain, фичи регулярно добавляются, баги фиксятся, да и код вылизан покруче чем у большинства.

Вылизан исключительно потому что его авторы зарабатывают где-то ещё, если им не на что будет жить, то он будет вылизан исключительно в попытках найти на повехности что-то съедобное.
UFO just landed and posted this here
Как вы себе это представляете? Пример:

weird(int[] arr)
{
    for (int n = 0; n < arr.length; n++) {
        arr[arr[n] ^ 0x55] ^= 0xAA;
    }
}

И как можно статически это проверить? А если условие не имеет отношения к индексу и/или размеру, и индексы вычисляются извне, то в начале цикла вообще нет смысла проверять. Пример конечно искусственный, но это чисто для демонстрации.

Поэтому в «безопасном» языке либо придётся «дуть на воду», либо явно отключать такие проверки прагмами или чем-то ещё (тоже тот ещё способ) — в конце концов, кто-то кто вызывает weird() может гарантировать что никакой элемент не будет больше чем 0xFF и что размер массива как минимум 256 элементов, а вот компилятор этого может и не узнать.
UFO just landed and posted this here
Тайпчекер и контракты хороши, если весь исходный код доступен и написан на одном языке, компилятору с которого можно всё рассказать. Но в приведённом мной примере Rust не помощник. Я не очень хорошо его знаю, но насколько я помню там нет контрактов — это величайшее упущение для «безопасного» языка (в то же время C# имеет pre-, postconditions и invariants).
это величайшее упущение для «безопасного» языка

Безопасный язык по-умолчанию будет дуть на воду. В Rust вы можете реализовать pre/post-conditions через 2 функции, где одна будет unsafe и использовать индексирование без проверки размера, а вторая будет проверять условия и вызывать unsafe функцию.

UFO just landed and posted this here
Рискну предположить, что в этом случае ядро будет очень сильно тормозить. Как пример — безопасный язык просто обязан проверять соответствие индекса размерам массива, это несколько лишних операций, больно бьет по кэшу и т.п. — а в ядре ОС таких операций немало, причём в довольно критичных местах.

Без бенчмарков это вилами на воде писано. Да, в чем-то мы проигрываем, а в чем-то выигрываем: например, раст все ссылки помечает как noalias. Какую выгоду это несет по производительности, думаю, говорить не стоит. Или когда можно безопасно ссылаться на данные там, где в вы будете их копировать просто ради собственного спокойствия (пример). Ну и так далее… Или вот статья — как думаете, во сколько раз наивный написанный в лоб раст медленнее оптимизированных плюсов? Ответ думаю вас удивит.

А для остальных приложенией — да посмотрите на мир Java, типа супер-безопасный язык (с точки зрения указателей как минимум), и сколько уязвимостей уже было в продуктах на нём писанных.

И ни в одном из них нет багов use after free и им подобным. Выше уже сказали — если нет техники, избавляющейся от всех проблем, давайте вообще никаких не решать?

Не поймите неправильно, я не утверждаю что не нужны безопасные языки, или что не нужно жертвовать производительностью ради безопасности — просто проблему нужно решать с другой стороны.

Вот в этом ваша ошибка :) Вы думаете, что безопасность и скорость — это взаимообратные величины, между которых нужно балансировать. А если посмотреть на слоган того же раста: Rust is a systems programming language focused on three goals: safety, speed, and concurrency.. И это не маркетинговый буллшит, а действительно так и есть, стоит только посмотреть на примеры которые я дал чуть выше.

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

Да ладно вам, лучше проще — законодательно запретить (с угрозой расстрела) программистам баги делать. И тогда точно заживем.

С другой стороны, возьмём софт который работает в борткомпах каждого современного автомобиля, самолёта etc — часто там обнаруживают уязвимости? А удаленные?

Постоянно находят. Сколько роликов про удаленный взлом каких-нибудь Тесл не перечислить. И это с учетом тех сил, которые тратятся.

Так что, повторюсь — язык это дело десятое.

Первостепенное. Нужно просто перестать себя обманывать, что «ну мне тут нужно быстро, так что безопасно не выйдет». Нет такой аксиомы :) Это как пятая аксиома Евклида — все к ней привыкли, но на самом деле от неё спокойно можно отказаться.
Или вот статья — как думаете, во сколько раз наивный написанный в лоб раст медленнее оптимизированных плюсов?


Код коду рознь, а если у компиляторов один бэкэнд (LLVM) — то всё опять таки упрётся в дополнительные телодвижения (типа проверки индексов), которые оптимизацией невозможно убрать в ряде случаев, просто в принципе невозможно (см. мой пример выше).

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

Пример не совсем корректен — Тесла это сырой продукт, да и если докажут что авария случилась из-за взлома, то отвечать будут по полной, «ой извините, баг» не прокатит (ибо регулируемая отрасль).

Речь шла про технику которая работает автономно и недоступна по интернету. Вам же наверняка известно, что почти в любом обычном (современном) автомобиле есть куча микроконтроллеров? А теперь расскажите как часто у вас отключается ABS сама по себе из-за багов. Ну а если отключится — то производитель будет отвечать очень даже материально. Мне лично неизвестен ни один случай, когда пришлось массово отзывать или перепрошивать серию машин из-за бага в firmware, а вам?

Поэтому я и предлагаю ввести ответственность за продукцию, если за это берут деньги — потому что сейчас от этого зависит жизнь, здоровье, благосостояние и т.п. Берешь деньги — давай гарантию, это честно. Накосячил так что потребитель пострадал — отвечай. В чём я неправ?

это не маркетинговый буллшит, а действительно так и есть, стоит только посмотреть на примеры которые я дал чуть выше.

Извините, но это именно маркетинговый буллшит. Толку с того на чём он focused, если писать будет криворукий программист? Ну не сможет он накосячить с памятью, зато накосячит в куче других мест. Даже хуже — криворукий подумает что ему вообще ни о чём думать не нужно, достаточно писать на этом языке (да, многие так думают) — и такого напишет… А для пользователя совершенно неважно как именно он накосячил — важно что «не работает как надо».

Все, абсолютно все без исключения баги (связанные с памятью или нет) — либо от криворукости, либо от невнимательности, либо от усталости, в общем как ни крутите — это вина разработчика (софта или железа), а не языка, так почему бы их не построить, или не контролировать и обучать жёстко?

Моё решение (либо исключить либо жётско контролировать человеческий фактор) универсально, а супер-мега-безопасный язык только создаст иллюзию решения проблемы, хотя решит всего лишь малую её часть.
Код коду рознь, а если у компиляторов один бэкэнд (LLVM) — то всё опять таки упрётся в дополнительные телодвижения (типа проверки индексов), которые оптимизацией невозможно убрать в ряде случаев, просто в принципе невозможно (см. мой пример выше).

Непонятное какое-то сравнение. У хаскелля тоже есть llvm бэкенд, значит ли это, что они будут по производительности равны (если мы уберем проверки индексов)?

Речь шла про технику которая работает автономно и недоступна по интернету. Вам же наверняка известно, что почти в любом обычном (современном) автомобиле есть куча микроконтроллеров? А теперь расскажите как часто у вас отключается ABS сама по себе из-за багов. Ну а если отключится — то производитель будет отвечать очень даже материально. Мне лично неизвестен ни один случай, когда пришлось массово отзывать или перепрошивать серию машин из-за бага в firmware, а вам?

Большинство бытовой и подобной техники — это всякие жабы со всеми вытекающими. Миллиард устройств не на ровном месте взялся.

Извините, но это именно маркетинговый буллшит. Толку с того на чём он focused, если писать будет криворукий программист? Ну не сможет он накосячить с памятью, зато накосячит в куче других мест.

Куча других мест намного более очевидна. Косяки в бизнес-логике можно отловить тестами, например. Хотя вот это отдельно хотел прокомментировать:
Даже хуже — криворукий подумает что ему вообще ни о чём думать не нужно, достаточно писать на этом языке (да, многие так думают) — и такого напишет… А для пользователя совершенно неважно как именно он накосячил — важно что «не работает как надо».

То есть язык должен был максимально неудобным, чтобы программист всегда был «в тонусе»? :)

Все, абсолютно все без исключения баги (связанные с памятью или нет) — либо от криворукости, либо от невнимательности, либо от усталости, в общем как ни крутите — это вина разработчика (софта или железа), а не языка, так почему бы их не построить, или не контролировать и обучать жёстко?

Глупо обвинять в том, что естественно. Примерно как обвинять кондитера, что у него не все пирожки идеальной одинаковой формы.
Моё решение (либо исключить либо жётско контролировать человеческий фактор) универсально, а супер-мега-безопасный язык только создаст иллюзию решения проблемы, хотя решит всего лишь малую её часть.

У вас нет никакого решения. Никто не будет работать по таким правилам вообще. Если вы введете расстрел за баги — наследующий день у вас будет куча новых шоферов и грузчиков, и ни одного программиста.
Непонятное какое-то сравнение. У хаскелля тоже есть llvm бэкенд, значит ли это, что они будут по производительности равны (если мы уберем проверки индексов)?

Одинаковые алгоритмы с одинаковыми структурами данных — да, будут равны. Например, простая функция которая возвращает сумму элементов целочисленного массива — написанная на Rust, C, C++ и хаскеле, пропущенная через LLVM — выдаст (с вероятностью 99,9%) одинаковый код. Если мы углубимся в объекты и тонкости их реализации с таблицами методов и прочими безобразиями — тут уже, скорее всего, будут отличия поболее.

Большинство бытовой и подобной техники — это всякие жабы со всеми вытекающими. Миллиард устройств не на ровном месте взялся.

Я вообще-то говорил не о простой «бытовой» технике, не зря сказал про автомобили — там практически нет багов в продакшн именно потому что производитель очень материально отвечает за их последствия. Насчёт жабы там сильно сомневаюсь, мощности и память не те. Впрочем, думаю, если найдут баг в микроволновке, которая взорвется или загорится из-за перегрузки, если в определенной последовательнсти нажать какие-то кнопки — то призводитель тоже ответит по самое не могу. А если розетка управляемая Алексой не включится — то да, никто не будет отвечать, хотя хз какие там будут последствия.

То есть язык должен был максимально неудобным, чтобы программист всегда был «в тонусе»? :)

Я где-то сказал «неудобным»? Он просто не должен вставать у меня на пути, если я явно этого не хочу. Моя программа — я царь горы. Это инструмент. Если мне непосчастливится работать в компании где это обязательно (стреляющий за ляпы компилятор) — ок, другое дело. Но пока у меня есть выбор — я хочу им пользоваться.

Верьте или нет, но после первых 5 лет написания проектов на C, я научился не делать ошибок связанных с работой с памятью, валидация всего на входе, выходе и даже между ними у меня уже в крови, даже в наскоро написанных программах — зная о чём нужно думать, их легко избегать, особенно когда отладчик использовать невозможно и приходится всё держать в голове (да, в те далекие времена отладчики были роскошью, впрочем, как и наличие какого-либо компилятора C).

И чем мне тут помог бы Rust? Вы конечно скажете что я могу устать, опечататься etc — да, когда-нибудь это начнёт случаться. Но я глубоко уверен, что если человек начинает настолько уставать или становится невнимательным, что делает ошибки в коде (которые не замечает после первого перечитывания на свежую голову) — ему пора менять род деятельности, на тот где он не сможет делать ошибок, по крайней мере таких ошибок которые не сможет исправить до выкатывания продукции в прод.

Глупо обвинять в том, что естественно.

Я не обвиняю, я указываю на источник проблемы. Как это ни прискорбно, но это из серии «нет человека — нет проблем». Поэтому идеальное решение — устранить из цепочки человека. Чуть менее идеальное — заставить его ошибаться почти никогда, или исключительно редко. Получается ведь у тех кто бомбы обезвреживает, почему не получится у программистов?

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

Давайте всё же не будем утрировать — я не такие драконовские меры предлагаю. А насчёт «никто не будет» — снова напомню про производителей автомобилей и прочей техники, где ответственность за баги весьма чувствительна (станки с ЧПУ и прочие промышленные роботы, как пример) — работают же, причём почти без багов. По крайней мере без таких которые явно ощутимы или даже хотя бы заметны. Причём, заметьте, автомобили при этом стоят вовсе не миллионы — эти микроконтроллеры и прочие embedded есть даже в дешевых авто.

Не хотите отвечать за содеянное — не берите деньги, а если уж берёте — то отрабатывайте и отвечайте за косяки. Я лично готов, а вы?
«Но я глубоко уверен, что если человек начинает настолько уставать или становится невнимательным, что делает ошибки в коде (которые не замечает после первого перечитывания на свежую голову) — ему пора менять род деятельности»

Ребята, сворачиваемся.
Ребята, сворачиваемся.

То есть вы предпочитаете раскачивать поезд, создавая иллюзию его движения, даже когда уже совершенно очевидно что это иллюзия?

Если так — успехов вам.

Вовремя уйти — не позорно. Правда, чтобы это понять, нужно время. В вашем случае оно, видимо, ещё не пришло.
UFO just landed and posted this here
UFO just landed and posted this here
Вектор в Rust — это не эквивалент массива в C. Я говорил про одинаковые структуры данных. Если они неодинаковые, то код, ясный пень, будет разным.
Программист на фортране может писать на фортране на любом языке программирования.

Мы говори про «типовое решение одной и той же задачи», а не как в проект на любом языке заимпортировать сишных апишек.
А я вот вижу умные указатели, move-семантику, ссылки, и вижу проекты, в которых пишут строго по канонам «современного C++», и бьют по рукам за небезопасные конструкции. А рядом вижу небезопасные инструкции, за счет которых получаем высокую скорость и низкие накладки по ресурсам. Так что я бы посоветовал Алексу Гейнору подумать, за счет чего современный Интернет вообще работает на современном железе. Точнее, я бы это сделал, если бы его заявление не было очередной явной попыткой унизить плюсы и раcпиарить Rust.
А рядом вижу небезопасные инструкции, за счет которых получаем высокую скорость и низкие накладки по ресурсам

За это тоже надо было бить по рукам. К тому же с большой долей вероятности в этом не было никакого смысла, т.к. бенчмарки никто не проводил как обычно это бывает.

Таки Rust практически равен С/С++ в производительности. Ничего бы с интернетом не случилось, если бы внезапно весь стек его технологий был перенесен на Rust. Стало бы только лучше и знаменитый heartbleed мы бы не увидели.
бенчмарки никто не проводил как обычно это бывает.
А вот по себе судить не надо, пожалуйста.
Таки Rust практически равен С/С++ в производительности.
То есть все таки проводите бенчмарки?
если бы внезапно весь стек его технологий был перенесен на Rust.
Внезапно этого точно не случилось бы, как минимум на это нужно потратить много времени. А кроме Mozilla в этом никто особо не заинтересован, насколько я понимаю.
бекенд у компилятора раста тот же llvm, что и в clang для c++, поэтому разница в производительности эквивалентных программ как правило будет несущественной.

Естественно, существуют различия. Например, в расте нельзя обработать out of memory и поэтому компилятор может агрессивно оптимизировать выделения/освобождения памяти. С другой стороны, исключения в с++ производительнее для преимущественно позитивных сценариев. High ground c++ только в том, что в нем всегда можно повторить поведение «как в rust», а наоборот — нет. Но это почти никогда и не нужно
UFO just landed and posted this here
По крайней мере по benchmark game у раст с плюсами и си паритет. Где-то он быстрее, где медленнее.
может и не ограничивается, но и выше головы на фронтенде не прыгнешь. Он для оптимизаций может сделать ровно столько, сколько дают гарантии языка. И сколько бы их у раста ни было, этого не хватит чтобы значительно оторваться от плюсов
Опущу ваши попытки уязвить, явно не поняв вообще сути моего комментария про бенчмарки.

Внезапно этого точно не случилось бы, как минимум на это нужно потратить много времени. А кроме Mozilla в этом никто особо не заинтересован, насколько я понимаю.

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

Переписывать с C/C++ на то что кардинально от него отличается по своим концепциям — это огромный труд.

Что мешало взять D в качестве безопасного языка, в крайнем случае допилить его если чего-то не хватает? Уж всяко проще было бы для любого сишника переписать на D, чем учить Rust и его зубодробительные отличия, при этом не имея возможности хотя бы частично использовать имеющийся код.

UFO just landed and posted this here
Смотря каких. Разумеется, от всех не спасает, но и Rust тоже спасает далеко не от всех.
Кроме атомиков, там в конце про них есть пояснение, что их не учитывали. Да и сам Rust на своем сайте никаких гарантий не дает — атомики как они есть могут сотворить что угодно.
Формально доказано не совсем это, вы хотя бы просмотрите сей труд, что-ли. Не говоря уже о том что этот пруф базируется на предположении что используются только стандартный фреймворк и библиотеки, и делает ещё массу всяких допущений.

Сам по себе язык вполне допускает race conditions (их невозможно проверить статически, особенно если поведение программы в целом и потоков в частности зависит от внешних данных), да и документация не делает таких утверждений, даже наоборот:
So it's perfectly «fine» for a Safe Rust program to get deadlocked or do something nonsensical with incorrect synchronization. Obviously such a program isn't very good, but Rust can only hold your hand so far. Still, a race condition can't violate memory safety in a Rust program on its own. Only in conjunction with some other unsafe code can a race condition actually violate memory safety.

Грубо говоря, пока там есть unsafe код, то никаких гарантий нет и не может быть, не говоря уже о том что race conditions не ограничиваются некорректной синхронизацией обращения к памяти (а только от этого язык и спасает, по сути, и то если не использовать unsafe).
Формально доказано не совсем это, вы хотя бы просмотрите сей труд, что-ли.

А что там доказано?


Грубо говоря, пока там есть unsafe код, то никаких гарантий нет и не может быть

Грубо говоря, вы не правы. Пусть у нас есть безопасный код, разбавьте код unsafe {NOP}, он будет таким же безопасным.


Вы плохо понимаете смысл unsafe. Советую почитать https://doc.rust-lang.org/nomicon/safe-unsafe-meaning.html

А что там доказано?

Там доказано, что в случае если мы будем использовать сферического коня в вакууме, то race не будет. Конечно, я утрирую, но они делают массу предположений о среде, библиотеках, etc. — а вы пишете «спасает от всех рейс кондишнов» — в то время как в труде говорится о конкретных, а не всех.

Грубо говоря, вы не правы. Пусть у нас есть безопасный код, разбавьте код unsafe {NOP}, он будет таким же безопасным.

Мне казалось очевидным, что речь шла не про unsafe {NOP}. Речь шла о том что при желании, незнании (или неправильном знании, или малом опыте) race очень легко можно устроить, язык этого не предотвратит сам по себе.

Вот если бы ни при каких условиях, независимо от того как и какой пишется код, race были бы невозможны в принципе — тогда да, я бы с вами согласился. Но это, увы, не так.
Вы можете грепнуть по проекту, и найти ВСЕ возможные места, где может возникнуть race. Вопрос — можно ли подобное сделать в каком-либо другом проекте?

Заранее отвечая на вопрос, что unafe будет очень много и всех не отследить: в одном известном фреймворке actix была проблема с unsafe, был целый пост на реддите. Автор ни в чем себя не сдерживал, и в большом асинхронном актор фреймворке было аж 100 использований. Но с тех пор была проведена работа, и примерно за неделю количество их было сокращено до 15, каждый из которых был просмотрен десятками глаз, и было решено, что они не UB.

Как сделать подобное ревью любой приличной С++ базы, я не представляю. Смысл как раз в том, что в расте вы грепаете unsafe, и смотрите, нарушаются инварианты или нет. Вам не нужно смотреть миллионы строк кода, достаточно пары десятков строк на каждый unasfe, которых в проекте тоже не больше пары десятков. Это задача, которую можно решить за пару дней. Для довольно крупного проекта.

Попробуйте теперь вровалидировать какую-нибудь akka.net, что в ней нет рейсов. Это я уж про плюсы я молчу.
Ещё раз повторюсь — Rust гарантирует только отсутсвие race, связанных с памятью. Точка. Все остальные вы ничем не грепнете, потому что к unsafe они не имеют отношения.

Хотя, в любом большом проекте с сотнями тысяч строк кода, не зная архитектуры приложения, не зная намерений разработчиков, не зная самого кода (внешний review) греп вам очень мало поможет.

Что касается других языков (любых) — нужно изначально писать код, который к ним не может привести. Пряморукий и опытный разработчик это сделает легко даже на ассемблере, причём на автомате, ему не нужна помощь компилятора.

Я не спорю что языки типа Rust снижают количество очевидных ошибок, но всё равно, большей частью речь только об ошибках связанных с обращением к памятью, в редких случаях других очевидных ляпах (типа присваивание вместо сравнения как в C, хотя это может быть и намеренно) — но это не решает проблему с багами в целом, это лишь уменьшит их количество (ненамного — C/C++ и прочие «небезопасные» языки и так мало где используются уже).

Если даже «прям щаз» всё что написано на C/C++ перепишут на Rust, это не сократит количество багов и уязвимостей даже на половину — по крайней мере, до тех пор пока разработчики не станут намного более квалифицированными.

В этом, собственно, и заключается моя мысль.
Borrow checker можно использовать не только для памяти. Он может защищать даже от не синхронизированного доступа к мешку картошки, или утечки этого самого мешка. Если правильно его готовить, не гарантированно, это правда. Также правда что это можно на любом языке. Но borrow checker позволяет создать абстракции, используя которые, клиентский код не сможет сделать некоторые ошибки.

Просто память защищена по дефолту. Другие ресурсы нужно самому.
Ещё раз повторюсь — Rust гарантирует только отсутсвие race, связанных с памятью. Точка. Все остальные вы ничем не грепнете, потому что к unsafe они не имеют отношения.

А какие еще race раст должен предотвращать? Конечно же, под памятью мы понимаем любые ресурсы, каналы там, сокеты, и всё-всё остальное. Программа вроде ничего другого и не умеет делать :)


Хотя, в любом большом проекте с сотнями тысяч строк кода, не зная архитектуры приложения, не зная намерений разработчиков, не зная самого кода (внешний review) греп вам очень мало поможет.

Ну вот практика показывает, что вполне поможет. Открываете любой проект, который видите первый раз в жизни. Грепаете ансейф. После этого смотрите на правила раста


Unlike C, Undefined Behavior is pretty limited in scope in Rust. All the core language cares about is preventing the following things:
— Dereferencing null or dangling pointers
— Reading uninitialized memory
— Breaking the pointer aliasing rules
— Producing invalid primitive values:
— — dangling/null references
— — a bool that isn't 0 or 1
— — an undefined enum discriminant
— — a char outside the ranges [0x0, 0xD7FF] and [0xE000, 0x10FFFF]
— — A non-utf8 str
— Unwinding into another language
— Causing a data race
That's it. That's all the causes of Undefined Behavior baked into Rust.

Если определяете любой из этих случаев — UB есть. Если нет — то нет.


Никакой контекст для этого вам не нужен. Т.к. в unsafe не бывает больше десятка-другого строчек, то и понимание проекта вам не особо нужно: достаточно локального понимания, что вот эти переменные таких вот типов, и мы не разыменоваываем null до проверки.


Что касается других языков (любых) — нужно изначально писать код, который к ним не может привести. Пряморукий и опытный разработчик это сделает легко даже на ассемблере, причём на автомате, ему не нужна помощь компилятора.

Видимо, популярные ОС, приложения под них, браузеры, виртуальные машины и все остальное пишут неопытные.


Я не спорю что языки типа Rust снижают количество очевидных ошибок, но всё равно, большей частью речь только об ошибках связанных с обращением к памятью, в редких случаях других очевидных ляпах (типа присваивание вместо сравнения как в C, хотя это может быть и намеренно) — но это не решает проблему с багами в целом, это лишь уменьшит их количество (ненамного — C/C++ и прочие «небезопасные» языки и так мало где используются уже).

Если оно уменьшает количество багов хотя бы в 2 раза, то это уже хороший такой толчок. А для этого есть все предпосылки.


Если даже «прям щаз» всё что написано на C/C++ перепишут на Rust, это не сократит количество багов и уязвимостей даже на половину — по крайней мере, до тех пор пока разработчики не станут намного более квалифицированными.

Конечно сократит — потому что компилятор явно не соберется там, где раньше была проблема. И у разработчика остается только либо исправить ошибку, либо написать unsafe, отстрелить ногу, и получить возврат кода на review, потому как проверить тыщи строк PR'а пытливым взглядом сильно труднее, чем зацепиться взглядом за unsafe, и попробовать детально проанализировать чем он занимается.


В этом, собственно, и заключается моя мысль.

поток 1 хочет захватить мьютексы в порядке A,B а поток 2 — в порядке B,A. Как именно раст предотвращает такой сценарий?

Никак. И это не считается за UB, это считается за ошибку логики приложения.


А как C++ решает проблему, когда есть ресурс, в который пишут из двух потоков, но забыли сделать mutex::lock? Rust эту проблему решает.

раст рекламируется как язык «предотвращающий гонки памяти на уровне семантики». И тут вдруг оказывается что любые ошибки которые раст не предотвращает — «ошибки логики приложения». Не надо так, называйте вещи своими именами

Да, я понял к чему вы ведете. Да, будет дедлок. Нет, раст от этого никак не защитит.


Rust is otherwise quite permissive with respect to other dubious operations. Rust considers it "safe" to:
  • Deadlock
  • Have a race condition
  • Leak memory
  • Fail to call destructors
  • Overflow integers
  • Abort the program
  • Delete the production database


However any program that actually manages to do such a thing is probably incorrect. Rust provides lots of tools to make these things rare, but these problems are considered impractical to categorically prevent.
Это же не race, а deadlock.
Deadlock это частный случай более общего определения race condition.
Конечно же, под памятью мы понимаем любые ресурсы, каналы там, сокеты, и всё-всё остальное.

По определению, никакой язык не в состоянии гарантировать ничего что выходит за рамки среды, которую он контролирует. Race может быть внешним, от языка не зависящим, он может быть gracefully processed (извините, не могу найти русский эквивалент), или может привести к проблемам. Собственно, про это явно говорится в документации к Rust.

Видимо, популярные ОС, приложения под них, браузеры, виртуальные машины и все остальное пишут неопытные.

Да, неопытные — большей частью. Тот факт что им удается сделать что-то работающим, нисколько не исключает тот факт что их способ — не самый оптимальный и не свободен от ошибок.

Это не значит что ничего не нужно делать, если не делать это хорошо — но факт остается фактом.

Если оно уменьшает количество багов хотя бы в 2 раза, то это уже хороший такой толчок. А для этого есть все предпосылки.

Неважно, сколько яда попадёт в ваш организм, если это смертельная доза. Мне, как потребителю, неважно, что программисты пофиксили 99% багов, если из за 1% отказали тормоза и я въехал в бетонную стену. Радуйтесь, что в большинстве случаев это не тормоза.

И у разработчика остается только либо исправить ошибку, либо написать unsafe, отстрелить ногу, и получить возврат кода на review, потому как проверить тыщи строк PR'а пытливым взглядом сильно труднее, чем зацепиться взглядом за unsafe, и попробовать детально проанализировать чем он занимается.

В этом и заключается проблема современных разработчиков.
Более чем 10 лет я писал write-only код, который вылизывался перед продакшн, потом работал более чем эти самые 10 лет без единой проблемы (и это был не Rust), и единственная поддержка в которой он нуждался — это хорошая документация. Увы, эти времена прошли, за последние 20 лет я не встретил (лично) никого кто был бы на такое способен. Печаль.
Да, неопытные — большей частью. Тот факт что им удается сделать что-то работающим, нисколько не исключает тот факт что их способ — не самый оптимальный и не свободен от ошибок.

Это не значит что ничего не нужно делать, если не делать это хорошо — но факт остается фактом.

Интересно, чем же таким интересным занимаются все опытные. Явно не ядра ОС пишут, и не новые языки. Да и ничего из популярного софта, ведь там регулярно то одна дыра, то другая.

Неважно, сколько яда попадёт в ваш организм, если это смертельная доза. Мне, как потребителю, неважно, что программисты пофиксили 99% багов, если из за 1% отказали тормоза и я въехал в бетонную стену. Радуйтесь, что в большинстве случаев это не тормоза.

Вот только не надо этих сказок про «чуть-чуть беременная». Качество кода — непрерывная величина, которая начиная с некоторого предела (за которым «абсолютная неработоспособность продукта») растет и растет. В винде куча багов, но она спокойно себе работает. Если бы багов стало в 2 раза меньше, это конечно же было заметно. Она была бы стабильнее, удобнее, и все такое. Но никто никуда не въезжает несмотря на текущее положение дел, хотя без этих багов жизнь была бы краше.

В этом и заключается проблема современных разработчиков.
Более чем 10 лет я писал write-only код, который вылизывался перед продакшн, потом работал более чем эти самые 10 лет без единой проблемы (и это был не Rust), и единственная поддержка в которой он нуждался — это хорошая документация. Увы, эти времена прошли, за последние 20 лет я не встретил (лично) никого кто был бы на такое способен. Печаль.

Значит, ваш код не особо был нужен. Или вы заливали код какого-нибудь вояджера, который запускался и делал одно и то же до конца своей жизни.

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

К слову, не-write-only код в документации часто не особо нуждается. Точнее сам код и является документацией, хоть генерируй по нему.
Увы, эти времена прошли, за последние 20 лет я не встретил (лично) никого кто был бы на такое способен.
Это не от программистов зависит, а от заказчиков.

Мне вот каждые 2-3 месяца прилетает такая ситуация. При создании первых версий оказывается, что некоторые очень важные бизнес сценарии будет сделать затратно (по времени). Заказчики клянутся, что такого нам точно не надо, и кое-то важное не закладывается в базу. Естественно, через полгода они начинают ныть, что им это надо, и вот прям сейчас, жить без этого не могут. Я им отвечаю: надо всё переписать, мы же при проектировании закладывались, согласовывали 3 раза, что такого точно не будет — вот вся переписка. Начальник же мне говорит — ничего переписывать не надо, херачь костылей побольше, но сделать надо быстро. Вот так всё и работает )))
UFO just landed and posted this here
Чуть выше можно найти описание того, что является UB. Предотвращение рейсов раст действительно не гарантирует, однако он позволяет детектировать некоторые паттерны, насколько мне известно.

Лично у меня чаще проблемы со значением, которые иногда получается через синхронизацию, а иногда бед, чем с попыткой получить кучу ресурсов в рандомном порядке.
D это не безопасный язык и гарантий больших он не дает. Мало того, что потокобезопасности нет, так еще похоже memory safety там можно сказать отсутствует и есть все теже самые проблемы. Я конечно про него ничего вообще не знаю, но беглый гуглинг дал именно такие ответы. Там есть GC, но чего-то я до сих пор его статус не понимаю. Он вроде бы есть, а вроде не обязательный. Абсурд какой-то.

На rust по-идее можно переписывать частями, т.к. линковку с С/С++ он поддерживает.
D позволяет писать небезопасный код (как и Rust, при желании), но по умолчанию он довольно безопасный. GC это часть стандартного рантайма, его можно отключить (когда нужно) — если не использовать стандартный рантайм (если нужно ручное управление).

Потокобезопасность там достигается рантаймом и библиотеками, хотя если не использовать бездумно shared access (т.е. только обмен сообщениями с примитивами синхронизации) будет ровно то же самое что и в Rust.

Имеющийся код на C/C++ придётся именно переписывать на Rust (который ещё нужно изучить и понять, плюс поменять ряд концепций), в то время как в случае с D его придётся только адаптировать (хотя в случае C++ с тяжелыми темплейтами будет очень тяжко, они совсем разные).

Когда я начал изучать Rust, я понял что создание кода на нём это головная боль и существенно большие временные затраты по сравнению с C/C++/D/C#, не говоря уже об объеме кода (писать придётся больше при одинаковых задачах), а по сравнению с D/C# выигрыш весьма сомнителен (с точки зрения безопасности). К счастью, мне он нужен исключительно read-only (нужно сделать аудит одного проекта), это намного проще чем писать код.

Вы всё же почитайте про D на его сайте, вместо беглого гугления (это не займёт много времени) — и сравните с Rust, как по фичам так и по простоте использования (для сишников).
D позволяет писать небезопасный код (как и Rust, при желании), но по умолчанию он довольно безопасный. GC это часть стандартного рантайма, его можно отключить (когда нужно) — если не использовать стандартный рантайм (если нужно ручное управление).

Понятие "небезопасный" вы формализуйте. А то в одном случае у вас "холодная" погода в 10 градусов, а в другом — "горячий" сверхпроводник с температурой -200С.


Потокобезопасность там достигается рантаймом и библиотеками, хотя если не использовать бездумно shared access (т.е. только обмен сообщениями с примитивами синхронизации) будет ровно то же самое что и в Rust.

Если компилятор не бьет по рукам, то это не безопасность.


Имеющийся код на C/C++ придётся именно переписывать на Rust (который ещё нужно изучить и понять, плюс поменять ряд концепций), в то время как в случае с D его придётся только адаптировать (хотя в случае C++ с тяжелыми темплейтами будет очень тяжко, они совсем разные).

Не надо тешить себя надеждой, на D точно так же нужно переписывать. И в случае с D опять же никакой выгоды нет, мы не можем сказать "да, в этом коде нет багов", просто сделав grep по какому-нибудь ключевому слову.


Когда я начал изучать Rust, я понял что создание кода на нём это головная боль и существенно большие временные затраты по сравнению с C/C++/D/C#

Видимо, компилятор заставил проверить все edge-кейсы сразу? С непривычки может быть довольно напряжно, да. Только в продакшне это все равно придется решать, только позже. Классическая статика вс динамика.


не говоря уже об объеме кода (писать придётся больше при одинаковых задачах)

Да вроде нет, не придется. По крайней мере, если хотим выразить то же самое. А если выражаем больше, то инфы нужно предоставить больше, логично же.


Но учитывая, что большую часть времени мы читаем, то "лишняя писанина" только улучшает понимание кода. В шарпах например я часто пытаюсь понять, что за инстанс тут за интерфейсом скрывается. Потому что в шарпах принято писать с максимальной динамической диспетчеризацией. В расте был бы генерик, из которого всё очевидно.

UFO just landed and posted this here
Писать на расте новый код? — пишите на здоровье, чем бы дитя не тешилось. А вот переписывать отлаженный и рабочий плюсовый код на язык с совершенно другими концепциями — занятие трудоемкое и бесполезное, только еще больше новых багов наплодится. У нас такое называется «непоправимо улучшить»
Я Вас уязвить не пытался, просто в моем мире бенчмарки проводят постоянно, и не боятся использовать небезопасные конструкции там, где это имеет смысл (а такие случаи имеются, уж поверьте). Вы же решили за весь мир, что бенчмарки не делают, а потом начали рассуждать о производительности. Но если Вас это обидело, прошу прощения.
На счет переписывания, мне понятно Ваше стремление, но нежелание потратить огромное время без видимой и сию минуту ощущаемой выгоды — для большинства людей это рационализм, а не лень.
Так переносите, в чем проблема-то?

Да никто не принижает плюсы.


Вот возьмем такой код


#include <memory>

int main () {
  int* p = new int (10);
  std::unique_ptr<int> a (p);
  std::unique_ptr<int> b (p);
}

Что мне в этой ситуации делать? Не помогли ни умные указатели, ни move-семантика.


Обычно мне на такое отвечают, что ни один нормальный программист так писать не будет, и вообще пример искусственный. Ну, не знаю, насколько он там искусственный, но такие примеры делают неплохую прибыль для ребят вроде PVS Studio.

во-первых, мув-семантики тут нет. Во-вторых, использование умных указателей подразумевает также создание объектов через соответствующие функции, для unique_ptr — make_unique.

Ссылаясь на PVS Studio наверно стоит глянуть их блоги и посмотреть, какие именно ошибки чаще всего находит их анализатор. Обычно это неправильное использование ||/&& или другие вариации unreachable/unused code.

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

Уверен, humbug может вам предоставить более жизненный пример.

Ссылаясь на PVS Studio наверно стоит глянуть их блоги и посмотреть, какие именно ошибки чаще всего находит их анализатор. Обычно это неправильное использование ||/&& или другие вариации unreachable/unused code.

Скорее всего просто потому, что их паттерны очевиднее. То есть вопрос «поиска ключей под фонарем». Если работа с умными указателями в 80% является ложноположительной, то никто не будет пользоваться таким инструментом, хотя это означает, что 20% реально баги. А если 20% выделения всей памяти это баги, то это катастрофа.
Предоставляйте сами. Что за детский лепет, третий раз уже в одной теме ловлю за язык. Первые два — 1. вы сказали повторите любой плюсовый код на расте и 2. с вас баг в хроме. Из сотни предупреждений анализатора багами обычно являются 1-2. Я лично не гений и не седовласый адепт, но ошибки памяти допускаю блин раз в полгода от силы. И это очень мало по сравнению с логическими ошибками. И когда я начинал писать на плюсах это соотношение было не в пользу UB (начинал после с++11 но до его введения в конторе). Поймите уже, что раст хоть и хорош, но глобальные проблемы ошибок он не решает и обезьян программистами не сделает. Не надо пожалуйста надуманных синтетических цифр, примеров не от мира сего и прочей ереси. Тем более что плюсы в развитии не остановились

Окей, давайте сыграем по вашим правилам.


Вот реальный код, написанный по канонам С++17, но в нем в продакшне был обнаружен баг. Его достаточно легко найти, когда код изолирован, и про него сказано "тут ошибка", но в проекте на миллионы строк придется попотеть, прежде чем поймете, почему иногда поведение странное


std::vector<_> vec = ...;
auto it = vec.begin(), end = vec.end();
while (it != end) {
    if (/* some conditions on `it` */) {
        ++it;
        continue;
    } else {
        // ...
        it = vec.erase(it);
    }
}
но он написан не по канонам с++17. Надо было использовать vector::erase (c++03) + remove_if (c++03) + lambda (c++11)
UFO just landed and posted this here
Если писать на «безопасном» подмножестве (а это значит без явных new/malloc), то такой ситуации не возникает. А если у Вас чешутся руки вручную выделить память только потому, что это позволяет язык — да, Вам действительно не помогут ни умные указатели, ни move-семантика.
И пример действительно искусственный, так как, судя по статьям от разработчиков PVS, такие баги встречаются довольно редко.
«безопасном» подмножестве

А можно почитать про это безопасное подмножество, чтобы я мог попробовать завалить программу с помощью кода, написанного на этом безопасном подмножестве?

Ну, если для Вас цель написания кода — это завалить программу, то почитайте про умные указатели — они как раз помогают избежать «double free».
Вообще Ваши комментарии такие уверенные, я думал Вы разбираетесь в этом вопросе.

picul вы подтверждаете, что CppCoreGuidelines (в котором я нашел стремную ошибку 3 года назад, когда он еще не был мейнстримом), описывает безопасное подмножество? А если еще найду? :D

Забавно, дурачитесь Вы, а минусуют меня.
Найденная Вами ошибка — как раз про ручное управление памятью, а не про умные указатели. И если Вы хотите мирок Rust'а внутри C++, то разумеется, что это не для Вас. Там же написано в этом самом месте — не надо так делать, используйте make_unique.

Ну подождите, критерий фальсифицируемости никто не отменял. Вы утверждаете, что можно писать безопасные программы на C++. Я утверждаю, что нельзя, предоставляю примеры, которые подтверждают мои слова. Вы говорите, что я должен писать на "безопасном" подмножестве, но не предоставляете мне описание этого "безопасного" подмножества, ведь моя цель — завалить программу и доказать, что безопасного C++ нет.

Вы утверждаете, что можно писать безопасные программы на C++. Я утверждаю, что нельзя, предоставляю примеры
Проверяйте формулировки ваших утверждений. Примером вы доказали, что можно писать небезопасные программы. Но не доказали в общем случае, что нельзя писать безопасные.

Нас интересует высказывания


\any program \in lang_name IsSafe(program)


То есть что любая программа, написанная на некотором языке lang_name (ну или на подмножестве языка, которое назовем так же) не будет содержать ошибок ну скажем неправомерного доступа к памяти.


Опровергается же такая конструкция контрпримером


\exist program \in lang_name Not(IsSafe(program))

А практический смысл в этой казуистике, если на вопрос как можно писать безопасно, не жертвуя производительностью, мне приводят в пример heapless, весь покрытый unsafe-ами, как прыщами?
Эмм, какая разница, что там под капотом?

В вашем коде нет никаких unsafe, и не надо париться ни по какому поводу.

И это мы говорим про «как сделать вычисление без кучи». На практике это достаточно редкая задача, ибо класть гигабайты данных на стек наверное никто не будет.
В вашем коде нет никаких unsafe, и не надо париться ни по какому поводу.
Но так мы теряем свойство языка, что его корректность доказана. Подключая библиотеку с unsafe, или хотя бы разок написав unsafe сами, мы уже не пишем на безопасном языке (до повторной формальной верификации уже нашего кода, что малореально). Вопрос в том, почему язык так спроектирован, что вынуждает делать unsafe? Почему не могли эти «надёжные» unsafe-кирпичики, которые есть в библиотеках, включить в язык, верифицировать с ними и не париться?
И это мы говорим про «как сделать вычисление без кучи». На практике это достаточно редкая задача
Как будто мало других библиотек с unsafe?
Но так мы теряем свойство языка, что его корректность доказана.

Не теряем. Это же свойство языка, а не отдельного крейта)) Если кидать дополнительные камни в ведро, то новые овцы не появятся =)

Ниже уже правильно ответили. Гарантии пропадают, если использовать unsafe.
ОК, если я пишу на Си и в каждой мной написанной строчке не происходит ничего плохого, а стандартную библиотеку я не использую, а пишу всё сам, то программа тоже гарантированно корректна )))

Я вам выше писал :) Для валидации среднего размера на расте вам достаточно просмотреть ~100 строчек кода. Чтобы гарантированно сказать, что тут нет UB, инвалидации указателей и прочего...


В случае С вам нужно просмотреть ВСЕ строчки кода. Причем комбинаторный взрыв говорит о том, что уже на тысячах строчках кода проанализировать что-то будет невозможно.

Вас послушать, может сложиться мнение, что на расте можно писать с отключенным мозгом, и если что, компилятор даст по рукам.

На самом деле, на расте точно так же необходимо просмотреть ВСЕ строчки кода. При написании каждой строчки надо доказывать себе, что это именно то действие, которое решает задачу.

Если говорить о lifetime, то на C++ далеко не каждая строка оперирует lifetime, поэтому тезис, что нужна проверка каждой строки для корректной работы с памятью, тоже неверен.
на расте можно писать с отключенным мозгом, и если что, компилятор даст по рукам.

Но ведь так и есть)) Главное не использовать unsafe

Зачем тогда нужен человек? Сажаешь любую обезъяну, и пусть пишет, пока программа не придёт в компилябельное состояние.
Затем, чтобы думать о более полезных вещах?

Примерно затем же, зачем придумали ассемблер — чтобы не запоминать микрокод конкретных процессоров.
Затем же, зачем придумали Си — чтобы не думать о нюансах конкретных процессоров, а больше о структурах данных


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

На самом деле, на расте точно так же необходимо просмотреть ВСЕ строчки кода.

Не нужно, по построению :)
При написании каждой строчки надо доказывать себе, что это именно то действие, которое решает задачу.

А вот это нужно. Но когнитивная нагрузка уже сильно меньше, потому что п.1.
UFO just landed and posted this here
В случае С вам нужно просмотреть ВСЕ строчки кода. Причем комбинаторный взрыв говорит о том, что уже на тысячах строчках кода проанализировать что-то будет невозможно.

Это если все строки кода взаимодействуют друг с другом. Но ведь на любом языке программисты стремятся собирать программу из отдельных маленьких, самостоятельных и тестируемых компонентов. И не потому, что боятся UB, а потому, что есть пласт ошибок вообще никак не связанных с памятью. И вот так по кусочкам и анализируют. А если делать спагетти, то и на плюсах вкусишь, и на расте, и на жаве, и на питоне…
Это верно.

Проблема в том, что изолировать таким образом код не получится. В одном месте записали нулл — ок. В другом прочитали — тоже ок. А вместе — не ок. То есть баг грубо говоря может покидать пределы функции, где он появился, и влиять в других местах. Ценность ключевых слов вроде unsafe именно в том, что мы ограничиваем контекст, в котором что-то может пойти не так. Дело не в спагетти. В том же шарпе я намучился с NullReferenceException. Потому что падает он в километре от того места, где реально проицинициализировался. Особенно если какие-нибудь умные DI используются.

То есть тут фишка в том, что если у вас есть два модуля, которые оба не имеют UB, то вместе они тоже ГАРАНТИРОВАННО его иметь не будут. В случае C/C#/… функция может неявно предполагает некоторые пред/постусловия, которые вызывающий код может нарушить, и тогда UB прилетит. То есть потестировали небольшой компонент А — всё ок, Б — всё ок, слили вместе — беда.
вот мне моя личная статистика говорит о том, что ошибки памяти — фигня, их легко обойти. Иногда даже удается с первого раза выкатывать работающую программу. А вот ошибки с опечатками в путях к файлам или названиям модулей, ошибки из-за недопонимания чужого апи, ошибки деплоя — вот от них меня кто спасет?
вот мне моя личная статистика говорит о том, что ошибки памяти — фигня, их легко обойти. Иногда даже удается с первого раза выкатывать работающую программу.

Ээ неет, это скорее ошибки памяти легко пропустить и не обнаружить. Потому что если файл не найден, вы это сразу поймете, и в релиз оно не попадет, а если в одном запуске на тысячу вместо какого-нибудь числа читается рандомный мусор, то это можно легко не заметить.

Насчет выкатить программу с первого раза — это я согласен, очень приятно. А что еще приятнее, что на шарпах у меня это стало получаться сильно чаще, чем в свое время на паскале, а на расте еще чаще, чем на шарпах. Полагаю, на хаскеле результат еще лучше, но я до него пока не дорос.

Короче, чем больше статических проверок, тем больше шансы, что код который их все прошел — рабочий.
Тоже заметил такое. С C# в большинстве случаев мне достаточно добиться компиляции и мой код будет корректен с большой долей вероятности с первого раза. С Go это стало еще более явно вплоть до того, что отпала вообще надобность в отладчике, т.к. глазами я и так прекрасно вижу, что код делает, и почему я могу получать тот или иной неправильный результат.

А взять Objective-С, на котором до сих пор пишу постоянно, так там порой такая дичь творится, что диву даешься. В основном благодаря в большинстве случаев вредительской фиче, где nil тихо проглатывает любые вызовы методов. Или что-то крашится, потому что не найден метод в рантайме. Все эти ООП языки с посылкой сообщений красивые только в теории… А если напортачишь где-то с assign вместо strong, то еще веселее становится все. Прям чувствуешь, что в С вернулся с его поимкой повреждений кучи комментированием случайных кусков кода.
Проблема в том, что изолировать таким образом код не получится. В одном месте записали нулл — ок. В другом прочитали — тоже ок. А вместе — не ок
Ну и чем это отличается от ситуации, когда в одном месте написали true — вроде ОК, а надо было false. И язык не поможет.
Тем, что нормальных средств ловить такие ошибки еще не придумали. Как придумают — сразу начну таким инструментом пользоваться.
Вопрос в том, почему язык так спроектирован, что вынуждает делать unsafe? Почему не могли эти «надёжные» unsafe-кирпичики, которые есть в библиотеках, включить в язык, верифицировать с ними и не париться?

Потому что мы можем написать компилятор, который покрывает 99% юзкейсов, и который можно написать за год. Или 100% кейсов, но писать его 10+ лет.


Тем более, что такой язык уже есть, Coq называется. Только вот писать программы вы на нем вы едва ли захотите, потому что доказывать компилятору, что 2 > 1 не самое интересное, чем можно заняться.


Возьмем типичную функцию, которая показывает, что unsafe нужен:


pub fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
    let len = self.len();
    let ptr = self.as_mut_ptr();

    unsafe {
        assert!(mid <= len);

        (from_raw_parts_mut(ptr, mid),
         from_raw_parts_mut(ptr.add(mid), len - mid))
    }
}

По сути тут мы разбиваем один диапазон на два непересекающихся. Проблема в том, что борроу чекер не позволит вам иметь 2 мутабельные ссылки, которые необходимы для формирования такого разбиения. Мы можем просмотреть код, и увидеть, что он ничего криминального не делает: возвращает 2 ссылки, которые заведомо никак не алиасятся, и друг друга не затрагивают.


Написать такой код — дело нехитрое. Перелопатить борроучекер, чтобы он его разрешил — даже не представляю, сколько усилий для этого нужно. А уж как потом будут страдать конечные разработчики. Уже сейчас люди жалуются на "инопланетный синтаксис", а ведь всё, что добавилось — лайфтаймы и ассоциированные типы. А в языке где подобное можно статически проверить там наверное было бы наворочено раз в 5 больше всего.




Короче, unsafe нужен не для стрельбы по ногам, а чтобы упростить компилятор и язык для нас с вами. Что считать unsafe, а что нет — дело трейдофа конкретных языков. Даже в C# есть ансейф и UB, но он все еще сильно безопаснее многих альтернатив.


Трейдоф раста мне нравится. Компилятор в меру придирчивый, но не инопланетный, и доказывать 2+2=4 в 30 листах вайт пейпера не требуется.

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

Верно! :) Поэтому раст позволяет выборочно эти термины "отключать", в случаях, когда они неудобны.


Но практика показывает, что они намного чаще облегчают жизнь, нежели наоборот

UFO just landed and posted this here
Эмм, какая разница, что там под капотом?
В вашем коде нет никаких unsafe, и не надо париться ни по какому поводу.

В std этих unsafe вообще завались. unsafe — не означает, что код плохой, unsafe означает, что программист берет на себя всю ответственность, когда он пишет unsafe. И если код внутри модуля с unsafe не вызывает UB, то и снаружи модуля вызвать UB невозможно. Фундаментальные особенности.

я понимаю. Я к тому, что

1. Практически все основные компоненты стандартной библиотеки формально верифицированны
2. Safe rust is sound.

Из этих двух посылок можно сделать вывод, что код без unsafe не может ничего плохого натворить. Если unsafe есть — то может и не может, а может и может :) Тут попадаем в ситуацию, похожу на плюсовую, не считая того, что места где может что-то пойти не так поддаются счету и легко локализуемы.
Кстати, в std многое можно было сделать без unsafe, но уже как сделали так и есть.
Да я думаю туда PR принимают. Выпилить лишних ансейфов я думаю они не откажутся.

Да, конечно, вы правы. Я доказал, что можно писать небезопасные программы =) Следовательно всегда существует возможность выстрелить себе в ногу на ровном месте.

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

Спасибо!


за это надо платить производительностью

Весьма спорно. Мы переписали ноду tox на Rust, так у нас потребляется чуть меньше CPU, чем на C. И нет ужасных багов https://blog.tox.chat/2018/10/memory-leak-bug-and-new-toxcore-release-fixing-it/, которыми можно выключить вообще все ноды в мире)))))

Это ничего не доказывает. С той же эффективностью можно было переписать на C++, либо попрофайлить исходное приложение и убрать ботлнеки.

Все языки тьюринг-полны, и на любом из них рано или поздно можно сделать работающий софт. Вопрос ведь не в этом.

Просто такой довод… Мы переписали и снизили потребление CPU. Это не заслуга языка, а заслуга алгоритмов. Я легко могу представить ситуацию, когда сервис переписан на Питон, например, и тоже CPU снизилось. Потому что в новой думали об асимптотике и высокоуровневых оптимизациях, а в исходной программе — не думали.

Тогда можно переписать с питона на С и получить выигрыш. Или не получить.


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


Моё мнение, что раст тупо паретто-оптимален. Потому что он находится в недоминируемом множествео тносительно С. Говоря по-человечески, он не медленнее С, но он более продуктивен и безопасен. Из минусов можно отметить только меньшую распространенность. Но я лично для себя я это не считаю оптимизируемым критерием, есть только некоторый порог распространенности, чтобы тупо можно было найти хотя бы одну интересную вакансию.

Лично для меня раст не оптимален, потому что имеет неразвитую инфраструктуру. Мне нужна IDE с мощным интегрированным отладчиком и различными assist-ами, которые, например, предложат автоматически добавить use, если похоже на то, что используется код из известного крейта.

К сожалению, согласен

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

image
UFO just landed and posted this here
UFO just landed and posted this here
Давая возможность для возникновения ошибок типа «memory unsafety», языки программирования, такие как C и C++, могут способствовать распространению почти бесконечного потока критических уязвимостей безопасности на протяжении многих лет.

Очень популярный язык PHP не даёт таких возможностей (сам язык — отдельные уязвимости run-time можно не считать, они исключительно редко использовались).

Тем не менее, в не менее популярной CMS, написанной на PHP, включая весь зоопарк плагинов к ней (я о WordPress, если это не очевидно) имеются просто зиллионы уязвимостей (которые никак не эксплуатируют уязвимости run-time).

Можно покопаться в популярных приложениях на Java или .NET и тоже найти немало уязвимостей, несмотря на то что там вполне неплохая «memory safety».

Так что не в языке дело, однако.
Можно покопаться в популярных приложениях на Java или .NET и тоже найти немало уязвимостей, несмотря на то что там вполне неплохая «memory safety».

Во-первых эти языки не такие уж безопасные.
Во-вторых в них нет целого класса проблем, которые были бы на си.

Автор сам капитан очевидность. По-моему все это давно очевидно всем. Проблема, что невозможно просто так заставить всех перелезть на другие языки, хотя они уже есть и не требуют чем-то сильно жертвовать в обмен на свою безопасность. Проблема это не техническая совершенно.

Конкретно С++ вполне себе безопасен в своем современном представлении. Его проблема в возрасте и накопленном багаже небезопасных конструкций. Просто удалить это все и заставить всех перейти на «безопасный С++» не получится, хотя комитет всеми силами пытается. Тоже самое касается легаси кода — у народа что-то горит вверху, а мысль предельно простая — накоплены тонны кода, который написан небезопасно и мир постоянно от этого страдает. И даже при наличии всего нужного в С++ очень сложно взять и все переписать как следует. Как говорил вроде бы Страуструп, внутри С++ есть маленький лучший язык, который рвется наружу. У языка изначально неправильный приоритет был — небезопасное поведение по-умолчанию. Правильный тренд современных системных языков — безопасное поведение по-умолчанию и не-безопасное, где конкретно об этом попросит программист. К сожалению, поезд уже ушел.

Нелепо конечно видеть такую резкую реакцию на такие предельно очевидные и верные вещи. Хотя понятно с определенной стороны — люди цепляются за любимую игрушку. Естественно все это не исправит и останутся какие-то уязвимости, только вот целый класс других уязвимостей, которые практически всегда являются критическими, можно запросто убрать. Взять теже Java/C# — у них как класс нет перечисленных уязвимостей, но в их случае скорость выполнения все же несколько большая плата за это. Типичная отмаза «не пистолет виноват, а тот, кто стрелял» это совершенно не конструктивно и неуместно.

Вверху приводили в пример JS. Действительно, через него творят жуткие вещи, только вот в этом виноват именно С/С++, а не JS. Чуть ли не все экплоиты так или иначе используют тот факт, что под низом небезопасный С++. Просто эксплуатируются они не напрямую. Какой-нить array в JS на самом деле реализован на плюсах, где и были дырки неоднократно в том же хромиуме. В Java/C# не случайно даже встроенные типы написаны на этом же языке, так безопасность и достигается. Нативный только рантайм, а все остальное под полным контролем, что исключило целые классы уязвимостей.
У языка изначально неправильный приоритет был — небезопасное поведение по-умолчанию.
У языка изначально был приоритет «не платить за то, что не заказывали» — и в общем он его придерживается. Если Вам не нравятся числовые переполнения и «use after free» — жалуйтесь производителям процессоров и разработчикам ОС.
Правильный тренд современных системных языков — безопасное поведение по-умолчанию и не-безопасное, где конкретно об этом попросит программист.
Вообще-то это тренд конца 90-ых, интересно почему Mozilla не написала Firefox на Java?
Действительно, через него творят жуткие вещи, только вот в этом виноват именно С/С++, а не JS.
Подождите, запишу)) Аль-Каидой, видать, тоже C++ руководит?
Какой-нить array в JS на самом деле реализован на плюсах, где и были дырки неоднократно в том же хромиуме. В Java/C# не случайно даже встроенные типы написаны на этом же языке, так безопасность и достигается. Нативный только рантайм, а все остальное под полным контролем, что исключило целые классы уязвимостей.

Святая наивность :)
C# Compiler Options Listed by Category
-optimize Enables/disables optimizations.
-checked Specifies whether integer arithmetic that overflows the bounds of the data type will cause an exception at run time.

Пока будут такие опции — дыры будет всегда :)
И что будет при переполнении? Ничего, произойдет исключение на выходе за границы массива, чем и страшны изначально арифметические переполнения. Сами по себе они уязвимости не порождают. А сборщик мусора всегда гарантирует, что никто не использует объект после освобождения. Поэтому Java и C# напрочь лишены всех этих проблем.

При чем здесь optimize тем более непонятно. Он ничего плохого не сделает. Все проверки и гарантии CLR от этого не исчезнут.
А сборщик мусора всегда гарантирует, что никто не использует объект после освобождения.

А ДО освобождения? И кто вам сказал, что память освбожденная будет затерта нулями в процессе?
Вопрос в том, что как таковая «языковая обязанность» — предотвратить проблемы ДО исполнения, лучше при компиляции. Компилятор добавит свои нюансы при когдогенерции, что бы реализовать «безопасный язык». Для С++ я могу сваять свой умный указатель на пару минут и свои менеджеры памяти пишут для С++, и работать будет похоже на .Net/Java и т.д.
Это никогда не было проблемой для С++, а вот что дизайн нужно продумывать ДО имплементации на С++ тех фич, что на себя берет .Net/ Java & Co — это факт.

Что будет в процессе исполнения — это вообщем не языковая проблема, а среды исполнения(стандартной библиотеки языка) и ее взаимодействия с ОС.
Если вы в С++ /Java / .Net загружаете библиотеки написанные на другом языке — кто виноват в проблемах?
А ДО освобождения? И кто вам сказал, что память освбожденная будет затерта нулями в процессе?
В управляемых языках нет операции освобождения памяти. Либо у процесса есть ссылка на регион (ограниченая размером региона), либо ссылки нет, и тогда читать/писать невозможно. Память переиспользуется, когда на неё больше нет ссылок.
Вопрос в том, что как таковая «языковая обязанность» — предотвратить проблемы ДО исполнения, лучше при компиляции
Компилятор берёт на себя эту обязанность. Код с неинициализированными ссылками на C# просто не скомпилируется, а на C++ с неинициализированными указателями — запросто.
В управляемых языках нет операции освобождения памяти

Это еще почему? а зачем тогда «уборка мусора»?
Либо у процесса есть ссылка на регион (ограниченая размером региона), либо ссылки нет, и тогда читать/писать невозможно.

Именно что «у процесса… ссылка на регион». В этом и проблема что внутри процесса вы можете творить почти что угодно, кроме того что вам запрещает OS и CPU. Как вы получите ссылку, на что она будет указывать — это ваша проблема. Если вы «хороший» — будет указывать «правильно», если вы «плохой» — будет указывать куда вам нужно, и единственное ваше спасение это OS & CPU.

Код с неинициализированными ссылками на C# просто не скомпилируется, а на C++ с неинициализированными указателями — запросто.

Это не панацея, потому что в процессе исполнения можно утворить почти любую пакость и поставить ссылки на то, что нужно «плохишу».
зачем тогда «уборка мусора»?
Читайте выше — чтобы переиспользовать память, когда на неё больше нет ссылок.
Именно что «у процесса… ссылка на регион». В этом и проблема что внутри процесса вы можете творить почти что угодно, кроме того что вам запрещает OS и CPU. Как вы получите ссылку, на что она будет указывать — это ваша проблема
Вы пишете какую-то дичь.
Можете продемонстрировать ваши утверждения примером кода на C#?

Внутри процесса могут жить изолированные AppDomains, которые даже ссылки не могут передавать друг другу.
Это не панацея, потому что в процессе исполнения можно утворить почти любую пакость и поставить ссылки на то, что нужно «плохишу».
Без unsafe нельзя. Или у вас есть пример кода?
А кто-то сказал, что «плохишь» будет делать это только .Net & C#? Или уже нельзя подгрузить в процесс свою DLL написанную на другом языке?
Вот dump просто консольки на .Net:
wow64cpu.dll!TurboDispatchJumpAddressEnd+0x544
wow64cpu.dll!TurboDispatchJumpAddressEnd+0x222
wow64cpu.dll!BTCpuSimulate+0x9
wow64.dll!Wow64LdrpInitialize+0x236
wow64.dll!Wow64LdrpInitialize+0x120
ntdll.dll!LdrInitShimEngineDynamic+0x308f
ntdll.dll!memset+0x1ec93
ntdll.dll!LdrInitializeThunk+0x5b
ntdll.dll!LdrInitializeThunk+0xe

Вот просто DLL загруженные в процесс, где исполняется мой .NET код.
advapi32.dll Advanced Windows 32 Base API Microsoft Corporation C:\Windows\SysWOW64\advapi32.dll
apphelp.dll Application Compatibility Client Library Microsoft Corporation C:\Windows\SysWOW64\apphelp.dll
bcryptprimitives.dll Windows Cryptographic Primitives Library Microsoft Corporation C:\Windows\SysWOW64\bcryptprimitives.dll
clr.dll Microsoft .NET Runtime Common Language Runtime - WorkStation Microsoft Corporation C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
clrjit.dll Microsoft .NET Runtime Just-In-Time Compiler Microsoft Corporation C:\Windows\Microsoft.NET\Framework\v4.0.30319\clrjit.dll
combase.dll Microsoft COM for Windows Microsoft Corporation C:\Windows\SysWOW64\combase.dll
cryptbase.dll Base cryptographic API DLL Microsoft Corporation C:\Windows\SysWOW64\cryptbase.dll
gdi32.dll GDI Client DLL Microsoft Corporation C:\Windows\SysWOW64\gdi32.dll
gdi32full.dll GDI Client DLL Microsoft Corporation C:\Windows\SysWOW64\gdi32full.dll
GuidX.exe Guid P:\Temp Projects\Guid\Guid\bin\Release\GuidX.exe
imm32.dll Multi-User Windows IMM32 API Client DLL Microsoft Corporation C:\Windows\SysWOW64\imm32.dll
kernel.appcore.dll AppModel API Host Microsoft Corporation C:\Windows\SysWOW64\kernel.appcore.dll
kernel32.dll Windows NT BASE API Client DLL Microsoft Corporation C:\Windows\SysWOW64\kernel32.dll
KernelBase.dll Windows NT BASE API Client DLL Microsoft Corporation C:\Windows\SysWOW64\KernelBase.dll
locale.nls C:\Windows\System32\locale.nls
mscoree.dll Microsoft .NET Runtime Execution Engine Microsoft Corporation C:\Windows\SysWOW64\mscoree.dll
mscoreei.dll Microsoft .NET Runtime Execution Engine Microsoft Corporation C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscoreei.dll
mscorlib.ni.dll Microsoft Common Language Runtime Class Library Microsoft Corporation C:\Windows\assembly\NativeImages_v4.0.30319_32\mscorlib\277a04b4ec834bb70c1bd343b14ebd3a\mscorlib.ni.dll
msvcp_win.dll Microsoft® C Runtime Library Microsoft Corporation C:\Windows\SysWOW64\msvcp_win.dll
msvcr120_clr0400.dll Microsoft® C Runtime Library Microsoft Corporation C:\Windows\SysWOW64\msvcr120_clr0400.dll
msvcrt.dll Windows NT CRT DLL Microsoft Corporation C:\Windows\SysWOW64\msvcrt.dll
ntdll.dll NT Layer DLL Microsoft Corporation C:\Windows\SysWOW64\ntdll.dll
ntdll.dll NT Layer DLL Microsoft Corporation C:\Windows\System32\ntdll.dll
ole32.dll Microsoft OLE for Windows Microsoft Corporation C:\Windows\SysWOW64\ole32.dll
oleaut32.dll OLEAUT32.DLL Microsoft Corporation C:\Windows\SysWOW64\oleaut32.dll
rpcrt4.dll Remote Procedure Call Runtime Microsoft Corporation C:\Windows\SysWOW64\rpcrt4.dll
sechost.dll Host for SCM/SDDL/LSA Lookup APIs Microsoft Corporation C:\Windows\SysWOW64\sechost.dll
shlwapi.dll Shell Light-weight Utility Library Microsoft Corporation C:\Windows\SysWOW64\shlwapi.dll
SortDefault.nls C:\Windows\Globalization\Sorting\SortDefault.nls
sspicli.dll Security Support Provider Interface Microsoft Corporation C:\Windows\SysWOW64\sspicli.dll
ucrtbase.dll Microsoft® C Runtime Library Microsoft Corporation C:\Windows\SysWOW64\ucrtbase.dll
user32.dll Multi-User Windows USER API Client DLL Microsoft Corporation C:\Windows\SysWOW64\user32.dll
version.dll Version Checking and File Installation Libraries Microsoft Corporation C:\Windows\SysWOW64\version.dll
win32u.dll Win32u Microsoft Corporation C:\Windows\SysWOW64\win32u.dll
wow64.dll Win32 Emulation on NT64 Microsoft Corporation C:\Windows\System32\wow64.dll
wow64cpu.dll AMD64 Wow64 CPU Microsoft Corporation C:\Windows\System32\wow64cpu.dll
wow64win.dll Wow64 Console and Win32 API Logging Microsoft Corporation C:\Windows\System32\wow64win.dll


Я конечно надеюсь, что все вокруг сделано правильно, но… факты показывают что это не всегда так.
Как-то вы непостоянны ))) Двумя комментами выше
Если вы в С++ /Java / .Net загружаете библиотеки написанные на другом языке — кто виноват в проблемах?
А сейчас
Или уже нельзя подгрузить в процесс свою DLL написанную на другом языке?

А пример C# кода можно, чтобы оно так упало?
Все понятно, понесло не в ту степь. А еще я могу драйвер уязвимый загрузить в ядро, ага. Или подгрузить EFI модуль. Давайте держаться сути разговора, а именно, memory safety гарантии языков программирования.
Давайте держаться сути разговора, а именно, memory safety гарантии языков программирования.

Если рассматривать идеальную среду в которой «все хорошо» и все пишут на «правильном языке» где компилятор математически доказывает корректность программы — тогда не вижу смысла. Это получается как обсуждение «сколько ангелов поместится на кончике иглы».
В идеальном мире ничего обусждать не нужно — там и так все хорошо без нас.
А реальном мире дофига программ пишутся на php, питоне, джаве, и там о проблемах с памятью не думают, но при этом эти проблемы и не возникают.
там о проблемах с памятью не думают, но при этом эти проблемы и не возникают.

Серьезно? Зато вынужден думать я. у меня сейчас мобильный более наворочанный чем сервер лет 10 назад, на котором работали 20 человек и при этом скайп как работал через з@дницу так и работает. А что бы делать ту же работу, что я делал 15 лет назад, я себе на железо потратил тысяч 20 долларов за все это время.
Как мне кажется — это большая «не проблема» потому что «о проблемах с памятью не думают».
Я вынужден оплачивать из своего кармана это маразм.
Я вынужден оплачивать из своего кармана это маразм.
Вас кто заставляет? Бросайте ИТ, выберите другую область деятельности.
Разработчики пишут, как им дешевле. Почему они должны думать о ваших финансах.
Вас кто заставляет?

Да. Что бы посмотреть котиков «в инертенете» ноутбука 2010 года хватало за глаза, на нем еще и виртуальные машины крутились. А в 2018 внезапно стало понятно, что… не хватает! Я сам по началу удивился. Подруге стало не хватать моего бука что бы «смотреть котиков». Пришлось покупать новый. Планшет пришлось сменить по той-же причине — на нем куча сайтов просто нельзя было открыть из-за тормозов.
Понадобилось в 2..3 раза более производительная техника, что тех же «котиков посмотреть».
Т.е меня вынудили, наделав кучу наворотов «в зоопарке» и наплевав на результат.

Почему они должны думать о ваших финансах.

Э… может потому что я им плачу, хотя и вынужденно?
Предвидя Вашу следующую реплику «так не платите», отвечу — «уже частично не плачУ», хотя бы тем, что вырезается вся реклама нафиг.
Много чего произошло с 2010г. Например, аналоговое вещание прекращают со следующего года — надо покупать новые телевизоры. Цены на всё постоянно растут.

Неудивительно, что создатели контента с котиками тоже лезут к вам в карман, пусть косвенно, минимизируя свои затраты на разработку.

И что теперь, жаловаться на весь мир? Жить — дорого. Хочешь удовольствий (котиков) — плати, они подорожали.
Неудивительно, что создатели контента с котиками тоже лезут к вам в карман, пусть косвенно, минимизируя свои затраты на разработку.

Что и требовалось доказать — дело не в языках. Но кодеры-раздолбаи имеют какое-то отношение к происходящему.
У пользователей нет выбора. Хотите котиков — вот вам дорогие котики. Дешевых уже никто не делает, дураков нет )))
Дело тут как раз таки в языках, а конкретно — в HTML, CSS, и JavaScript. Изначально HTML предназначался для описания простых текстовых документов с гиперссылками, но потом его обвешали костылями, и стали делать на нём «богатые» GUI. JavaScript был скриптовым языком, и не предназначался для чего-то большего, чем валидация данных форм перед отправкой их на сервер, но на нём стали писать сложную логику, характерную для десктопных приложений. Вся эта связка технологий чудовищно неэффективна, она тянет за собой бесполезный груз обратной совместимости, она жрёт слишком много ресурсов выполняя несвойственные ей задачи. HTML, CSS, и JavaScript давно уже пора заменить новыми стандартами, более удобными, заточенными под современный веб, и эффективно использующими ресурсы компьютера.
Дело тут как раз таки в языках, а конкретно — в HTML, CSS, и JavaScript.

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

А почему начали на нем писать вещи, для которых не предназначен?
Случайно не надежда на «если посадить миллион обезъян за пишушие машинки они когда-то напечатают Войну и Мир»? Что-то вроде «посадим миллион JS-обезъянок за компы и получим Гениальное Творение».
Порог входа в JS низок, закончилось Electron (народ в соседней ветке обсуждает) и переходом Windows на Chromium движок браузеров «из коробки».
Интернет доказал что «миллион обезъянок не напечатали Войну и Мир» и похоже никогда не напечатают.
Насчет JS — плакать хочется от усилий которые в него вливают. Такую энергию да в мирное русло и что-то, определенно, поправить в «консерватории»...
А почему начали на нем писать вещи, для которых не предназначен?
Потому что люди этим пользуются. Если бы они писали, и никто не пользовался, то и писать перестали бы.
А ДО освобождения? И кто вам сказал, что память освбожденная будет затерта нулями в процессе?

Не понял мысли. До освобождения меня не волнует что будет. Есть указатели живые на объект, значит он кому-то нужен. Нет — сборщик все почистит. Нулями затирать и не нужно. Важно, что никогда мне в руки не попадет неинициализированная памать, спецификация мне гарантирует забитую нулями память при создании любого объекта. Если опасения насчет того, что в памяти где-то остался секрет и его могут достать какими-то внешними способами, то это абсолютно другая проблема и для нее в библиотеке языка есть свои решения.

Опять таки, никакие безопасные современные конструкции С++ не решают полностью проблему. Там все так же полно небезопасного поведения, т.к. безопасность не является частью языка, компилятора, рантайма, стандартной библиотеки и всего вот этого. Хромиум написан вон на С++ современном, а таки JS запросто все равно эскплуатирует в нем уязвимости. Да и банальная многопоточность сломает эти «безопасные» конструкции языка из стандартной библиотеки. Безопасность должна быть от начала до конца, тогда проблема исчезнет.

Что будет в процессе исполнения таки языковая проблема в том числе. C# не в вакууме выполняется, а в CLR, которая несет с собой гарантии. И в спецификации языка сборка мусора прописана конкретно. Так же как проверки выхода за границы и инициализация нулями при создании чего-либо.
Что будет в процессе исполнения таки языковая проблема в том числе. C# не в вакууме выполняется, а в CLR, которая несет с собой гарантии.

Это просто ожидания и надежда что «CLR, которая несет с собой гарантии».
На мой взгляд корректнее сказать " CLR, которая должна нести с собой гарантии".
Flash, JS, Java, .Net — все «CLR которые должны», и…?

Просто потыкать для примера:
Vulnerabilities in the Microsoft .NET Common Language Runtime Could Allow Remote Code Execution (974378)
This security update resolves three privately reported vulnerabilities in Microsoft .NET Framework and Microsoft Silverlight. The vulnerabilities could allow remote code execution on a client system if a user views a specially crafted Web page using a Web browser that can run XAML Browser Applications (XBAPs) or Silverlight applications, or if an attacker succeeds in persuading a user to run a specially crafted Microsoft .NET application.

CVE-2018-8356 | .NET Framework Security Feature Bypass Vulnerability
A security feature bypass vulnerability exists when Microsoft .NET Framework components do not correctly validate certificates.


Я не понимаю, что вы пытаетесь все это время доказать. С чем вы спорите? Первая уязвимость — ничего конкретного по ней найти невозможно, но допустим, одна уязвимость на заре рождения .Net в 2009 году, велика беда. Вторая вообще не имеет отношения к теме, там речь о неправильной верификации сертификатов.

Было бы лучше, если бы вы не бездумно копипастили первое, что попадется, а сначала проверяли и желательно искали конкретную суть уязвимости. Т.к. по первой я до сих пор не уверен, что она связана с нарушением гарантий безопасности памяти, а не с логикой где-то.
Это не спор был, а простой посыл к тому, что надежда на CLR — не очень оправдана (да шаг хороший, но слишком оптимистична).
Уже такое было: Все программисты хорошие и поэтому можно обойтись кооперативной многозадачностью — по факту надежды не оправдались. Тогда сделали вытесняющюю много задачность и аппаратную защиту памяти — по факту надежды не оправдались. Тогда приделали NX биты, CLR & Co — по факту опять надежды не оправдались. Сейчас оказывается надо пределывать языки, процессоры и среду исполения, в надежде что уж на сей раз то точно получится.
Тенденция показывает, на мой взгляд, что проблемы то не в языках…
Тенденция показывает, что вы начали бредить про темы, отдаленно относящиеся к сути разговора и перемешали все уровни исполнения кода. Надежда на CLR оправдана, гарантии она свои выполняет. Если хотите поговорить о проблемах безопасности на другом уровне исполнения, то давайте это делать в каком-то другом месте, а не в теме, где обсуждаются memory safety гарантии языков программирования.
Тогда приделали NX биты, CLR & Co — по факту опять надежды не оправдались
То есть, по вашему нет никакого движения в правильном направлении? В 2018 нужно сидеть всем в одном адресном пространстве с кооперативной многозадачностью, раз уж всё равно полной безопасности нет? Какие-то проблемы закрываются (какие-то остаются), в целом направление развития позволяет создавать ПО большей и большей сложности.
То есть, по вашему нет никакого движения в правильном направлении?

Все эти действия были вынужденной реакцией. Люди которые проектировали С++, Windows 3.0, Intel 286 — были грамотными професионалами. Но даже они — такого не предусмотрели, как тучи «обезъянок-кодеров» и кучу «плохишей».
Неидеальный мир вынуждает двигаться в «правильном направлении».
А вы не путайте memory safety и дыры в песочнице. Обе ваши уязвимости — про второе, про исполнение кода из левых источников. Да, если запускать произвольные программы из интернета — можно схватить вирусню, тоже мне открыли Америку!

Ни одна из этих уязвимостей никак не поможет моему коду выйти за границы массива и не упасть при этом с исключением.
Вот я так и не понял, что эта первая уязвимость делает. Позволяет она сделать RCE как оно обычно подразумевается или действительно банальная — вот тебе код, запусти пожалуйста.
Первая уязвимость — это дыра в песочницах CLR и Silverlight, типичное повышение привилегий. Статус RCE она получила потому что Silverlight-приложения встраиваются в веб-страницы и автоматически запускаются штатным образом.
Если что, всегда можно возразить, что CLR написанна на C++… :)
Автор сам капитан очевидность. По-моему все это давно очевидно всем.

Да нет, не очевидно. Почитайте комментарии — "Самдурак", "вот иди на своем русте и пиши", "а вот в PHP/.Net/Java/… тоже есть баги",… Никакого единодушия по поводу "да, проблема существует" нет.

А что Вы думаете по этому поводу?
Прошу извинить за непопулярное ИМХО: Delphi-7. Конечно, стоило бы доработать, но ИМХО не в том направлении, как это было сделано.

Вот тоже подумал сразу — в Дельфях таких проблем не было! Жаль, что они проиграли гонку...

если про плату (система Delphi платная), то пилили бы GNU Pascal, с безопасностью и тестами. Даже сейчас один из открытых вариантов — FPC/Lazarus уже давно можно использовать для различных задач.
Да и Delphi уже стал частично бесплатный (Community Edition).
Мы на Лазарусе недавно выкатили приложение в продакшн под Линукс. Порядка 600-та тысяч строк, работает, продаётся.
Пока не проиграл. Несмотря на вялотекущие его похороны последние 20 лет цветет и пахнет :)

Делфи принципиально вопрос не решает. Да, с чем-то там получше, но и всё.

Принципиально не решает но то, что хотя бы переполнение буфера на pascal строках не работает, насколько я знаю, уже только одно это существенно улучшить безаопасноть. Строгая типизация помогает надежности. Внешние тулы (Эврикалог) помогает закрыть возможность обращения к разрушенным данным. Много всего, в общем. С SQL инъекциями, конечно, нужно самим бороться. Тут увы.
Да не, про SQL-то понятно. Я скорее про гарантии ссылочной безопасности, многопоточной безопасности, и всего прочего… Отсутствие переполнения буфера это как раз-таки улучшение, но чем больший класс задач мы сможем закрыть (не потеряв продуктивности, как разработчики), тем лучше.
Правильнее было назвать так статью.
У Интернета могут быть серьёзные проблемы из-за несовершенства человеческого интеллекта.

У человечества может быть проблема из-за возможности выстрелить себе в ногу. С/СРР позволяют это сделать чуть легче, чем Rust, но человечество всегда найдет, чем выстрелить себе в ногу.

Проблемы будут всегда. Но их все равно нужно решать.
Я так и не понял — автор пошутил в духе «у нас честные 4 ГБ» или так остроумно расписался в своей некомпетентности?
Ну если уж говорить, какие из ЯП больше всего угрожают интернету, то первую строчку тут займёт вовсе не C++, а Javascript. Именно из-за особенностей этого языка мы имеем тормозящие веб-приложения, монструозные js-движки (с кучей уязвимостей), чтобы хоть как-то облегчить эти тормоза. Но прогресс в эту сторону уже идёт — появляются Typescript (чтобы хоть как-то снизить число ошибок), WebAssembly и Emscripten, чтобы обойти ограничения производительности js.

Нужно мыслить шире. Языки программирования способствуют появлению ошибок. Программирование способствует появлению ошибок. Да что там, исполнение команд способствует появлению ошибок!..

Delphi лишен указанных проблем. Некоторых по умолчанию. Некоторых опционально.
HeartBleed, например, оказавший влияние на 17% защищенных серверов в интернете, был уязвимостью переполнения буфера

Специалист настолько крут, что даже не знает, в чём суть HeartBleed, и что она могла появиться на любом ЯП.
А вы сами то знаете? Не могла она произойти на любом языке.
Если есть язык, где вся выделяемая память по умолчанию обнуляется — да, на таком не могло бы. Такие есть? Подозреваю, что нет, т.к. это был бы дикое и в 99.9% не нужно проседание по производительности. Но HeartBleed'а в таком языке бы не было, это верно.
Внезапно, наверное любой язык со сборщиком мусора так и работает. Go, C#, Java — все они возвращают только инициализированную нулями память. Получить мусорные значения, которые оказались в памяти на момент исполнения, просто невозможно. Судя по всему, Rust тоже это гарантирует, но другими способами — он не даст скомпилировать код, который использует неинициализированные значения. Rust имеет формальное доказательство корректности, т.е. это можно считать эквивалентным обнулению всего и вся в плане безопасности.

Дикому падению производительности здесь взяться неоткуда. Да и в С/С++ любой нормальный программист и так знает, что нужно обнулять выделяемую память. Себе же жизнь проще делаешь.
Интересно, не знал. Ок, тогда согласен, если бы openssl был написан на этих языках, то там HeartBleed'а не было бы.
Дикому падению производительности здесь взяться неоткуда.

Если очищать память, которая и так будет всё проинициализирована, то падение производительности гарантировано.
Да и в С/С++ любой нормальный программист и так знает, что нужно обнулять выделяемую память. Себе же жизнь проще делаешь

Для всех блоков памяти так никто не делает. Зачем мне очищать память, если я тут же буду в неё, к примеру, что-то читать, или хочу проинициализировать её не нулями, а oxff? Да, в в одном из ста тысяч (или миллионов) случаев это и может помочь (как в случае с HeartBleed), но жертвовать ради этого производительностью в остальных случаях?
падение производительности гарантировано

Лучше не фантазировать, а измерить. А до тех пор обнулять все, что только можно.

Зачем мне очищать память, если я тут же буду в неё, к примеру, что-то читать, или хочу проинициализировать её не нулями, а oxff

Инициализируйте чем угодно, но полностью. Нулями, потому что это проще отлаживать потом. Заодно это прекрасно работает со строками, т.к. магическим образом все становится терминированным нулями.

но жертвовать ради этого производительностью в остальных случаях?

Именно так. Эту мантру про производительность везде и всюду надо всеми силами выбивать из С/С++ программистов. Нужно жертвовать считанными наносекундами ради того, что потом может накрыть весь интернет.

Ну а heartbleed это не исправит. Там речь о выходе за границы массива, никакая инициализация это бы не решила. Виноват С и его свобода творить с памятью что вздумается. Суть уязвимости в том, что у нас есть короткий пакет, а внутри него указана большая длина. Отсутствие проверок длины приводит к тому, что код бездумно возвращает содержимое той длины, которое указал пакет. Решили бы эту проблему другие гарантии упомянутых языков, которые не позволят выйти за границы и выкинут рантайм исключение — в Go и Rust вылезет паника, в Java/C# вылезет исключение. В обоих случаях это скорее всего положит весь процесс, т.к. такие вещи не принято ловить.
Как раз необязательно нулями — инициализируют предопределенным значением, но другим, чтобы было видно что ты «не попал».
Тот же GCC пишет 0xdeadbeef в хип, MSC например тоже в стеке прописывает константу. Это в дебаге.
Это понятно. Я про свои переменные и свою память. Там удобнее всего и традиционно годятся нули. Предопределенные значения пишут, чтобы дебажить выходы за границы, это да. Но и работает это обычно только в дебаге, а инициализация нулями это поведение самого кода по-умолчанию.

По-моему свою память тоже удобней каким-нибудь паттерном забивать.
Я натыкался на баги с памятью только один раз (т.к. пишу на rust)), но зато, когда наткнулся, я очень быстро догадался отконвертировать адрес в hex, увидел паттерн 0xDC и благодаря этому быстро нашел багу. А вот паттерн в виде нуля зачастую может оказаться корректно обработанным, и в результате баг не будет выловлен.

В управляемых языках нельзя выделенную память забивать паттерном, потому что язык обычно даёт гарантии, что все ссылочные типы инициализированы значением null, а числовые — нулём.

Для языков типа C/C++ гарантий инициализации нет, потому ради производительности можно вообще не инициализировать, а в отладочной сборке — инициализировать паттерном, что быстрее позволит обнаружить использование неинициализированной переменной.

Интересно, если на rust выделять память под структуру данных, в которых много числовых полей, язык гарантирует, что они инициализированы нулём, или значение не определено? Если потребовать от программиста, чтобы он явно определил все значения структуры в конструкторе, то какая разница, чем инициализирован выделенный блок, если каждый байт будет перезаписан.

Я имел в виду языки с unmanaged heap.
Сразу оговорюсь, что мой опыт в rust невелик.
Зануления не гарантируется. Вместо этого гарантируется, что вы не сможете обратиться к неинициализированной памяти. Поэтому какая разница, как выглядит неинициализированная память, если фиг вам дадут ее почитать)
Для инициализации используется либо соответствующая конструкция StructName {
field:val,

}, либо функция (обычно статическая в классе), делающая то же самое.
Я имел проблемы только потому, что выделял память вручную, через malloc. Но мой кейс безусловно весьма специфичен. Насколько я понимаю, в обычных проектах unsafe-код крайне редок.

Ну, об unsafe речи и нет. Там возвращаемся в замечательный мир C/C++, где гарантия одна — никаких гарантий.
Зависит от того что делаешь. Не так много можно делать в unsafe. Если вызываешь intrinsic, или внешний код, то гарантий мало. А если просто изменяешь статическую переменную (без мютекса), или разименовываешь что-то, то остается многое, точно типы совпадают и лайфтаймы, например.
То есть, в rust мы всё-таки платим за то, чем не пользуемся.

Например, если я хочу выделить память под массив структур, а заполнять данные в них потом, по мере появления данных, мне всё равно придётся заранее инициализировать каждое поле.
Это другой случай.
Например, у меня N записей с логинами (id, login) и отдельно N записей с паролями (id, password). Я хочу создать N структур (id, login, password). Но когда я заполняю (id, login), я вынужден инициализировать и password, хотя в данный момент он неизвестен, и я его гарантированно перезапишу позже.
Хм, а откуда у вас есть гарантии, что айдишники в двух наборах данных соответствуют друг другу?
Допустим, я знаю, что это так. А если не так — то пусть будет UB. Получается, я плачу за безопасность производительностью.
А если не так — то пусть будет UB.

Ох, сколько в этой фразе боли… Вы же понимаете, что UB — это не только про некорректный результат, но и про ханойские башни, и отправку всей вашей базы данных злоумышленникам на личную почту? Потому что компилятор вправе вызывать никогда не вызываемую функцию, и делать прочие странные штуки…

Не понял опять вашей необходимости


fn main() {
    let a = [(1, "Alex"), (2, "Maria")];
    let b = [(1, "Pass1"), (2, "Pass2")];
    let c: Vec<_> = a.iter().merge_join_by(&b, |i, j| i.0.cmp(&j.0)).map(|either| {
        match either {
            Left(_) => panic!("No password"),
            Right(_) => panic!("No login"),
            Both(x, y) => (x.0, x.1, y.1)
        }
    }).collect();
    println!("{:?}", c);
}

Ссылка на плейграунд


Кстати, итераторы заставили меня проверить ситуацию, где нет логина или нет пароля, о которой я изначально не подумал. Любопытно, потому что в случае неинициализированной памяти я вполне мог забыть это проверить и получить в рантайме очередную уязвимость.

merge_join_by — что там под капотом, хеш-таблица, сортировка слиянием?
Там слияние двух упорядоченных последовательностей.

OK, напишите код на С++, а я его перепишу на Rust.

давайте:
std::vector<MyType, MyAllocator> vec;

Или что-то в этом духе:
std::set_new_handler(+[] {
    std::cout << "out of memory" << std::endl;
    std::set_new_handler(nullptr);
});

Пффф, а в чем смысл этого вашего кода, если вы в трех строчках допустили UB?


cat test.cpp:


#include <iostream>

int main() {
    std::cout << "out of memory" << std::endl;
}

(gdb) bt
#0  __GI___libc_malloc (bytes=1024) at malloc.c:2902
#1  0x00007ffff76f81d5 in __GI__IO_file_doallocate (fp=0x7ffff7a50620 <_IO_2_1_stdout_>) at filedoalloc.c:127
#2  0x00007ffff7706594 in __GI__IO_doallocbuf (fp=fp@entry=0x7ffff7a50620 <_IO_2_1_stdout_>) at genops.c:398
#3  0x00007ffff77058f8 in _IO_new_file_overflow (f=0x7ffff7a50620 <_IO_2_1_stdout_>, ch=-1) at fileops.c:820
#4  0x00007ffff770428d in _IO_new_file_xsputn (f=0x7ffff7a50620 <_IO_2_1_stdout_>, data=0x400944, n=13) at fileops.c:1331
#5  0x00007ffff76f97bb in __GI__IO_fwrite (buf=0x400944, size=1, count=13, fp=0x7ffff7a50620 <_IO_2_1_stdout_>) at iofwrite.c:39
#6  0x00007ffff7b63ec6 in std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#7  0x00007ffff7b64237 in std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#8  0x0000000000400859 in main () at test.cpp:4

Читаем http://www.cplusplus.com/reference/new/set_new_handler/ :


The new-handler function may try to make more storage available for a new attempt to allocate the storage. If -and only if- the function succeeds in making more storage available, it may return

Notice that if new_p is a function that does not implement the proper functionality (described above), or if new_p is an invalid pointer, it causes undefined behavior.

Мало того, что вы не аллоцировали дополнительное место, но вы еще своим std::cout запросили новое (которого может и не быть).


Что вы своим кодом-с-неопределенным-поведением хотели сказать?

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

что раст не умеет обрабатывать out of memory. Даже более простой пример:
try {
    a = make_unique<T>(...);
} catch (bad_alloc &e) {
    // ...
}

ему неподвластен. Другими словами, я хотел сказать «нельзя повторить на расте вот такой вот код на с++» в ответ на
OK, напишите код на С++, а я его перепишу на Rust.

Так или иначе оба приведенных мной сниппета содержат поведение, не воспроизводимое на rust, а вы не способны подтвердить своё бахвальство
что раст не умеет обрабатывать out of memory.

Да ну? Тогда что это за странная штука в языке


#[lang = "oom"]
fn oom() -> !;

хм, странно… Что-то видимо умеет.


Так или иначе оба приведенных мной сниппета содержат поведение, не воспроизводимое на rust, а вы не способны подтвердить своё бахвальство

Если вы про то, что в сейф расте нельзя получить UB, а вы в 3 строчках получили, тогда действительно раст это воспроизвести не может.

хм, странно… Что-то видимо умеет.

оно?
Unstable (alloc #27783): this library is unlikely to be stabilized in its current form or name


Если вы про то, что в сейф расте нельзя получить UB, а вы в 3 строчках получили, тогда действительно раст это воспроизвести не может.

вы продолжаете упрямо игнорировать пример с параметризацией контейнера аллокатором и с try/catch обработку out of memory
напишите код на С++, а я его перепишу на Rust
Как насчёт эффективной работы со строками (в стиле сишных char[N])? Сколько в вашей версии будет аллокаций в куче? На C — ни одной.
struct userinfo {
  int id;
  char name[200];
  char pass[200];
};

// function defined in other file
void register_users(const userinfo* users, int count);

int main() {
  userinfo users[10];
  for (int i = 0; i < _countof(users); i++) {
    users[i].id = i;
    snprintf(users[i].name, _countof(users[i].name), "user%d", i);
    strcpy(users[i].pass, "***");
  }
  register_users(users, _countof(users));
  return 0;
}

Если я правильно понимаю, вы просто читаете из IO и присваиваете поля. В расте будет все то же самое. Откуда тут вообще может взяться аллокация в куче? Если только в языках с GC.


В расте пишете "в лоб" чтение с консоли, получается то же самое


use std::mem;
use std::io::{self, Read};

#[derive(Copy, Clone)]
struct UserInfo {
    id: i32,
    name: [u8; 200],
    pass: [u8; 200],
}

fn main() -> io::Result<()> {
    let mut user_infos: [UserInfo; 10] = [unsafe{mem::zeroed()}; 10];

    for i in 0..user_infos.len()  {
        user_infos[i].id = i as i32;
        io::stdin().read(&mut user_infos[i].name)?;
        io::stdin().read(&mut user_infos[i].pass)?;
    }
    register_users(&user_infos);
    Ok(())
}

fn register_users(users: &[UserInfo]) {

}

Хотя более rustish way, и без ансейфа скорее выглядел бы как-то так:


use std::io::{self, Read};

struct UserInfo {
    id: i32,
    name: String,
    pass: String,
}

fn main() -> io::Result<()> {
    let mut user_infos: io::Result<Vec<UserInfo>> = (0..10).map(|i| {
        let mut name = String::with_capacity(200);
        let mut pass = String::with_capacity(200);
        io::stdin().read_to_string(&mut name)?;
        io::stdin().read_to_string(&mut pass)?;
        Ok(UserInfo {
            id: i,
            name,
            pass
        })
    }).collect();

    register_users(&user_infos?);
    Ok(())
}

fn register_users(users: &[UserInfo]) {

}

избавились от ансейфа и возможных проблем с тем, чтобы читать "за" аллоцированную строку (то, что у вас мусор). Да, строки нулл-терминированные, но по смещению все равно можно что-нибудь не то достать. В расте будет ошибка доступа по несуществующему индексу (в отличие от первого варианта, где все так же на соплях). Аллокаций тут будет столько же, сколько в первом случае, но не одним куском, а по мере продвижения по итератору. Однако, не в куче, а на стеке.


Общее потребление памяти будет такое же. А если не собирать вектор, то вообще O(1).

Если я правильно понимаю, вы просто читаете из IO и присваиваете поля
Я не читаю из консоли, а формирую набор структур userinfo по принципу
id = N,
pass = "***",
name = "userN"
, где N — порядковый номер записи.

Печать по формату в строковый буфер (sprintf) есть в расте?

Строки как name:[u8;200] идеоматичны для раста? (для Си — да). Понятно, что специально любой пример можно заоптимизировать до нужной кондиции, но так и на Паскале никто не мешает писать в стиле Си (вместо string — массивы из char), но так же не пишут.

Понял. Простите, я плюсы давно уже в институте забыл :)


Тогда это будет выглядеть так:


use std::io::{self, Read};

struct UserInfo {
    id: i32,
    name: String,
    pass: String,
}

fn main() {
    let mut user_infos: Vec<_> = (0..10).map(|i| {
        UserInfo {
            id: i,
            name: format!("User{}", i),
            pass: "***".into(),
        }
    }).collect();

    register_users(&user_infos);
    Ok(())
}

fn register_users(users: &[UserInfo]) {

}

Печать в буфер есть, но в данном случае проще просто передать выделенное на стеке значение, чтобы не терять лишнюю память. Но если вы хотите, то конечно же раст позволит:


use std::fmt::Write;

struct UserInfo {
    id: i32,
    name: String,
    pass: String,
}

fn main() {
    let mut user_infos: Vec<_> = (0..10).map(|i| {
        let mut name = String::with_capacity(200);
        let mut pass = String::with_capacity(200);
        write!(&mut name, "User{}", i);
        write!(&mut pass, "***");
        UserInfo {
            id: i,
            name,
            pass,
        }
    }).collect();

    register_users(&user_infos);
}

fn register_users(users: &[UserInfo]) {

}

PsyHaSTe, сорян, ты не прав. String относится к коллекциям, которые выделяют память в хипе. Use no_std.

Да, забыл совсем.


Я когда делал parity, я юзал stack string, забыл из какого крейта.




Вспомнил :) heapless

name: format!(«User{}», i),
Значение, коротое возвращает format!, копируется же?
(0..10).map… .collect()
Что возвращает collect()? Вектор, в общем случае произвольной длины?
Значение, коротое возвращает format!, копируется же?

Мувится
Что возвращает collect()? Вектор, в общем случае произвольной длины?

Тут будет аллокация в куче, да. Но ничто не мешает собирать в кастомную коллекцию. Например, есть крейты, которые повторяют функционал стандартных коллекций, но выделяются на стеке. Smallvec, к примеру. Или вот docs.rs/heapless/0.4.0/heapless
Значение, коротое возвращает format!, копируется же?

Мувится
Объявив поле
name: String, вы получаете оверхед в том, что данные не сразу лежат по указанному адресу, а там лежит ссылка на данные. Без потери производительности не выходит.
Да, я уже сказал, что ошибся. Аллокация в данном случае будет. Смотрите пример ниже, там такой ошибки нет.
    let mut users: Vec<UserInfo, U10> = Vec::new();
    for i in 0..10 {
        let user = UserInfo::new(i);
        users.push(user)

И как это всё лежит на стеке, с возможностью вставлять в вектор? Вы дизасемблер смотрели?
heapless название подсказывает что на стеке. Там дженерик. Размер известен во время компиляции, так же как и в C++ варианте.

Возможность вставлять дает счетчик.
И как это всё лежит на стеке, с возможностью вставлять в вектор?

Да. А что вас смущает?


https://japaric.github.io/heapless/src/heapless/vec.rs.html#38-44


Это ж не вектор из std, а вектор из крейта heapless. Есть buff на стеке, len, capacity. Проверяем, что len < capacity, вставляем элемент в buff[len] и инкрементим len. Просто, быстро, безопасно, без смс, без регистрации.


Вы дизасемблер смотрели?

Зачем?

Да, похоже, это то, что нужно. Однако в реализации модуля штук 20 unsafe )))

То есть, оптимально писать на расте можно только так вот.

Один раз пишите stack-allocated вектор на unsafe, потом используете уже спокойно. В контейнарах из std тоже много unsafe наверное под копотом, потому что в конечном итоге вызывается libc::malloc() или что-то в этом роде. Просто оборачивается всё проверками и получаем безопасную либу в итоге.

И, тем не менее, вот пенальти по производительности:
vec.push выполняет копирование UserInfo в буфер вектора.

И ещё вопрос. Эта конструкция:
 let mut name = String::new();
        fmt::write(&mut name, format_args!("user{}", id))
            .expect("Not enough space to format user name");

        UserInfo {
            id,
            name,
            pass: String::from("***"),
}
Разве не создаёт новую строку в хипе?
Разве не создаёт новую строку в хипе?

Читайте внимательно: без std, т.е. даже при опечатке не получится аллоцировать память в хипе.
Эта String тоже из heapless. Так как UserInfo::name: String<U200>, а в конструкторе мы инициализируем поле UserInfo::name локальной переменной name, то Rust выводит тип локальной переменной как String<U200>, поэтому String::new() — это String::<U200>::new().


И все равно с no_std у вас не получится достучаться до std::string без кастомных аллокаторов.


И, тем не менее, вот пенальти по производительности

Или да, или нет. Зависит от компилятора, как он оптимизирует.

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

Поэтому и надо смотреть код, а не сразу говорить «Зачем?» )))

Ну теперь уже ваша очередь опровергнуть мои слова) Какие ваши доказательства? =))

Какие ваши доказательства? ))
Это можно устроить: play.rust-lang.org/?version=stable&mode=release&edition=2018&gist=7f1f40667ddb00de9605341f141d917d

heapless vector пишет элементы в свой буфер через std::ptr::write. В примере создание двух объектов, и копирование одного в другой, с использованием последнего. В ожидаемой оптимизации копирования не должно быть, а использоваться должен первый объект (или сразу запись во второй объект данных от первого объекта). Но копирование есть, это строки
	movaps	144(%rsp), %xmm0
	movaps	160(%rsp), %xmm1
	movaps	176(%rsp), %xmm2
	movaps	%xmm2, 64(%rsp)
	movaps	%xmm1, 48(%rsp)
	movaps	%xmm0, 32(%rsp)
play.rust-lang.org/?version=stable&mode=release&edition=2018&gist=7f1f40667ddb00de9605341f141d917d

Указанный пример использует стандартные String и Vec, которые хранят свои данные в хипе, поэтому их логика гораздо сложнее. Не сомневаюсь, что предоставленный вами листинг будет аналогичен и в C++ с его std::vector и std::string.


Будьте добры предоставить простынку asm кода для heapless.

playground не подключает внешние крейты.

Ну извините. Ручками, локально =) Не забудьте установить rustc 1.32.0-nightly и собирать cargo build --release.

Аааа! Сектанты! Обращают в свою веру!

Вот так оно и начинается… :)

во-первых, зря сомневаетесь. Вам стоит поиграться с godbolt’ом для rust/c++. Во-вторых, размещение объектов на стеке не гарантирует более высокую производительность в сравнении с кучей. В целом, преждевременные оптимизации в ущерб читаемости чаще вредят
Интересно, если на rust выделять память под структуру данных, в которых много числовых полей, язык гарантирует, что они инициализированы нулём, или значение не определено?

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

Интересно, если на rust выделять память под структуру данных, в которых много числовых полей, язык гарантирует, что они инициализированы нулём, или значение не определено? Если потребовать от программиста, чтобы он явно определил все значения структуры в конструкторе, то какая разница, чем инициализирован выделенный блок, если каждый байт будет перезаписан.

В сейф расте вы не сможеет создать структур и не проинициализировать.


В ансейф расте есть mem::unitialized() и mem::zeroed(), которые делают именно то, что вы от них ожидаете.

Если очистка памяти относится к openssl, то, учитывая качество его кода (пришлось сталкиваться), возможно и имеет смысл. Но в общем случае, на мой взгляд, это всё-таки оверкилл.
Ну а heartbleed это не исправит. Там речь о выходе за границы массива, никакая инициализация это бы не решила. Виноват С и его свобода творить с памятью что вздумается. Суть уязвимости в том, что у нас есть короткий пакет, а внутри него указана большая длина. Отсутствие проверок длины приводит к тому, что код бездумно возвращает содержимое той длины, которое указал пакет.

Если посмотреть коммит, где heartbleed был исправлен, то там видно, что выделялся буфер бОльшего, чем нужно, размера, потом в него читался payload (то, что реально нужно было отправить назад, небольшого размера) и обратно отправлялся весь этот большой буфер. Если бы он обнулялся после выделения, то уязвимости бы не было (разве что излишнее выделение памяти и лишняя пересылка данных).
Нет, не поможет. Вот уязвимый код github.com/openssl/openssl/blob/bd6941cfaa31ee8a3f8661cb98227a5cbcc0f9f3/ssl/d1_both.c

Далее по строкам:
1457 — payload равно длине, которую прислали извне
1458 — в pl кладем указатель на входящий пакет, сдвинутый на 3 байта вперед
1474 — выделяем память столько, сколько сказано в пакете, т.е. payload
1480 — копируем туда содержимое pl той длины, что в payload. Тут то и дыра — payload мы не провели, что оно не превышает реальный размер пришедшего пакета (читай pl), а значит выходим за границы pl и читаем чужую память, где может оказаться что угодно.

Ниодин безопасный язык такое не позволит сделать, вылетит рантайм исключение. В том числе rust.
Ок, согласен. Плохо прочитал описание и не до конца понял, в чём была ошибка. Да, и обнуление памяти тут не поможет, поэтому бессмысленно.
Нет. Нет и нет.
У вас тут считанные наносекунды, там считанные наносекунды, здесь еще немного, здесь «на всякий случай» и вот уже Опера кушает гигабайты ОЗУ и рендерит страничку несколько секунд.

«Весь интернет» это не весь мир софта. И оттого что ктото лажанул при написании очень популярного софта тащить лишние вещи…

Виноват не «Си», а кривые руки програмиста.
Виноват не «Си», а кривые руки програмиста.

Ох уж эта мантра про программистов.


А можете мне ради интереса показать хоть одного настоящего программиста? Ну такого, который не лажает в написании популярного софта. Линус там какой-нибудь, или Столлман. Может, Керниган? Я просто вот всегда хотел увидеть того, кого называют "настоящим программистом". Потому что вокруг одни ненастоящие, видимо...

Понимаете, не всегда безопасность кода является определющей характеристикой. Есть еще такая вешь как производительность.
И пока падение производительности на обеспечение безопасности будет не нулевым — будут жить низкоуровневые языки типа С/С++.
У меня сейчас задержка в пару миллисекунд на алокацию памяти — критична, если я еще все эти гигабайты буду занулять где ни надо.

А есть еще всякие технологии ZeroCopy разные DPDK.
Вам критична безопасность? ОК берем и пишем на Расте… А да, напомните компилятoр Rust на каком языке написан? Вы уверены что там «уязвимостей» нет? а то вон OpenSSL тоже использовали.

Компилятор написан на расте, но в низу там llvm на C++.

C++ быстр, если соблюдать некоторые правила. Так же и раст может быть таким же быстрым (оставаясь безопасным), если соблюдать правила.
Стоп… Если соблюдать правила то и С++ будет безопасным.

На самом деле чтобы не говорили — я знаю кучу ОС написаных на плюсах, но ниодной написаной на Расте. Да и браузер только один… вроде.
На самом деле чтобы не говорили — я знаю кучу ОС написаных на плюсах, но ниодной написаной на Расте.
Выбирайте: wiki.osdev.org/Rust

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

Безопасный по умолчанию и быстрый, когда профайлер показал что нужно оптимизировать. Медленный код видно сразу, на тестах. Уязвимости не видно сразу и они могут нанести вред до обнаружения.
Понимаете, не всегда безопасность кода является определющей характеристикой. Есть еще такая вешь как производительность.

И? Почему не может быть быстрого безопасного кода? Посмотрите на бенчмарки раста, обычно он +-1% от сишного кода. Вон, берем бенчмарк, раст на первых двух местах. Несмотря на «зануление где ни надо» (кстати, где именно? Раст нигде ничего не зануляет, потому что ему это не нужно. В отличие кстати от тех же плюсов, где как говорили комментаторы выше, зануляют память просто для удобства дебага в последующем) и прочее.

А есть еще всякие технологии ZeroCopy разные DPDK.

Как раз в расте это реальнее, потому что там вы не копируете, где не надо. Процитирую статью, которую я уже линковал выше:

And this is one place Rust really shines. It lets you do optimizations which you wouldn’t dream of doing in C++. In fact, while the C++ way of looking at this problem would probably be to just clone and move on, most Rust programmers would think of using slices as the default, and not even consider it an “optimization”. And again, this wasn’t with much cognitive overhead; I could just follow the compiler and it fixed everything for me.

(с) link

А да, напомните компилятoр Rust на каком языке написан?

На расте, а что?

а то вон OpenSSL тоже использовали.

Это тут при чем?
Если очищать память, которая и так будет всё проинициализирована, то падение производительности гарантировано.
Сейчас у процессоров много ядер, и отдельный фоновый низкоприоритетный поток занимается обнулением, поэтому влияние незначительно.

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

Можно же хорошо написать! Односвязный lock-free список для организации списков страниц на очистку и очищенных страниц, обнулять записью мимо кеша (есть такие инструкции в x86).
Отлично и получить некогерентный кеш на разных ядрах?
Я думаю, эта инструкция инвалидирует изменяемую строку на всех ядрах. Дальше вы скажете — «отлично, и выбить эту строку из кешей?». Но ведь страницы из очереди страниц на очистку и не должны занимать кеш.

Наверно можно написать, но остаётся много открытых вопросов и компромисов. Например, если это фоновый процесс, то значит у нас есть какая-то задержка на использование памяти. Есть какие-то приоритеты исполнения, канал обмена данными с памятью тоже не резиновый и при большом числе ядер в системе может оказываться узким местом.
И главный вопрос в любом случае сведётся к цене, и ответ однозначно будет не "бесплатно". Но так же пока никуда не делись системы с одним ядром и с малым количеством памяти.
Но, если можно дешевле, а Rust показывает, что можно, то зачем платить больше? Но для этого поддержка такого уровня контроля должна быть на уровне языка и придётся чем-то жертвовать — например, дополнительно декларировать зависимости памяти в виде "времён жизни" (или ещё как-то). Многие, как оказалось, к этому не готовы, это "сложно", что при этом не мешает утверждать, что они способны всё то же самое удерживать в голове. Этот самообман, увы, мешает многим принять новую концепцию, которая вполне возможно прижилась бы и в других языках, несмотря на "тяжёлое наследие".

Вот поэтому сейчас куча софта работает как бог на душу положит и какой нибудь тупенький браузер расходует тьму ресурсов: «сейчас у процессоров много ядер».

С++ достаточно низкоуровневый язык, а уж С и подавно. Ненадо в язык тащить какие то дополнительные действия, только потому, что какой то программер в критичном месте забыл чтото обнулить.

То есть обнулять память перед освобождением, как сейчас в том же openssl всюду делается — это норма, а после инициализации — ужаc-ужас и падение производительности? :-)

Конкретно для openssl — возможно, обнуление всей выделяемой памяти и имеет смысл. Но заметьте, даже после HeartBleed так не стали делать, видимо на то были причины. Я же понял это как обнуление вообще всей памяти, во всех приложениях на C/C++, и это я всё-таки считаю оверкиллом.
Зачем всей. Каждый malloc заменить на calloc, каждую переменную при создании чем-то заполнять конкретным и уже мир станет чуточку лучше.
Напоминает восторженные отзывы некоторых программистов (80% отдела) с текущего места работы, когда какое-то время назад переходили на перспективный C# с богомзабытого С++, «подверженного трудноуловимым ошибкам». Там правда потом со временем выяснилось, что проблема-таки не совсем в языке, но это уже совсем другая история.

Я тут недавно услышал такое замечательное мнение: "Почему все с C переходят на C++? — потому что найти хороших разработчиков на С почти нереально" (речь шла про автоматику (B&R Automation Studio) и эмбедед).
Та же самая история и с "Почему топят против C++?" — не найти столько разработчиков: намного проще выучиться на php/js/python etc. и писать код даже не подозревая, что происходит на уровне железа. Однако, вопреки утверждению в статье вот такой вот подход (язык не позволит сделать мне ошибку) как раз и приводит к уязвимости, т.к. занижает требования к квалификации разработчиков и, как следствие, приводит к ошибкам и уязвимости меньшей сложности, чем у разработчиков высокого класса на том же С. (Согласитесь, что эксплуатация SQL инъекций несколько проще, чем переполнение стека после дождя в четверг?)

UFO just landed and posted this here
автор оригинальной статьи работает в Mozilla. Казалось бы, при чем тут Rust?

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

Комменты про Rust у статье (да и сама статья) это дичь какая-то, каким бы хорошим языком он не был, складывается стойкое впечатление, что его комьюнити это какая-то упоротая секта. Что-то вообще отбивает любое желание иметь дело с Rust.

А можно подробнее? Раст вполне критикуют, на соответствующих ресурсах и темах. Просто возможно на фоне общего недовольства языков он выделяется тем, что им менее недовольны. Stackoverflow survey это подтверждает.

UFO just landed and posted this here

Вот уж не обессудьте, но судя по комментариям к этой статье, подобное описание поведения значительно больше подходит к некоторым сторонникам С++. Безапелляционные заявления "С++ божественен, проблем вообще нет, их выдумали недоброжелатели, Rust/Swift/___(нужное вписать) — не нужен". Не это ли описанный выше фанатизм?

UFO just landed and posted this here
Думаю, это нормальный процесс. Изначально раст задумывался как better C++ с лозунгом «Nothing new». Очень любопытный доклад, где человек как раз размышлял, что он хочет починить. Наверное все постепенно к этому приходят, сначала делают свои обертки над типами, потом какой-нибудь фреймворк, потом расширение языка через какой-нибудь препроцессор, а потом решают, что «хватит это терпеть» и запиливают полноценный язык.

Поэтому логично, что в статьи про проблемы плюсов приходят набегатели, и начинают рассказывать, как эти проблемы решаются где-то еще. Что про них сказать — они есть везде :) В статье про C# прибегают котлинисты и скалисты, а те отвечают им в обратных статьях. С другой стороны, они все вместе набегают в статьи про Java, как в приснопамятной недавней про плохой котлин.

Прекрасно понимаю, что избыток таких набегателей вызывает негатив, но к сожалению, не знаю, чем помочь. Разве что рассказать, что вы не одиноки, и статьи про недостатки почти любого языка вызывают людей, готовых рассказать, как они это чинят. Нужно скорее понять, что люди не выпендриваются, а правда хотят помочь. Они вспоминают, как сами мучились с такими проблемами, и пытаются помочь, как могут. Не всегда это получается удачно. Но относитесь к этому более открыто, люди правда хотят, чтобы вам ваша работа нравилась еще больше, чем сейчас.
UFO just landed and posted this here
«большинство программных проектов, даже самых важных для безопасности Интернета, не являются новыми. Они были запущены десять лет назад, если не больше».

В С++11 был сделан большой шаг для борьбы с утечками, поэтому, пенять на плюсы ссылаясь на стандарт выпущенный в 98-м мягко говоря не корректно.

Утечки памяти (и других ресурсов) — это немного другая проблема, не касающаяся memory safety как таковой.

Непонятно при чем тут язык программирования как таковой? Языки создаются для разных средств и задач. А так на Бейсике нет работы с памятью и запускается в песочнице интерпретаторе. Давайте все кодить на бейсике!

Да язык С/С++ сложный и становится все сложнее. А значит шансов выстрелить себе в ногу больше чем у других языков. И? Это всего лишь один из языков. Не нравится / не подходит — выбирайте другой… А так с/с++ уж с восьмидесятых годов как умирает да все не помрет никак. Не дождетесь!!!

Помимо гарантий которую даёт borrow checker, ещё например в раст удобные и безопасные sum типы. Сколько легаси до сих пор довольствуются union+enum. А нормальный variant только в C++17, но там синтаксис стрёмный в стиле плюсов. А плюсовая система инклюдов вместо нормальных модулей, ждать C++20, а пока продолжать оборачивать в #ifdef? Кроме того макросы в расте более читабельны и меньше шансов выстрелить в ногу, в частности не надо оборачивать все в do {} while false; Можно ещё вспомнить Optional который надо раскрывать явно, вместо сравнения с nullptr в сях про которое можно забыть.
Вроде основываясь на всех набитых шишках растоманы убрали большинство граблей.

пока продолжать оборачивать в #ifdef?

можно #pragma once, но я не уверен, что это широкораспространено и хотя бы не compiler-specific
Я про это же ;): что это не факт, что «широко распространено» и поддерживается другими компиляторами ;)
Поддержу статью в том что:
1. Все люди ошибаются, код даже после ревью, юнит и Q&A тестов может содержать уязвимости и ошибки.
2. Ревью, юнит и Q&A тесты тоже делаются людьми, а они (смотри пункт 1) тоже могут ошибиться

Пока на новых (более безопасных) языках не воздвигнут подобное тому, что есть на С, С++ — особого желания переходить на них не возникнет

Articles