Небезопасный код
Главная сила Rust — в мощных статических гарантиях правильности поведения
программы во время исполнения. Но проверки безопасности очень осторожны: на
самом деле, существуют безопасные программы, правильность которых компилятор
доказать не в силах. Чтобы писать такие программы, нужен способ немного ослабить
ограничения. Для этого в Rust есть ключевое слово unsafe. Код, использующий
unsafe, ограничен меньше, чем обычный код.
Давайте рассмотрим синтаксис, а затем поговорим о семантике. unsafe
используется в четырёх контекстах. Первый — это объявление того, что функция
небезопасна:
unsafe fn beregis_avtomobilya() {
    // страшные вещи
}
Например, все функции, вызываемые через FFI, должны быть помечены как
небезопасные. Другое использование unsafe — это отметка небезопасного блока:
unsafe {
    // страшные вещи
}
Третье — небезопасные типажи:
unsafe trait Scary { }
И четвёртое — реализация (impl) таких типажей:
# unsafe trait Scary { }
unsafe impl Scary for i32 {}
Важно явно выделить код, ошибки в котором могут вызвать большие проблемы. Если программа на Rust падает с "segmentation fault", можете быть уверены — проблема в участке, помеченном как небезопасный.
Что значит "безопасный"?
В контексте Rust "безопасный" значит "не делает ничего небезопасного". Также важно знать, что некоторое поведение скорее всего нежелательно, но явно не считается небезопасным:
- Deadlock'и
 - Утечка памяти или других ресурсов
 - Выход без вызова деструкторов
 - Целочисленное переполнение
 
Rust не может предотвратить все виды проблем в программах. Код с ошибками может и будет написан на Rust. Вышеперечисленные вещи неприятны, но они не считаются именно что небезопасными.
В дополнение к этому, ниже представлен список неопределённого поведения (undefined behavior) в Rust. Избегайте этих вещей, даже когда пишете небезопасный код:
- Гонка данных
 - Разыменование нулевого или висячего указателя
 - Чтение неинициализированной памяти
 - Нарушение правил о совпадении указателей с помощью сырых указателей
 &mut Tи&Tследуют модели LLVM noalias, кроме случаев, когда&TсодержитUnsafeCell<U>. Небезопасный код не должен нарушать эти гарантии совпадения указателей.- Изменение неизменяемого значения или ссылки без использования 
UnsafeCell<U> - Получение неопределённого поведения с помощью intrinsic-операций компилятора:
- Индексация вне границ объекта с помощью 
std::ptr::offset(offsetintrinsic), кроме разрешённого случая "один байт за концом объекта". - Использование 
std::ptr::copy_nonoverlapping_memory(intrinsic-операцииmemcpy32/memcpy64) с пересекающимися буферами 
 - Индексация вне границ объекта с помощью 
 - Неправильные значения примитивных типов, даже в скрытых полях:
- Нулевые или висячие ссылки или упаковки (boxes)
 - Любое значение логического типа, кроме 
false(0) илиtrue(1) - Вариант перечисления, не включённый в его определение
 - Суррогатное значение 
charили значениеchar, превыщающееchar::MAX - Последовательности байт, не являющиеся UTF-8, в 
str 
 - Размотка стека в код на Rust из чужого кода (через границы FFI), или размотка из кода на Rust в чужой код
 
Сверхспособности небезопасного кода
В небезопасном блоке или функции, Rust разрешает три ситуации, которые обычно запрещены. Всего три. Вот они:
- Доступ к или изменение статической изменяемой переменной.
 - Разыменование сырого указателя.
 - Вызов небезопасных функций. Это самая мощная возможность.
 
Это всё. Важно отметить, что unsafe, например, не "выключает проверку
заимствования". Объявление какого-то кода небезопасным не изменяет его
семантику; небезопасность не означает принятие компилятором любого кода. Но она
позволяет писать вещи, которые нарушают некоторые из правил.
Вы также встретите ключевое слово unsafe, когда будете реализовывать интерфейс
к чужому коду не на Rust. Идиоматичным считается написание безопасных обёрток
вокруг небезопасных библиотек.
Давайте поговорим о трёх упомянутых возможностях, доступных в небезопасном коде.
Доступ или изменение static mut
Rust позволяет пользоваться глобальным изменяемым состоянием с помощью static mut. Это может вызвать гонку по данным, и в сущности небезопасно. Подробнее
смотрите раздел о static.
Разыменование сырого указателя
Сырые указатели поддерживают произвольную арифметику указетелей, и могут вызвать целый ряд проблем безопасности памяти и безопасности в целом. В каком-то смысле, возможность разыменовать произвольный указатель — одна из самых опасных вещей, которые вы можете сделать. Подробнее смотрите раздел о сырых указателях.
Вызов небезопасных функций
Эта возможность затрагивает то, откуда можно делать вызов небезопасного кода: небезопасные функции могут вызываться только из небезопасных блоков.
Мощь и полезность этой возможности сложно переоценить. Rust предоставляет некоторые intrinsic-операции компилятора в виде небезопасных функций, а некоторые небезопасные функции обходят проверки безопасности для достижения большей скорости исполнения.
В заключение, повторимся: хотя вы и можете делать в небезопасных участках почти что угодно, это не значит, что стоит это делать. Компилятор будет предполагать выполнение оговоренных инвариантов, так что будьте осторожны!