Считать CVE у Rust и C++ — ловушка: один пример с curl объясняет почему
Передай NULL в функцию на C, получи segfault — и это «неправильное использование», не CVE. Сделай то же самое в безопасном Rust — и баг в памяти автоматически становится дырой в библиотеке. Статья показывает, как именно CVE-счётчики вводят в заблуждение.
Тезис автора: если функция на Rust не помечена unsafe, её нельзя использовать неправильно в смысле памяти — значит, любой баг там это дыра в самой библиотеке. В C и C++ ответственность лежит на вызывающем коде, и ошибка того же класса в CVE не попадает.
Тред разошёлся жёстко. Одни: CVE-счётчики настолько бесполезны, что любые рассуждения о них — повод игнорировать оратора. Другие, со ссылкой на Страуструпа: большинство таких багов это C-стиль в C++, а современный C++ с надёжными библиотеками закрывает разрыв.
Аргумент: кто отвечает за ошибку
В статье How memory safety CVEs differ between Rust and C/C++ автор доказывает: сравнивать сырые счётчики CVE по языкам бессмысленно, потому что два сообщества проводят границу ответственности в разных местах. Его рабочий пример: curl_getenv(NULL) на C падает с segfault, но curl-CVE из этого не возникает — это «неправильное использование», вина вызывающего кода. В Rust тот же баг квалифицируется иначе. Как он сам пишет:
«Если вызываемая функция не помечена
unsafe, ответ однозначен: использовать её неправильно невозможно.»
Поэтому в безопасном Rust баг в памяти означает дыру в самой библиотеке и получает CVE; в C/C++ идентичный просчёт классифицируется как ошибка пользователя и в статистику не попадает. Один баг — два разных бухгалтерских документа.
«Как только кто-то начинает считать CVE — я перестаю слушать»
Громче всего в треде поддержали именно мета-тезис.
«Моё правило: как только кто-то начинает сравнивать или обсуждать количество CVE, я просто игнорирую всё, что он говорит дальше. Сложно придумать более бесполезную метрику.» — комментатор о самой метрике
Однако и сам тезис автора получил критику. Один читатель указал, что аргумент бьёт по Rust: если любая несоответствие в безопасности типов считается уязвимостью, неожиданный panic! из библиотеки можно оформить как DoS-баг — «невозможно определить в изоляции». Контрибьютор MediaWiki провёл границу чётче: функция на Rust, принимающая Option, «по сути объявляет, что умеет обрабатывать None» — это не то же самое, что передать null-указатель в C-функцию и ждать краша.
Призрак Страуструпа входит в дискуссию
Сторона C++ пришла с весомой цитатой. Один читатель пересказал недавнее интервью Бьярне Страуструпа: проблемы с безопасностью памяти «почти все» относятся к коду на C или к C-стилю в C++, который игнорирует современный язык, а надёжные библиотеки закрывают большую часть оставшегося. Другие добавили оговорки к Rust: он меняет баги с памятью на риски цепочки поставок, а unsafe — не единственная дверь к UB: стандартная библиотека, зависимости и дыры в корректности типов тоже в счёт. Читатель с наклонностью к статистике попытался соразмерить ставки: на баги с памятью приходится небольшая доля уязвимостей в обычном коде, и лишь часть из них — класс use-after-free, который ловит borrow checker.
Тезис выживает в споре
Даже защитники C++ в большинстве признали узкий вывод: CVE-счётчики сравнивают две разные системы учёта, а не два уровня безопасности. Rust переносит контракт в систему типов, поэтому нарушения видны как баги библиотеки; C/C++ оставляют контракт вызывающему, поэтому нарушения видны как ошибка пользователя или вовсе не видны. Число, которое можно нагуглить, измеряет то, как каждое сообщество ведёт документацию. Рядом стоит реальный пример: движок браузера сообщил, что парсер HTML на Rust работает на 10% быстрее заменённого C++.
Получайте такие разборы каждый день
Главные истории Hacker News — на email, в Telegram или RSS.
OpenRouter Fusion опрашивает панель моделей, судья выбирает ответ — в 7 раз медленнее и в 4 дороже
Fusion отправляет ваш промпт нескольким моделям одновременно, затем модель-судья синтезирует один ответ. На исследовательском бенчмарке — хорошие результаты. Разработчики в треде, уже пробовавшие то же самое, объясняют, почему судья по большей части вознаграждает сам себя.