Розіменування "сирих" вказівників

Створення вказівників є безпечним, але для їх розіменування потрібно unsafe:

fn main() {
    let mut s = String::from("обережно!");

    let r1 = &raw mut s;
    let r2 = r1 as *const String;

    // БЕЗПЕКА: r1 та r2 були отримані з посилань і тому
    // гарантовано є ненульовими та правильно вирівняними, об'єкти, що лежать в основі
    // посилань, з яких вони були отримані, є дійсними на протязі
    // всього небезпечного блоку, і до них немає доступу ні через
    // посилання, ні одночасно через будь-які інші покажчики.
    unsafe {
        println!("r1 є: {}", *r1);
        *r1 = String::from("ууухооох");
        println!("r2 є: {}", *r2);
    }

    // НЕБЕЗПЕЧНО. НЕ РОБІТЬ ЦЬОГО.
    /*
    let r3: &String = unsafe { &*r1 };
    drop(s);
    println!("r3 is: {}", *r3);
    */
}
This slide should take about 10 minutes.

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

У випадку розіменувань покажчиків це означає, що покажчики мають бути дійсними, тобто:

  • Покажчик має бути ненульовим.
  • Покажчик має бути розіменоваючим (у межах одного виділеного об’єкта).
  • Об’єкт не повинен бути звільнений.
  • Не повинно бути одночасних доступів до того самого розташування.
  • Якщо вказівник було отримано шляхом приведення посилання, базовий об’єкт має бути дійсним, і жодне посилання не може використовуватися для доступу до пам’яті.

У більшості випадків вказівник також має бути правильно вирівняний.

У розділі "НЕ БЕЗПЕЧНО" наведено приклад поширеної помилки UB: *r1 має 'static час життя, тому r3 має тип &'static String, і таким чином переживає s. Створення посилання з покажчика вимагає великої обережності.