Fil-C 徹底解説 — Rustに書き直さずにC/C++をメモリ安全にする「InvisiCaps + GC」の仕組みと現実的な使いどころ
はじめに
C と C++ が生むセキュリティ脆弱性の 66〜75% は、バッファオーバーフローや use-after-free といった「メモリ安全性」の失敗に起因すると言われる。米 CISA は重要インフラ向けソフトウェアにメモリ安全化のロードマップ提出を求め、業界は Rust への移行を進めている——が、世界中に積み上がった膨大なレガシー C を全部書き直すのは現実的ではない。そこに現れたのが Fil-C だ。「既存の C/C++ をほぼ書き換えずに、実行時にメモリ安全を保証する」という大胆なアプローチが、7月にはてなブックマーク121を集め話題になっている。本記事では Fil-C が何をどう実現しているのか、その仕組みと制約を、Rust 移行との対比で解説する。
Fil-C とは何か — 「書き直さない」メモリ安全化
Fil-C は、元 Apple の WebKit/JavaScriptCore エンジニアである Filip Pizlo 氏が開発するメモリ安全な C/C++ コンパイラだ。ベースは clang 20.1.8 で、C17 と C++20 をサポートする。最大の特徴は、gcc や clang を Fil-C に差し替えてコンパイルするだけで、特別な構文なしに既存コードがメモリ安全になる点にある。
Zenn の検証記事では、著者がバイナリ tarball を落として setup.sh を実行し、通常の clang と同じ手順で C コードをコンパイルしている。試しにバッファオーバーフローを起こす strcpy を書くと、Fil-C は違反箇所を libc 内部までピンポイントで示す詳細なスタックトレースを出して停止した。解放済みメモリへのアクセス(use-after-free)も同様に検出され、「freed」フラグが立ってアクセスが弾かれる。付属の stdfil.h を使うと、ポインタが持つアクセス可能範囲(下限・上限アドレス)まで覗ける。
つまり Fil-C は、Rust のように所有権モデルを学び直してコードを書き換えるのではなく、「今あるコードをそのまま安全な実行環境に載せ替える」道を選んだツールだと言える。
技術的な仕組み — InvisiCaps と FUGC
Fil-C のメモリ安全性は、大きく2つの技術で支えられている。
1. InvisiCaps(見えないケイパビリティ) Fil-C は各ポインタに、そのポインタがアクセスしてよいメモリ範囲と操作権限を記述した「ケイパビリティ(capability)」を紐づける。ポイントは、このメタデータをポインタと同じ64bit幅に見せかけたまま、アドレス空間の「見えない領域」に別途格納することだ。ARM の CHERI がポインタ自体を128bitに拡張して能力情報を埋め込むのに対し、Fil-C はポインタのサイズを変えない。そのため既存の構造体レイアウトや ABI 上のポインタ幅の前提を壊さずに済む。あらゆる潜在的に危険な操作(配列アクセス、ポインタ演算、間接参照)は、このケイパビリティに照らして実行時に検証される。
2. FUGC(Fil’s Unbelievable Garbage Collector)
Fil-C は並行動作するガベージコレクタを備える。ここで重要なのは free() の扱いだ。free() は即座にメモリを再利用可能にするのではなく、そのメモリを指す全ポインタを原子的に「無効」としてマークする。これにより use-after-free・二重解放・不正な free はすべて確実に panic する。GC はオブジェクトを移動させない設計なので、ミューテータとコレクタ間の同期が単純になり、スレッド停止はループのバックエッジ(安全な地点)での数命令に限定される。LWN の計測では FUGC の CPU 使用は約135%(=35%の時間 GC が走る)程度で、リアルタイム性を大きく損なわない範囲に収まっている。
この2つの組み合わせにより、コンパイル時の型システムに頼る Rust とは対照的に、Fil-C は実行時チェックでメモリ安全を担保する。
性能オーバーヘッドと現実的な制約
「実行時に全ポインタを検証する」以上、オーバーヘッドは避けられない。Zenn 記事のベンチマーク(gcc 比)では、傾向がはっきり出ている。
- mandel(浮動小数点中心): 約1.05倍遅い — ポインタ操作が少ないとほぼ無視できる
- btree(メモリ確保が多い): 約1.10倍遅い — Zig の safe mode より速い場面も
- sieve(配列アクセス中心): 約2.27倍遅い — 境界チェックのコストが直撃
LWN の分析では、ポインタを多く含む構造体でメモリ使用量が倍増し、典型的には4倍程度の性能低下も起こりうるとされる。要するにポインタの使い方次第でオーバーヘッドは大きく振れる。数値計算のホットループなら実用範囲だが、ポインタ追跡が支配的なワークロードでは代償が重い。しかも Rust の unsafe ブロックのような「ここだけチェックを外して最適化する」逃げ道が Fil-C には無い。
もう一つ見逃せない制約が ABI 非互換だ。Fil-C が生成したオブジェクトは通常のコンパイラの成果物とリンクできない。安全チェーンを完全にするための意図的な設計だが、裏を返せば依存ライブラリを含めてすべてを Fil-C で再コンパイルする必要がある。実際 Linux From Scratch での検証では、ユーザースペースをメモリ安全版として構築できた一方、Fil-C 自身のランタイム・glibc・カーネルといった土台は従来コンパイラで作る必要があった。加えて、メモリ安全性に無関係な undefined behavior には対処しない、Rust など他言語とのリンケージは未対応、といった線引きもある。開発は Pizlo 氏がほぼ単独で進める活発な個人プロジェクトという段階だ。
エンジニアへの影響 — どこで効くか
Fil-C は「Rust 移行の完全な代替」ではなく、移行戦略の選択肢を増やすものとして捉えるのが実務的だ。使いどころは主に3つ考えられる。
第一に、書き直しコストを払えないレガシー資産の延命。数十万行の枯れた C コードを、挙動を変えずにメモリ安全な実行環境へ載せ替えられるなら、CISA が求めるロードマップに対する現実的な一手になる。DARPA の TRACTOR(C→Rust 自動変換)のような機械翻訳とは別軸の、「翻訳せず封じ込める」戦略だ。
第二に、セキュリティ検証・ファジングの土台。既存コードを Fil-C でビルドすれば、メモリ違反が詳細なスタックトレース付きで即座に panic する。ASAN 的な用途を、より強い保証(provenance 違反の検出まで)で置き換えられる可能性がある。
第三に、性能要件が緩いツール・バッチ処理。ポインタ操作が支配的でないワークロードなら、1.1倍前後のオーバーヘッドで安全性を買える。一方、レイテンシがシビアなホットパスや、依存ライブラリを Fil-C で再ビルドできない環境では現状フィットしない。
まとめ
- Fil-C は clang ベースの「書き直さずに C/C++ をメモリ安全化する」コンパイラで、特別な構文なしに既存コードを安全化できる。
- 仕組みは、ポインタ幅を変えずに能力情報を隠し持つ InvisiCaps と、
free()を確実に無効化する並行GC FUGC の組み合わせ。 - 代償はオーバーヘッド(配列アクセス中心で約2.3倍、ポインタ含有構造体でメモリ倍増)と ABI 非互換(依存含め全再コンパイルが必要)。
- Rust への全面移行が非現実的なレガシー領域で、「翻訳せず封じ込める」現実解として価値がある。
Rust か C かの二択で語られがちなメモリ安全性の議論に、Fil-C は「既存の C をそのまま安全に走らせる」という第三の軸を持ち込んだ。まだ個人プロジェクトの域を出ないが、レガシー資産を抱える現場ほど、この選択肢の成熟を注視する価値がある。
今日のその他のニュース
Gemini 3.6 Flash 発表、Gemini 4 も開発中 — Google が Gemini 3.6 Flash / 3.5 Flash-Lite / 3.5 Flash Cyber を発表。3.6 Flash はトークン効率が改善し、同一コストでより高品質な出力を狙う。次世代の Gemini 4 も開発中と明言された。(gigazine)
DRAM・NAND 価格が10倍に — AI 需要を背景に半導体メモリ価格が急騰。クラウド費用・自作PC・組込み開発の調達コストに直結し、当面の計画見直しを迫る「異常」な市場拡大が続く。(JBpress)
FeliCa の脆弱性を JVN が正式公表、深刻度「High」 — 約1年前に騒がれた FeliCa の脆弱性を JVN が正式に公表。深刻度は「高」と評価された。決済・交通系での影響範囲に注意。(ITmedia)