unsafe 関数の呼び出し

安全性要件を守らないと、メモリ安全性が損なわれます!

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

#[derive(Debug)]
#[repr(C)]
struct KeyPair {
    pk: [u16; 4], // 8 バイト
    sk: [u16; 4], // 8 バイト
}

const PK_BYTE_LEN: usize = 8;

fn log_public_key(pk_ptr: *const u16) {
    let pk: &[u16] = unsafe { std::slice::from_raw_parts(pk_ptr, PK_BYTE_LEN) };
    println!("{pk:?}");
}

fn main() {
    let key_pair = KeyPair { pk: [1, 2, 3, 4], sk: [0, 0, 42, 0] };
    log_public_key(key_pair.pk.as_ptr());
}

unsafe ブロックには、必ず安全性コメントを付けてください。そのコメントでは、 コードが実際に安全である理由を説明しなければなりません。この例には安全性コメントがなく、健全ではありません。

要点:

  • slice::from_raw_parts の第 2 引数は、バイト数ではなく 要素数 です! この例は、ある配列の末尾を越えて別の配列にまで読み進めることで、 予期しない挙動が起こることを示しています。
  • これは、そのポインタの導出元となった配列の末尾を越えて 読み取っているため、未定義動作です。
  • log_public_key は unsafe であるべきです。というのも、pk_ptr は未定義動作を避けるために 特定の前提条件を満たしていなければならないからです。未定義動作を引き起こしうる 安全な関数は unsound と呼ばれます。その安全性に関する ドキュメントには何と書くべきでしょうか?
  • 標準ライブラリには低レベルな unsafe 関数が多数含まれています。可能な場合は 安全な代替手段を優先してください!
  • 最適化のために unsafe 関数を使う場合は、その効果を示すベンチマークを 必ず追加してください。