mcpField
F
ffi-code-review

ffi-code-review

github.com/existential-birdsテスト・品質8566 回インストール11 週間前に更新
リポジトリ

ffi-code-review について

ffi-code-reviewは、Rustの外部関数インターフェースに特化したコードレビュー用スキルです。crateやビルド設定、ABIと型レイアウト、ポインターや所有権、コールバックを確認し、検証ゲートを通過してから指摘を報告します。

主な機能

  1. 01Cargo.tomlとbuild.rsを確認
  2. 02ABI宣言とシンボルのエクスポートを点検
  3. 03FFIの型レイアウトと文字列処理をレビュー
  4. 04所有権、コールバック、panic安全性を評価
  5. 05検証ゲート後に指摘を報告

活用シーン

  1. 01RustからCライブラリへのバインディングをレビュー
  2. 02FFI変更のメモリとABIのリスクを確認
  3. 03ビルドスクリプトと生成バインディングを評価

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/existential-birds/beagle --skill ffi-code-review

インストール後、Claude Code で/ffi-code-reviewを入力して読み込まれたか確認します。

同梱ファイルreferences/safety-patterns.mdreferences/type-mapping.md

詳細

FFI コードレビュー

レビューワークフロー

  1. Cargo.toml を確認する -- Rust エディション(2024 では extern ブロックと unsafe 属性に破壊的変更があります)、build-dependencies(bindgen、cc、pkg-config)、crate-type(cdylib、staticlib)、および links キーを確認します
  2. build.rs を確認する -- リンクディレクティブ(cargo:rustc-link-lib、cargo:rustc-link-search)、bindgen の設定、C ソースのコンパイルを確認します
  3. extern ブロックを確認する -- 呼び出し規約、シンボル宣言、安全性注釈を確認します
  4. 型レイアウトを確認する -- FFI を介するすべての型は、#[repr(C)] またはプリミティブな FFI 型でなければなりません
  5. 文字列とポインターの扱いを確認する -- CStr/CString の使用、null チェック、所有権の移転を確認します
  6. コールバックを確認する -- extern "C" fn ポインター、FFI 境界を越える際のパニック安全性を確認します
  7. ゲート -- 報告する前に、以下のゲートを完了します。「内部検証」で先に進まないでください

ゲート

順番に完了してください。各問題についてゲート 4に合格するまで、指摘事項を出力しないでください。

ゲート 1 — クレートのコンテキスト(ディスク上)
合格条件: レビュー対象クレートの Cargo.toml(該当する場合はワークスペースメンバーのパス)を開き、edition = と、この FFI に関係する links、crate-type、build-dependencies の項目を記録していること。
根拠のない指摘を防ぐ条件: エディション固有の指摘(unsafe extern "C" {}、#[unsafe(no_mangle)] など)には、この確認が必要です。edition が 2024 でない場合、2024 のみの要件を指摘しないでください。

ゲート 2 — リンクとバインディングのソース
合格条件: クレートがネイティブコードをリンクするか、bindgen/pkg-config を使用する場合、build.rs(またはチェックイン済みのバインディングのエントリポイント)を開いていること。build.rs がない場合は、バインディングが手書きであることを明記し、該当する extern / include! の箇所をレビューしていること。
成果物: 開いたファイルのパスを少なくとも 1 つ記録していること(例:build.rs、src/ffi.rs、または include! 経由の OUT_DIR バインディング)。

ゲート 3 — コードの根拠
合格条件: 予定している各指摘について、差分の抜粋や部分的なコードスニペットだけでなく、読み込んだ関数またはブロック全体に基づく対象箇所 [FILE:LINE] があること。

ゲート 4 — 報告前の手順
合格条件: review-verification-protocol スキルを読み込み、適用していること。これには repr(C)、安全性コメント、所有権/コールバック、または bindgen を多用するコードに関するFFI 固有の検証も含まれます。

出力形式

指摘事項は次の形式で報告してください。

[FILE:LINE] ISSUE_TITLE
Severity: Critical | Major | Minor | Informational
Description of the issue and why it matters.

クイックリファレンス

問題の種類リファレンス
C と Rust の型マッピング、repr(C) レイアウト、列挙型、不透明型references/type-mapping.md
セーフラッパー、所有権の移転、コールバック、build.rs、テストreferences/safety-patterns.md

レビューチェックリスト

extern ブロックと呼び出し規約
  • 外部関数宣言で extern "C" を使用している(明示的に指定し、裸の extern は使わない)
  • エディション 2024:extern "C" {} ブロックを unsafe extern "C" {} と記述している
  • C に公開する関数で extern "C" fn を使用している(デフォルトの Rust 呼び出し規約は使わない)
  • 呼び出し規約が外部ライブラリと一致している(Win32 API では "C"、"system")
  • #[link(name = "...")] で正しいライブラリ名を指定している
  • 静的リンク時に #[link(name = "...", kind = "static")] を使用している
シンボル管理
  • エクスポートする関数で #[no_mangle] を使用し、シンボル名を保持している
  • エディション 2024:#[no_mangle] を #[unsafe(no_mangle)] と記述している
  • エディション 2024:#[export_name = "..."] を #[unsafe(export_name = "...")] と記述している
  • Rust の名前と C のシンボル名が異なる場合に #[link_name = "..."] を使用している
  • エクスポートする項目が pub である(公開された #[no_mangle] シンボルのみがライブラリ出力に現れます)
型レイアウト
  • FFI 境界を越えるすべての構造体/共用体に #[repr(C)] が付いていること — Rust のデフォルトのレイアウトは未定義です
  • プリミティブ型には std::ffi/std::os::raw の対応する型(c_int、c_char、c_void)を使用していること
  • C で int を使う箇所で、単独の i32 を使用していないこと — プラットフォームによって幅が異なるため、c_int を使用します
  • __be32 のような特殊な C 型には、Rust の整数型ではなくバイト配列([u8; 4])を使用していること
  • FFI 境界を越える列挙型には、#[repr(C)] または明示的な判別値を指定した #[repr(u8)]/#[repr(u32)] を使用していること
  • C スタイルのビットフラグ列挙型には、Rust の列挙型ではなく整数型をラップした新しい型(または bitflags クレート)を使用していること
  • 新しい値が追加される可能性のある C 列挙型を表す列挙型に #[non_exhaustive] を付けていること
文字列の扱い
  • C 文字列には &str や String ではなく、CStr(借用)または CString(所有)を使用していること
  • CString::new() の結果について、内部にヌルバイトがないか確認していること(\0 があると Err を返します)
  • .as_ptr() で導出した *const c_char ポインターを使用する間、CString が存続していること
  • 受け取った *const c_char を、unsafe 内で CStr::from_ptr() を使って検証していること
  • C 文字列が有効な UTF-8 であると仮定していないこと — Result を返す to_str() を使用します
  • OS パスには &str ではなく、OsStr/OsString と CStr を使用していること
所有権とメモリ割り当て
  • 所有権の契約が明確であること:誰が割り当て、誰が解放するか
  • Rust が割り当てたメモリは Rust が解放し(Box::from_raw)、C が割り当てたメモリは C が解放すること
  • ヒープの受け渡しで Box::into_raw と Box::from_raw を正しく対にして使用していること
  • 配列を C に渡す際は Vec::into_raw_parts を使用していること(ポインター+長さ+容量)
  • C に渡すすべての不透明な Rust 型にデストラクター関数を公開していること
  • C が割り当てたメモリに対して Drop が実行されないこと(また、その逆も同様)
コールバック
  • コールバック型にクロージャや fn(...) ではなく、extern "C" fn(...) を使用していること
  • FFI 境界を越えてパニックが巻き戻らないよう、コールバックで std::panic::catch_unwind を使用していること
  • コールバックのコンテキストを *mut c_void として渡し、呼び出し箇所で安全に復元していること
  • null 許容の関数ポインターに Option<extern "C" fn(...)> を使用していること(ニッチ最適化)
Bindgen とビルドスクリプト
  • Bindgen の出力をレビューして正しさを確認していること(自動生成された型には調整が必要な場合があります)
  • 生のバインディングには -sys クレートのパターンを使用し、安全なラッパーには別のクレートを使用していること
  • build.rs で cargo:rustc-link-lib と cargo:rustc-link-search を正しく使用していること
  • Cargo.toml の links キーで、同じネイティブライブラリが重複してリンクされないようにしていること
  • プラットフォーム固有のバインディングをビルドごとに生成していること(単一プラットフォーム向けにチェックインしていないこと)
安全性に関するドキュメント
  • すべての unsafe ブロックに、不変条件を説明する // SAFETY: コメントがあること
  • すべての公開 FFI ラッパー関数に、安全性の要件が記載されていること
  • Edition 2024:unsafe fn の本体で、安全でない操作を明示的な unsafe {} ブロックで囲んでいること

重大度の判断基準

重大(マージをブロック)
  • FFI 境界を越える型に #[repr(C)] がない(メモリレイアウトが未定義)
  • 文字列の扱いが誤っている:CStr/CString が必要な箇所で &str/String を使用している
  • 所有権が混乱している:C が割り当てたメモリを Rust のアロケーターで解放している(またはその逆)
  • catch_unwind を使わずに、パニックが FFI 境界を越えて巻き戻る
  • C のビットフラグに Rust の列挙型を使用している(無効な判別値は未定義動作を引き起こします)
  • extern "C" fn ポインターが必要な箇所にクロージャを渡している
大(修正を推奨)
  • unsafe ブロックまたは公開 FFI 関数に安全性に関するドキュメントがない
  • 受け取った *const T/*mut T を参照外しする前に null ポインターをチェックしていない
  • C がポインターを使用する前に CString が破棄される(ダングリングポインター)
  • #[link(name = "...")] がなく、一部のプラットフォームでリンクに失敗する
  • Edition 2024:extern ブロックに unsafe extern が付いていない
  • Edition 2024:#[no_mangle] が #[unsafe(...)] で囲まれていない
小(修正を検討)
  • C の int に c_int ではなく i32 を使用している(ほとんどのプラットフォームでは正しいものの、移植性がありません)
  • 拡張可能な C 列挙型に対応する列挙型に #[non_exhaustive] がない
  • 保守性を高められる Bindgen を使わず、冗長な手動バインディングを使用している
  • プラットフォームガードなしでバインディングをチェックインしている
情報
  • 生のバインディングを -sys クレートに分割する提案
  • 異なる *mut c_void ポインターに不透明なラッパー型を追加する提案
  • null 許容ポインターに Option<NonNull<T>> を使用する提案

有効なパターン(指摘しないでください)

  • エディション 2024 での unsafe extern "C" {} -- 外部宣言の正しい形式です
  • エディション 2024 での #[unsafe(no_mangle)] -- シンボルエクスポートの正しい形式です
  • null 許容コールバックに対する Option<extern "C" fn(...)> -- ニッチ最適化が保証されています
  • null 許容ポインターに対する Option<NonNull<T>> -- ゼロコストの null 許容ポインターパターンです
  • 不透明な C 型に対する *mut c_void -- 内部レイアウトが重要でない場合の標準的な方法です
  • 型安全な不透明ポインターのために c_void をラップする異なる空構造体 -- ポインターの取り違えを防ぎます
  • コンパイル時リテラルを使った CStr::from_bytes_with_nul_unchecked -- リテラルが null 終端されていると分かっている場合は安全です
  • 制御された巻き戻しに対する extern "C-unwind" -- RFC 2945 により有効です
  • bindgen クレートでの include!(concat!(env!("OUT_DIR"), "/bindings.rs")) -- 標準的なパターンです
  • 所有権移転に対する Box::into_raw / Box::from_raw の組み合わせ -- 対になっている場合の正しいパターンです

指摘を報告する前に

問題を報告する前に、ゲート 1~4 を順番に完了してください。ゲート 4 には review-verification-protocol スキルが含まれています。

コメント