- Verusやframa-cと同等の機能を持つ検証機を作成する
- 事前条件
- 事後条件
- ループ普遍条件
- 検証対象となるRustのソースコードファイルをコマンドライン引数として受け取る。
- rustc_driverのrun_compilerを呼び出し、Callbackを登録してコンパイル処理を開始する。
- コンパイラの解析後、after_analysisコールバック内で型情報コンテキスト(TyCtxt)を取得する。
- TyCtxtを用いて、プログラムのエントリーポイントであるmain関数のDefId(定義ID)を特定する。
- main関数のDefIdを基に、TyCtxtから型付き高水準中間表現(THIR)を取得する。
- THIRから検証に不要な情報を削ぎ落とし、独自の中間表現(RTHIR)へと変換する。
- RTHIRからmain関数の本体(Body)を抽出し、シンボリック実行を開始する。
- 関数の本体に含まれる文(stmts)と式(expr)を先頭から順に評価し、プログラムの状態を論理的な中間表現(LIR)としてモデル化する。
- シンボリック実行によって構築された論理式(LIR)を、SMT-LIB 2形式のテキストに変換する。
- 生成したSMT-LIB 2クエリを、Z3(SMTソルバ)に入力として渡す。
- Z3の証明結果を出力する。
- 検証対象となるRustのソースコードファイルをコマンドライン引数として受け取る。
- rustc_driverのrun_compilerを呼び出し、Callbackを登録してコンパイル処理を開始する。
- コンパイラの解析後、after_analysisコールバック内で型情報コンテキスト(TyCtxt)を取得する。
- TyCtxtを用いて、プログラムのエントリーポイントであるmain関数のDefId(定義ID)を特定する。
- main関数のDefIdを基に、TyCtxtから型付き高水準中間表現(THIR)を取得する。
- THIRから検証に不要な情報を削ぎ落とし、独自の中間表現(RTHIR)へと変換する。
- RTHIRからmain関数の本体(Body)を抽出
- Bodyからアノテーションやpureな関数を抽出
- CHCに変換しそれをSMT-LIB 2クエリに変換
- 生成したSMT-LIB 2クエリを、Z3(SMTソルバ)に入力として渡す。
- Z3の証明結果を出力する。
以下の関数プログラムを検証
fn seven(n: i64) -> i64
// todo
// require: n <= i64::MAX - 3
// ensure: n == 7
{
if n <= 4 { n + 3 } else { seven(seven(n - 4)) }
}
fn main() {
assert!(seven(42) == 7);
}