Небезпечні функції

Виклик небезпечних функцій

Функцію або метод можна позначити як unsafe, якщо вони мають додаткові передумови, які ви повинні підтримувати, щоб уникнути невизначеної поведінки:

extern "C" {
    fn abs(input: i32) -> i32;
}

fn main() {
    let emojis = "🗻∈🌏";

    // БЕЗПЕКА: Індекси розташовані в правильному порядку в межах 
    // фрагмента рядка та лежать на межах послідовності UTF-8.
    unsafe {
        println!("смайлик: {}", emojis.get_unchecked(0..4));
        println!("смайлик: {}", emojis.get_unchecked(4..7));
        println!("смайлик: {}", emojis.get_unchecked(7..11));
    }

    println!("кількість символів: {}", count_chars(unsafe { emojis.get_unchecked(0..7) }));

    // БЕЗПЕКА: `abs` не працює з покажчиками і не має жодних вимог до
    // безпеки.
    unsafe {
        println!("Абсолютне значення -3 згідно з C: {}", abs(-3));
    }

    // Недотримання вимог кодування UTF-8 порушує безпеку пам’яті!
    // println!("смайлик: {}", unsafe { emojis.get_unchecked(0..3) });
    // println!("кількість символів: {}", count_chars(unsafe {
    // emojis.get_unchecked(0..3) }));
}

fn count_chars(s: &str) -> usize {
    s.chars().count()
}

Написання небезпечних функцій

Ви можете позначити власні функції як unsafe, якщо вони вимагають певних умов, щоб уникнути невизначеної поведінки.

/// Міняє місцями значення, на які вказують задані покажчики.
///
/// # Безпека
///
/// Покажчики повинні бути дійсними і правильно вирівняними.
unsafe fn swap(a: *mut u8, b: *mut u8) {
    let temp = *a;
    *a = *b;
    *b = temp;
}

fn main() {
    let mut a = 42;
    let mut b = 66;

    // БЕЗПЕКА: ...
    unsafe {
        swap(&mut a, &mut b);
    }

    println!("a = {}, b = {}", a, b);
}
This slide should take about 5 minutes.

Виклик небезпечних функцій

get_unchecked, як і більшість функцій _unchecked, небезпечна, оскільки може створити UB, якщо діапазон невірний. Функція abs некоректна з іншої причини: вона є зовнішньою функцією (FFI). Виклик зовнішніх функцій зазвичай є проблемою лише тоді, коли ці функції роблять щось із вказівниками, що може порушити модель пам'яті Rust, але загалом будь-яка функція C може мати невизначену поведінку за довільних обставин.

У цьому прикладі "C" - це ABI; інші ABI також доступні.

Написання небезпечних функцій

Насправді ми не будемо використовувати вказівники для функції swap - це можна безпечно зробити за допомогою посилань.

Зверніть увагу, що небезпечний код дозволяється всередині небезпечної функції без блоку unsafe. Ми можемо заборонити це за допомогою #[deny(unsafe_op_in_unsafe_fn)]. Спробуйте додати його і подивіться, що станеться. Ймовірно, це буде змінено у майбутньому виданні Rust..