露出した Unsafe Rust
// 著作権 2026 Google LLC // SPDX-License-Identifier: Apache-2.0 pub fn copy(dest: &mut [u8], source: *const u8) { let source = { let mut len = 0; let mut end = source; while unsafe { *end != 0 } { len += 1; end = unsafe { end.add(1) }; } unsafe { std::slice::from_raw_parts(source, len + 1) } }; for (dest, src) in dest.iter_mut().zip(source) { *dest = *src; } } fn main() { let a = [114, 117, 115, 116].as_ptr(); let b = &mut [82, 85, 83, 84, 0]; println!("{}", String::from_utf8_lossy(b)); copy(b, a); println!("{}", String::from_utf8_lossy(b)); }
ある場所から別の場所へバイトをコピーするという機能自体は同じままです。
「ただし、スライスを手動で作成する必要があります。そのためには、まず データの終端を見つける必要があります。」
「今回はテキストを扱っているので、C の慣習であるヌル終端 文字列を使います。」
コードをコンパイルしてください。出力が同じままであることを確認してください。
「健全でない関数でも、入力によっては正しく動作することがあります。テストが 通るからといって、その関数が健全であるとは限りません。」
「何か問題点に気づく人はいますか?」
- 可読性: コードをすばやく見て把握しにくい
sourceポインタが null かもしれないsourceポインタがダングリングしているかもしれない。つまり、解放済みまたは未初期化の メモリを指している可能性があるsourceがヌル終端されていないかもしれない
「関数シグネチャを変更できないと仮定した場合、これらの問題に対処するために コードへどのような改善を加えられるでしょうか?」
- null ポインタ: null チェックを追加し、早期リターンする (
if source.is_null() { return; }) - 可読性: 「最初の null バイトを見つける」処理を自前で実装するのではなく、 十分にテストされたライブラリを使う
「ただし、一部の安全要件は防御的にチェックすることが不可能です。 たとえば:」
- ダングリングポインタ
- ヌル終端バイトが存在しないこと
「この関数をどのように健全にできるでしょうか?」
- 次のいずれか
source入力引数の型を、長さが既知のものに変更する。つまり、前の例のように スライスを使う。
- または
- 関数を unsafe としてマークする
- 安全性の事前条件を文書化する