В Rust нашли 11-летнюю ошибку в проверке заимствований (borrow checker)

13 октября 2026 года в репозитории rust-lang/rust появился issue №164250 о бреши в проверке заимствований (borrow checker). Требования к временам жизни структуры, например T: 'static, можно обойти через присваивание в ковариантное поле. В итоге реализация Drop получает ссылку, которая на самом деле не 'static, но предполагает, что она 'static.
Воспроизведение в issue такое. Объявлена структура Q<T: 'static + Send>(Option
Над описанием стоит заметка за подписью lcnr, добавленная, как там сказано, потому что issue разошёлся по сети и собирает много посетителей. В ней говорится, что система типов Rust призвана предотвращать небезопасную работу с памятью, а исправление всех нарушений корректности типов (unsoundness), крупный приоритет Types Team; среди связанных работ названы следующее поколение решателя трейтов, переработка ограничений регионов и Project Zero. Ошибка помечена как P-high и была бы P-critical независимо от того, сталкивались ли с ней на практике; «только P-high» она именно потому, что ей 11 лет: ошибку, которую не нашли за 11 лет, нельзя так уж легко задеть. Кроме того, в заметке сказано, что она, скорее всего, не приводила к небезопасной работе с памятью случайно: хотя вызвать её кажется легко, для эксплуатации нужна намеренно вредоносная реализация Drop.
В обсуждении участники привели другие варианты. Один обходится без 'static: Drop записывает через изменяемую ссылку другую ссылку с более коротким временем жизни, и после выхода из блока программа печатает уже недействительные данные. Другой, по словам комментатора, падает или печатает освобождённую память начиная с версии 1.4. Третий с потоком и задержкой в одну секунду назван «самым простым для понимания». Ещё один комментатор предположил, что унификация типов вообще не проверяет ограничения по временам жизни, и показал пример без присваивания в поле, через приведение типов. Другой участник пишет, что его вариант кода компилируется с версии 1.18.0 (2017) и спрашивает, как это не нашли раньше. Модератор превентивно закрыл обсуждение для всех, кроме участников с правами, чтобы не допустить спама и бесполезных комментариев. У issue метки I-unsound («брешь в корректности, худший вид ошибки»), A-borrow-checker, T-types, A-destructors, A-lifetimes и A-variance; статус открыт, исправление в источнике не названо.
Ключевые факты
- Issue №164250 в rust-lang/rust (13 октября 2026 года): ограничения времён жизни структуры вроде T: 'static обходятся через присваивание в ковариантное поле, и Drop получает не 'static ссылку, считая её 'static.
- Программа из issue компилируется и печатает содержимое уже уничтоженной локальной строки; под AddressSanitizer падает с stack-use-after-scope. Воспроизводится на nightly и стабильных версиях как минимум до 1.85.0.
- Автор заметки lcnr пишет, что ошибке 11 лет, она P-high (и была бы P-critical независимо от встречаемости), а для эксплуатации нужна намеренно вредоносная реализация Drop.
- В комментариях есть другие варианты воспроизведения, включая вариант без 'static и вариант через унификацию типов; про версии 1.18.0 и 1.4 говорят сами комментаторы.
- Исправление и сроки в источнике не указаны, issue открыт, обсуждение ограничено для участников с правами.
Почему это важно
Ошибка бьёт в главное обещание Rust: система типов призвана предотвращать небезопасную работу с памятью, и в заметке к issue это прямо сказано. Метка I-unsound описывает такой класс как брешь в корректности, «худший вид ошибки». Здесь компилятор принимает программу, которая читает уже уничтоженные данные. Отдельно показательно, что брешь пролежала, по словам автора заметки, 11 лет.
Кому это важно
Прежде всего разработчикам компилятора и языка Rust, а также авторам библиотек, чей код опирается на ограничения времён жизни и на корректную работу Drop. Остальным Rust-разработчикам стоит знать о проблеме, но по оценке автора заметки случайно на неё не наткнуться: для эксплуатации нужна намеренно вредоносная реализация Drop.
Как это применить
Готового исправления или обходного пути в источнике нет. Практично следить за issue №164250 и при желании проверить воспроизведение по двум ссылкам Godbolt из описания (с AddressSanitizer и без). Пример кода из issue можно запустить на своей версии компилятора: по описанию, проблема есть на nightly и на стабильных версиях как минимум до 1.85.0.
Можно ли доверять
Источник первичный: это официальный трекер rust-lang/rust, а заметка написана с позиции Types Team. Но оценки вроде «случайно этого не задеть» и «скорее всего, не приводила к небезопасной работе с памятью», суждение автора заметки, а не результат отдельной проверки. Версии 1.18.0 и 1.4 названы комментаторами и в заметке не подтверждены. Кто нашёл ошибку и открыл issue, в источнике не указано.
Риски и подводные камни
Исправление и сроки в источнике не названы, issue остаётся открытым. Комментаторы показали несколько вариантов, в том числе без 'static и через унификацию типов без присваивания в поле, так что проблема может оказаться шире одного примера; это их предположения, не вывод команды. Про использование ошибки в реальном ПО или инциденты в источнике ничего не сказано. Обсуждение закрыто для участников без прав, поэтому разбор причин придётся искать в самом issue и связанных обсуждениях.
«Ошибку такого рода, которую не нашли за последние 11 лет, на самом деле нельзя так уж легко задеть.»
— lcnr, заметка в issue №164250 репозитория rust-lang/rust