Проблема безопасной разработки на С++ возникла не вчера, и она достигла таких размеров, что рекомендации использовать более надежные языки программирования, принимаются на самом высоком уровне.
Но даже несмотря на наличие подобных рекомендаций, планы прекратить использовать С++ и перейти любой другой безопасный язык программирования, часто не выдерживают обычных финансовых расчетов. Ведь если отказаться от С++, то что придется делать с миллионами или даже миллиардами строк кода, которые были написаны за несколько предыдущих десятилетий?
К сожалению, и сам С++ не особо стремится стать более "безопасным". Точнее, подобное стремление плохо сочетается с требования к стандарту языка, которые принимаются комитетом по стандартизации С++. Ведь любой стандарт должен обеспечивать обратную совместимость со всем старым легаси кодом, что автоматически сводит на нет любые попытки внедрения какой либо новой лексики на уровне единого стандарта С++.
И в это ситуации правы те, кто выступает за обязательную поддержку обратной совместимости со старым кодом. Но правы и те, кто считает необходимым добавление новых возможностей для безопасной разработки на С++ хотя бы в новых проектах.
Таким образом, возникают, казалось бы, взаимоисключающие и не разрешимые противоречия:
- Текущее состояние С++ не может гарантировать безопасную разработку на уровне стандартов языка.
- Принятие новых стандартов С++ с изменением лексики для безопасной разработки обязательно нарушат обратную совместимость с существующим легаси кодом.
- Переписывать всю имеющуюся кодовую базу С++ под новую безопасную лексику (если бы такие стандартны были приняты), ничуть не дешевле, чем переписать этот же код на новом модном языке программирования.
Но ключевым моментом в предыдущем абзаце является фраза "казалось бы".
Введение в проблематику
Предположим, что существует методика (концепция, алгоритм или набор библиотек), которые гарантируют безопасную разработку компьютерных программ, например, в части безопасной работы с памятью (не важно на каком языке программирования). Тогда должна существовать её формализация до деталей реализации (к сожалению, например в Rust, приводиться только общее описание концепции с простыми примерами, тогда как полный список всех возможных сценариев и выполнение проверок является черным ящиком внутри компилятора языка).
И это ни в коем случае не критика Rust! Я отлично понимаю, что была проделана громадная работа, а сам язык продолжает постоянно развиваться. Поэтому отсутствие полной формализации правил для безопасной работы с памятью произрастает не от конкретного языка, а из-за недостатка общей универсальной теории, подходящей для всех случаев жизни.
Но речь даже не об этом, а о том, что термин "безопасная разработка" или более конкретно, "безопасная работа с памятью", включает в себя не только какой-то машинный код, а в первую очередь набор лексических правил языка программирования, которые на уровне исходного текста программы не дают программисту писать программы с ошибками. Тогда как компилятор обязан иметь возможность убедиться в корректной реализации методики (концепции) еще на этапе синтаксического анализа исходного текста программы.
И именно этот момент (новые правила лексики) фактически и нарушают обратную совместимость со всем старым легаси кодом С++!
Возможна ли безопасная разработка на С++?
Однако мне кажется, что уже сейчас существующие возможности С++ позволяют разрешить данное противоречие без нарушения обратной совместимости со старым кодом. Для этого всего лишь нужно иметь техническую возможность добавлять в компиляторы дополнительные (пользовательские) проверки, которые и должны реализовывать контроль выполнения правил безопасной разработки еще на этапе компиляции программы.
А так как подобные проверки с высокой долей вероятности не будут выполняться для старого легаси кода, то они обязательно должны быть отключаемыми. И подобная возможность уже давно существует за счет создания пользовательских плагинов для компиляторов!
Я не рассматриваю реализацию дополнительного синтаксического анализа за счет сторонних приложений (статических анализаторов, например, на базе Clang-Tidy), так как любое внешнее по отношению к компилятору решение, всегда будет содержать как минимум один существенный недостаток — необходимость синхронно поддерживать и использовать одни и те же режимы компиляции исходных текстов программ, что для С++ может быть очень не тривиальной задачей с его препроцессором.
Комментарии (12)
Jijiki
12.01.2025 15:33тут смотря что еще понимать под легаси если легаси С то есть моменты (например операторы дальше я пока сам наглядно не сталкивался)
Скрытый текст
vec2 t(vec2 x) { return x-1*2+100;//не заработает в С }
тут как бы напрашивается момент где начинается граница ошибок
если стандарты языка С++, то вроде просто надо выбрать стандарт и в него компилировать (но я когда писал компилировал старый код в 23 стандарт и пользовался не всеми преимуществами стандарта - писал на шаблонах + наследование, ну стандартный С++ как мне кажется, с доступными штуками - там вроде всё тривиально, а вот по статье по ссылке где пишут что С++ не безопасен я смотрел ее и никогда не думал так писать - двоякое ощущение), мне лично показалось когда видел ту статью что так можно где угодно ошибки найти
насчет плагинов - ведь кланг в его документации даёт понять что разработчик может добавлять свои плагины, и есть свободно распространяемые плагины который вы привели в пример
Windows.h линкуется собирается с 23 стандартом и вы даже brush сможете вызвать и воспользоваться и другими вызовами, где легаси, где опасность, в чем там проблемы я пока не понял
можно сравнить с ценой вызова на Сшарп и Ява (мне думается надо признать что есть разные языки с разными парадигмами, а так можно бесконечно обижаться на разные подходы)
kozlyuk
12.01.2025 15:33Предложенный подход в пределе означает реализовать borrow checker для C++ (имеется в виду анализатор схожей мощности). Вряд ли много компаний-пользователей компилятора способны написать такое сложное расширение (это мягко говоря). Если оно будет написано, скорее всего, удобнее будет интегрировать эти наработки в апстрим, чтобы упростить поддержку.
Jijiki
12.01.2025 15:33а какой конкретный пример есть на этот счет? может сервер - web не сможет работать с обращениями и будет что сбой? или что произойдёт, что конкретно в race condition плохого у С++?
может легаси не соберётся в чем там проблема можно пример?
у меня есть пример возможно плохой
thread = SDL_CreateThread(TestThread, "TestThread", (void *)NULL); SDL_WaitThread(thread, &threadReturnValue);
я запускал 2-3 окна игроки рендерились
это код дедикейтед сервера
kovserg
12.01.2025 15:33Всё упирается в то что все постоянно пытаются выстроить жесткую систему. А жесткие системы они всегда хрупкие. И чем жестче вы будете контроль тем "веселее" и масштабнее будут разрушения. А если еще учесть что язык позволяет использовать противоречащую здравому смыслу логику для оптимизаций, то язык может и будет безопасным, но всегда будет способен неприятно удивить.
Explorus
12.01.2025 15:33не уверен насчет совместимости, но некоторые предложения от Саттера уже были
https://isocpp.org/files/papers/P3081R0.pdfrsashka Автор
12.01.2025 15:33Это решает одну и туже задачу с помощью одних и тех же инструментов (аннтоации).
Но Саттер настаивает на добавления новых аннотаций в стандарт, тогда как мне кажется, что уже С++20 возможностей достаточно для реализации предложенной концепции.
lieff
Вы про https://safecpp.org/draft.html ?
rsashka Автор
Нет, это не С++. Но данный проект очень хорошо демонстрирует описанную в статье проблему со старым легаси кодом, когда начинают дорабатывать синтаксис языка, и тем самым нарушают обратную совместимость.
lieff
В RFC пишут об обратном: "The proposed Safe C++ should be a pure subset of ISO C++ except few ignorable pragma and attributes. So that other compilers which don’t support the extension can compile the codes accepted by Safe C++."
https://discourse.llvm.org/t/rfc-a-clangir-based-safe-c/83245
Я правда тоже пока не gонял как они собираются делать совместимость в сложных примерах а не приведенных демках. Но вроде как это объявлено целью.
rsashka Автор
В тех примерах, которые есть на сайте проекта, обратной совместимости не наблюдается. Может быть у них что-то есть в планах, но по факту пока этого не видно.
lieff
Совместимость есть в примерах из RFC (вторая ссылка), как это объединять с первой будут мне тоже не понятно, о чем тоже написал.