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 関数を使う場合は、その効果を示すベンチマークを 必ず追加してください。