Абсолютисты безопасности памяти
- title
- Абсолютисты безопасности памяти
- type
- summary
- summary
- Пётр Сарнацкий о том, что Fil-C и Rust дополняют друг друга, а аргумент "в Rust есть unsafe" несостоятелен
- tags
- memory-safety, rust, zig, c-language, language-design
- sources
- memory-safety-absolutists
- created
- 2026-07-29
- updated
- 2026-09-14
- lang
- ru
- translation_of
- memory-safety-absolutists
- source_updated
- 2026-09-14
- translated
- 2026-09-14
- translator
- lllm/antigravity/gemini-3.7-flash-medium
Пётр Сарнацкий написал это в ответ на то, как изменились споры о безопасности памяти. Абсолютисты из заголовка - это не разработчики на Rust, как можно было бы подумать; это люди, которые теперь утверждают, что Rust нельзя считать безопасным по памяти из-за наличия unsafe.
Исходная ситуация
До недавнего времени расклад для системных языков без GC был простым. Rust отказывается компилировать программы, которые могут нарушить безопасность памяти, соглашаясь с тем, что иногда он будет браковать вполне корректный код, и предлагает unsafe как аварийный выход для таких задач, как разыменование сырых указателей. C и родственные ему языки оставляют безопасность памяти на совести программиста, предлагая разную степень помощи - RAII и умные указатели в C++, defer в zig - но ничего, что могло бы предотвратить нарушение.
Fil-C меняет этот расклад. C и C++, скомпилированные с Fil-C, падают в панику при некорректном обращении к памяти (включая чтение за границами буфера и use-after-free), объединяя GC с InvisiCaps для отслеживания того, к какой памяти указателю разрешён доступ; устройство механизма описано в simplified-model-of-fil-c. Andrew Kelley анонсировал режим компиляции для Zig, вдохновлённый этой идеей. Сарнацкий недвусмысленно даёт понять, что желает проекту успеха, и надеется, что популярные проекты на C и C++ начнут выпускать релизы, скомпилированные с Fil-C.
Тезис, которому он оппонирует
Аргумент, с которым он постоянно сталкивается, звучит так: если бы сторонников Rust действительно заботила безопасность памяти, они бы продвигали Fil-C и отказались от Rust, поскольку Fil-C безопаснее; иначе же их волнует только их собственный новый язык. Автор Fil-C продвигает похожую мысль в Twitter, где регулярно звучит тезис, что Rust - небезопасный по памяти язык, потому что unsafe позволяет обойти его гарантии. Заголовок issue у Kelley содержит то же обвинение в скобках: "introduce an actually memory safe (unlike Rust) compilation mode inspired by Fil-C".
Сарнацкий считает это точно таким же сектантским поведением, в котором обычно обвиняют разработчиков на Rust, только развёрнутым в обратную сторону.
Опровержение в четыре шага
Во-первых, исходная предпосылка подразумевает полную взаимозаменяемость (drop-in replacement), чем Fil-C вовсе не является. Он ABI-несовместим с программами, скомпилированными без него, в ряде случаев может работать в несколько раз медленнее и привносит GC. Ничто из этого не фатально для множества программ: огромное количество софта могло бы работать в несколько раз медленнее без каких-либо заметных последствий, а многим программам не нужна динамическая линковка. Однако проекты, для которых GC и несовместимость ABI категорически неприемлемы, вполне реальны и популярны, и зачастую это именно те задачи, для которых хорошо подходит Rust. Эти две технологии пересекаются совсем не так, как требуется для этого аргумента.
Во-вторых, практические результаты. Сарнацкий оговаривается, что данных о надёжности Rust в реальных условиях пока немного, но статистика Android - самая большая из доступных выборок: около 5 миллионов строк кода на Rust в платформе Android, одна потенциальная уязвимость безопасности памяти, найденная и исправленная до релиза, и расчётная плотность в 0.2 уязвимости на миллион строк. Исторический показатель Google для кода на C и C++ близок к 1000 на MLOC - разница более чем в тысячу раз. У других проектов цифры будут иными, но общая тенденция очевидна.
В-третьих, сама формулировка выбора. Что вы выберете: технологию, предотвращающую 99.9% проблем в 100% программ, или устраняющую 100% проблем в 90% программ? Сарнацкий прямо говорит, что эти числа выдуманы, а суть - в самой постановке вопроса, а не в арифметике. Его ответ в том, что этот выбор ложный: проекты на C, C++ и Zig, готовые пойти на такие компромиссы, должны выпускать бинарники с Fil-C, а остальной софт следует писать на языках, устраняющих большую часть или весь риск иным путём.
В-четвёртых, у гарантий Fil-C тоже есть свои особенности. Те самые 1000 уязвимостей на MLOC никуда не исчезают под Fil-C - они превращаются в падения (crash). Это лучше, чем уязвимость безопасности, но исправлять такое количество аварийных завершений всё равно придётся. И если уж речь зашла о редких сценариях сбоев, справедливо вспомнить, что существовали уязвимости безопасности, возникшие именно из-за возможности злоумышленника уронить программу.
Он также защищает применение Rust там, где подошёл бы язык со сборщиком мусора вроде Golang, споря с абсолютистами, считающими это неприемлемым. За этим стоит наблюдение, что эти две группы программ почти не пересекаются: программам, которые можно было написать на языке с GC, unsafe обычно вообще не нужен, а программам, требующим unsafe, как правило, нельзя было использовать GC. К тому же разработчики, взвешивающие компромиссы, а не слепо следующие правилу, часто обнаруживают, что другие гарантии (в частности, предотвращение гонок данных) перевешивают очень небольшой остаточный риск. Это вторая половина языка, связанная с rust-send-sync, которую подход Fil-C никак не затрагивает.
Финальный аргумент - проверка на последовательность. Если показатель Rust в 0.2 уязвимости на MLOC для вас действительно невыносим, вы должны как минимум столь же громко критиковать тех, кто компилирует YOLO C, C++ и обычный Zig без fil. Он отмечает, что некоторые абсолютисты применяют этот стандарт исключительно к Rust.
Взаимосвязи
Шаг "в Rust есть unsafe, следовательно, Rust небезопасен" - это основа всей аргументации оппонентов, и safety-in-an-unsafe-world служит прямым контраргументом к нему. Позиция Joshua Liebow-Feeser заключается в том, что безопасность памяти даёт не сам Rust, а библиотека, и Rust поставляет из коробки ровно одну такую реализацию; unsafe - это инструмент инкапсуляции доказательства корректности, а не дыра в системе типов. Опыт Netstack3 подтверждает выводы Android, на которые ссылается Сарнацкий: 192 000 строк сетевого кода на Rust, одиннадцать месяцев тестирования на себе (dogfooding) и всего три найденных бага. Ни Сарнацкий, ни Liebow-Feeser не утверждают, что код на Rust невозможно сломать; оба говорят, что значимая величина - это частота поломок, а не теоретическая возможность допустить ошибку в языке.
cobaltc, концептуальная спецификация преемника C, встаёт на сторону Rust: unsafe - это явная локальная граница, и небезопасный код может реализовывать безопасную абстракцию, но не должен нарушать инварианты, гарантируемые безопасным интерфейсом. Концепция ability-guarantee-tradeoff описывает общую суть компромисса Rust: компилятор принимает меньше программ в обмен на гарантии, а unsafe служит способом вернуться к более широкому множеству допустимых программ.