Небезпечні функції
Виклик небезпечних функцій
Функцію або метод можна позначити як 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);
}
Виклик небезпечних функцій
get_unchecked, як і більшість функцій _unchecked, небезпечна, оскільки може створити UB, якщо діапазон невірний. Функція abs небезпечна з іншої причини: вона є зовнішньою функцією (FFI). Виклик зовнішніх функцій зазвичай є проблемою лише тоді, коли ці функції роблять щось із вказівниками, що може порушити модель пам’яті Rust, але загалом будь-яка функція C може мати невизначену поведінку за довільних обставин.
У цьому прикладі "C" - це ABI; інші ABI також доступні.
Написання небезпечних функцій
Насправді ми не будемо використовувати вказівники для функції swap - це можна безпечно зробити за допомогою посилань.
Зверніть увагу, що небезпечний код дозволяється всередині небезпечної функції без блоку unsafe. Ми можемо заборонити це за допомогою #[deny(unsafe_op_in_unsafe_fn)]. Спробуйте додати його і подивіться, що станеться. Ймовірно, це буде змінено у майбутньому виданні Rust..