Rust製zlib実装がIntel CPUバグを回避。C言語なら黙って壊れていた

Rust製zlib実装がIntel CPUバグを回避。C言語なら黙って壊れていた
Intel

zlibのRust実装「zlib-rs」の最新版0.6.4が6月21日にリリースされた。AArch64のチェックサム修正やAVX-512の最適化も含まれる。だが今回の本題は別にある。Intel Raptor Lake世代のCPUバグに対する回避策だ。


Raptor Lakeが引き起こしたクラッシュ

zlib-rsは、Trifecta Tech Foundation(オランダ)が開発するRust製のzlib互換実装で、ISRGのProssimoプロジェクトが初期の開発を支援した。2024年4月の初版から採用が広がり、2026年5月にリリースされたFirefox 151.0.0でgzip圧縮・展開のデフォルトバックエンドに採用されている。

問題が起きたのは、Firefoxがzlib-rsを統合した直後だった。Nightly版でクラッシュレポートが上がり始め、ログには「論理的にありえない境界チェックの失敗」が残っていた。開発者はローカルでは再現できず、レポートが積み重なるにつれてパターンが見えてきた。クラッシュの報告元が、Intel第13・14世代Core(Raptor Lake)に集中している。

zlib-rsの開発を率いるフォルケルト・デ・フリース(Folkert de Vries)氏は、Trifecta Tech Foundationのブログでこう振り返っている。「自分たちの実装がこの悪名高いRaptor Lake CPUバグを踏んでいた」。だが何がバグを引いているのか、どう追い詰めればいいのか、手がかりがなかった。

1バイトの書き込みが化ける

転機は、RAD Game Toolsのファビアン・ギーゼン(Fabian Giesen)氏が公開したブログ記事だった。同氏はゲーム向け圧縮ライブラリOodleで同じCPUバグに直面し、問題の正体を特定していた。ハフマン符号化の結果をメモリに書き込む際に使われる、特定のMOVB命令がバグの引き金になる。

RCXレジスタのビット8〜15(ch)をメモリに書き込む命令が、Raptor Lakeでは稀にビット0〜7を書き込んでしまう。ハードウェアレベルの不具合で、ソフトウェアから見れば1バイトの値が無言で化ける。zlibもハフマン符号化を使う。zlib-rsがまさにこの命令を生成していた。

ここでRustの特性が効いた。C言語のzlibなら、壊れたデータはそのまま処理されていただろう。検出できるのは、展開後のデータが運良くチェックサム不一致を起こした場合だけだ。zlib-rsでは、Rustの境界チェックが不正な値を即座に捕まえ、クラッシュとして表面化させた。デ・フリース氏もブログで「C言語なら黙ってデータが壊れるだけだった。境界チェックの失敗として表面化したのは幸運だった」と書いている。

Raptor Lakeバグ: C言語とRustの検出差異
MOVB命令実行Raptor Lakeのバグが発動1バイトの値が無言で化けるC言語のzlibデータ破損が静かに拡散チェックサム不一致でしか検出不可Rustのzlib-rs境界チェックで即座に検出クラッシュとして表面化

修正は、コンパイラ(LLVM)が問題の命令を生成しないよう、メモリ書き込みの方法を変えるワークアラウンドだ。FirefoxではMozillaのマイク・オメ(Mike Hommey)氏がパッチを実装し、zlib-rs本体にもアップストリームされた。LLVM 23ではこの命令自体が生成されなくなるというが、開発者によれば偶然の副産物であり意図的な修正ではない。zlib-rsは当面このワークアラウンドを維持する。

0.6.4のその他の変更

Raptor Lake対応以外にも、0.6.4には実質的な修正と最適化が含まれる。

AArch64のAdler32修正では、NEONコードパスでpair変数の剰余演算がテール処理後に抜けていた問題を直している。整数オーバーフローにより、特定の入力でチェックサムが不正になっていた。x86_64のAVX2/AVX-512実装やスカラー実装には影響しない。

AVX-512のVNNI最適化では、命令レベル並列性(ILP)を活かすトリックを標準AVX-512に適用した。少なくともAMD Zen 5では、Adler32チェックサムの計算でわずかな性能向上が確認されている。

LoongArch64向けCRC32実装が新たに追加された。LoongArchは中国Loongsonが開発するCPUアーキテクチャで、独自のCRC32命令を持つ。

「Cより速い」先の現実

zlib-rsは2025年2月の0.4.2リリース時点で、展開速度でC実装のzlib-ngやChromium版zlibを上回ったと発表している。開発元のベンチマークでは、x86_64 Linuxの展開でzlib-ngを6〜10%以上上回る結果が出ており、CPython経由でストックzlibと比較した別のテストでは最大32倍の速度差が記録されている。

だがRaptor Lakeの一件は、性能とメモリ安全性だけでは語れない現実を突きつけた。ハードウェアバグはソフトウェア側の正しさとは無関係に発生し、デバッガも再現手順も効かない。zlib-rsのチームは数か月間、何をすべきかわからないまま過ごしたと明かしている。

Rustの境界チェックがなければ、このバグはデータ破損として静かに広がっていた可能性が高い。「安全」とは、バグを防ぐことだけではない。バグが起きたとき、それを見えるようにすることでもある。

参照元

他参照

関連記事

この記事を共有する