Unsafe関数の呼び出し

Unsafe関数の呼び出し

未定義の動作を回避するために満たす必要がある追加の前提条件がある関数またはメソッドは、unsafe とマークできます。

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

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

    // SAFETY: The indices are in the correct order, within the bounds of the
    // string slice, and lie on UTF-8 sequence boundaries.
    unsafe {
        println!("emoji: {}", emojis.get_unchecked(0..4));
        println!("emoji: {}", emojis.get_unchecked(4..7));
        println!("emoji: {}", emojis.get_unchecked(7..11));
    }

    println!("char count: {}", count_chars(unsafe { emojis.get_unchecked(0..7) }));

    // SAFETY: `abs` doesn't deal with pointers and doesn't have any safety
    // requirements.
    unsafe {
        println!("Absolute value of -3 according to C: {}", abs(-3));
    }

    // UTF-8 エンコード要件を満たさない場合、メモリの安全性が損なわれます。
    // println!("emoji: {}", unsafe { emojis.get_unchecked(0..3) });
    // println!("char count: {}", count_chars(unsafe {
    // emojis.get_unchecked(0..3) }));
}

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

Unsafe関数の書き方

未定義の動作を回避するために特定の条件が必要な場合は、独自の関数を unsafe とマークできます。

/// 指定されたポインタが指す値をスワップします。
///
/// # Safety
///
/// ポインタが有効で、適切にアラインされている必要があります。
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;

    // SAFETY: ...
    unsafe {
        swap(&mut a, &mut b);
    }

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

Unsafe関数の呼び出し

get_unchecked, like most _unchecked functions, is unsafe, because it can create UB if the range is incorrect. abs is unsafe for a different reason: it is an external function (FFI). Calling external functions is usually only a problem when those functions do things with pointers which might violate Rust's memory model, but in general any C function might have undefined behaviour under any arbitrary circumstances.

この例の "C" は ABI です(他の ABI も使用できます)。

Unsafe関数の書き方

実際には、swap 関数ではポインタは使用しません。これは参照を使用することで安全に実行できます。

アンセーフな関数内では、アンセーフなコードをunsafeブロックなしに記述することができます。これは #[deny(unsafe_op_in_unsafe_fn)] で禁止できます。追加するとどうなるか見てみましょう。これは、今後の Rust エディションで変更される可能性があります。