Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Разыменование сырых указателей

Создание указателей безопасно, но их разыменование требует unsafe:

// Copyright 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0

fn main() {
    let mut x = 10;

    let p1: *mut i32 = &raw mut x;
    let p2 = p1 as *const i32;

    // SAFETY: p1 и p2 созданы взятием сырых указателей на локальную переменную, поэтому
    // гарантированно не равны null, выровнены и указывают на один объект,
    // выделенный (на стеке).
    //
    // Объект, на который указывают сырые указатели, живёт всё время выполнения функции, поэтому
    // он не освобождается, пока существуют сырые указатели. Через ссылки к нему
    // не обращаются, пока существуют сырые указатели, и из других потоков одновременно к нему тоже не обращаются.
    unsafe {
        dbg!(*p1);
        *p1 = 6;
        // Изменение может корректно наблюдаться через сырой указатель, как в C.
        dbg!(*p2);
    }

    // НЕКОРРЕКТНО. НЕ ДЕЛАЙТЕ ТАК.
    /*
    let r: &i32 = unsafe { &*p1 };
    dbg!(r);
    x = 50;
    dbg!(r); // Объект, лежащий в основе ссылки, был изменён. Это UB.
    */
}
This slide should take about 10 minutes.

Хорошей практикой (и требованием руководства по стилю Rust для Android) является написание комментария к каждому блоку unsafe, объясняющего, как код внутри него удовлетворяет требованиям безопасности выполняемых небезопасных операций.

Для разыменования указателей это означает, что указатели должны быть допустимыми, то есть:

  • Указатель не должен быть null.
  • Указатель должен быть разыменовываемым (в пределах границ одного выделенного объекта).
  • Объект не должен быть освобождён.
  • Не должно быть одновременного доступа к одному и тому же месту.
  • Если указатель получен приведением ссылки, базовый объект должен быть живым, и ни одна ссылка не может использоваться для доступа к памяти.

В большинстве случаев указатель также должен быть правильно выровнен.

Раздел «UNSOUND» показывает пример распространённого вида ошибки UB: наивное взятие ссылки на результат разыменования сырого указателя обходит знание компилятора о том, на какой объект на самом деле указывает ссылка. Поэтому анализатор заимствований не «замораживает» x, и мы можем изменить его, несмотря на существование ссылки на него. Создание ссылки из указателя требует большой осторожности.