一般的な安全性の前提条件

  • エイリアシングと可変性
  • アラインメント
  • 配列アクセスが境界内であること
  • 初期化
  • ライフタイム
  • ポインタの来歴
  • 妥当性
  • メモリ

各前提条件の説明にあまり時間をかけすぎないでください。コースの中で 詳細を見ていくことになります。意図は、そのような前提条件が いくつもあることを示すことです。

「不完全なリストですが、考え始めるための主要な安全性の前提条件を いくつか挙げています。」

  • 妥当性。値は、それが表す型にとって妥当な値でなければなりません。Rust の 参照は null であってはなりません。unsafe でそれを作成すると、
  • アラインメント。値への参照は適切にアラインされていなければならず、これは
  • エイリアシング。すべての Rust コードは Rust の借用規則を守らなければなりません。ポインタから 可変参照 (&mut T) を手動で作成している場合は、 作成できるのは 1 つだけです
  • 初期化。Rust の型のすべてのインスタンスは完全に初期化されていなければなりません。 生メモリから値を作成するには、書き込んであることを確認する必要があり
  • ポインタの来歴。ポインタの起源は重要です。usize を 生ポインタにキャストすることは、もはや許可されていません。
  • ライフタイム。参照は、その参照先より長生きしてはいけません。

一見した以上に微妙な条件もあります。

「境界内の配列アクセス」を考えてみましょう。メモリ位置から読み取ること、すなわち デリファレンスは、プログラムを壊すために必須ではありません。境界外の 参照を作成した時点で、すでにコンパイラの前提が破られ、不安定な 挙動につながります。

Rust は LLVM に、その getelementptr inbounds の前提を使うよう伝えます。その前提は コンパイラ内の後続の最適化パスを誤った動作に導きます(境界外の メモリアクセスは起こりえないためです)。

任意: 以下のコードが表示される the playground を開いてください。これは 本質的には Rust 構文で書かれた C 関数で、配列から要素を取得するものだと 説明してください。Show LLVM IR ボタンで LLVM IR を生成します。次を 強調表示してください。 getelementptr inbounds i32, ptr %array, i64 %offset.

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

#[unsafe(no_mangle)]
pub unsafe fn get(array: *const i32, offset: isize) -> i32 {
    unsafe { *array.offset(offset) }
}

期待される出力(強調表示する行は %_3 で始まります):

define noundef i32 @get(ptr noundef readonly captures(none) %array, i64 noundef %offset) unnamed_addr #0 {
start:
  %_3 = getelementptr inbounds i32, ptr %array, i64 %offset
  %_0 = load i32, ptr %_3, align 4, !noundef !3
  ret i32 %_0
}

境界: デリファレンスしなくても、LLVM の inbounds の前提により、境界外のポインタ(「末尾の 1 つ先」ルールを超えるもの)を 作成することは UB になると、あなたは正しく指摘しました。