どの言語でも使える C-Reduce の技法
(bernsteinbear.com)- C-Reduce は C コンパイラのバグ再現コードを縮小するツールだが、決定的な条件・高速な再現・変更可能なソースファイルがあれば、他の言語にも適用できる
- 例として、RustPython で scrapscript を実行中に発生したバグを縮小する過程を示しており、
interesting.shが特定のエラーメッセージを探して再現可否を判定する creduce --not-c interesting.sh scrapscript.pyを実行するだけでファイルサイズは素早く小さくなり、序盤でほぼ 50% 縮小する進行を確認できる--not-cは C 専用の縮小パスを避けるオプションであり、Python のような入力で不要な実行時間を減らすのに役立つ- バグが再現される条件を短いスクリプトにできるなら、C 以外の言語のバグレポートも C-Reduce でより小さく扱いやすくできる
C-Reduce を C 以外の入力に使う条件
- C-Reduce は Regehr とその同僚が作った C コンパイラのバグ再現コード最小化 ツールである
- 10,000 行の C ファイルが Clang のバグを引き起こすとき、巨大なファイルをそのまま送るのではなく、自動で縮小する用途に使える
- C 専用ツールのように見えるが、次の条件があれば他言語の入力にも使える
-
決定的な条件
- 縮小速度に役立つ、比較的高速な再現方法
- C-Reduce が縮小できる、1 つ以上の変更可能なソースファイル
- 決定的な条件はループラッパーを使って確率的に模倣することもできる
-
RustPython バグ再現縮小の例
- RustPython で scrapscript を実行していたところバグが発生し、これを報告するために
interesting.shスクリプトを書いた - スクリプトは RustPython バイナリの 絶対パス で
scrapscript.pyを実行した後、標準エラーを含む出力から次の文字列を探すtried to push value onto stack but overflowed max_stackdepth
- 実行コマンドは次のとおり
creduce --not-c interesting.sh scrapscript.py
- C-Reduce は parallel で interestingness test を実行し、ファイルサイズを素早く縮小していく
- 例の進行率は 0.5%、9.2%、18.1%、47.5% などと表示される
- 数秒のうちにファイルをほぼ 50% 縮小
- 記事を書き終える時点では 96.9% 縮小 に到達
--not-cを使わないと、C-Reduce は C 専用パスを多数使用する- Python 入力では、こうしたパスが実行時間を遅くする可能性がある
- 結果そのものを実質的に変えることはない可能性が高い
- 関連内容は後に Delta debugging ページへ移された
1件のコメント
Hacker News の意見
縮小後のファイルが共有されていなかったので自分で回してみた。
RustPythonをビルドしてscrapscript.pyを取得し、interesting.shのパスを変えてnix run nixpkgs#creduce -- --not-c interesting.sh scrapscript.pyで実行したところ、最終的に96.4%、7347バイトあたりで止まり、結果はhttps://gist.github.com/judofyr/47cba8a20cb2cd5798943ef975d0...にあるshrinkrayは10分ほど回すと162バイトまで縮む: https://gist.github.com/DRMacIver/ee025c90b4867125b382a13aaa...もっと長く置けば少し良くなるかもしれないが、ほぼ止まったように見えたので飽きて終了した
C-Reduceの作者であるJohn Regehrも、この用途には
Shrinkrayを試してみるよう勧めている。Shrinkrayは形式に依存せず動作するよう作られており、C-Reduceが得意でない場合にも向いているツールだという: https://mastodon.social/@regehr/113489759789563570Shrinkrayの公式リポジトリですか? https://github.com/DRMacIver/shrinkraycviseにも触れておきたい: https://github.com/marxin/cviseC以外の言語にもかなりうまく動作するPython製の代替である
John Regehrほかの著者が2012年に書いた、動作の仕組みを説明する論文がある: https://fsl.cs.illinois.edu/publications/regehr-chen-cuoq-ei...
記憶では、C-Reduceのドメイン非特化の縮小の大半は単純な総当たりに近い
C-Reduceを今初めて知ったが、もう夢中になっている。初めてgit bisectを見つけた時に似ている
いつか適した状況に出会ったときに使えるよう、頭の片隅に入れておきたい
設定してみようかと思う。VICEがホストOSのファイルへ「出力」する機能をサポートしているというので、エミュレータ上でテストを走らせられそうだ
デルタデバッグは新しい概念ではない: https://en.wikipedia.org/wiki/Delta_debugging
私が作ったデルタデバッグ実装である
deltaは19年以上前のものだ: https://github.com/dsw/deltaMicrosoftがオープンソースを「癌」と呼んでいた時代に、Microsoft Researchが私のオフィスまで人を送り、公開してほしいと依頼してきたのでオープンソースとしてリリースした。LatnerのLLVM紹介でも「標準的なdeltaデバッグツール」に言及しているので、かなりよく知られたツールである: https://aosabook.org/en/v1/llvm.html
つまり、効果的なプログラム縮小には単純なデルタデバッグ以上のものが必要だという結論である。もちろんC-Reduceも今では12年もののツールだ
同時に、リンクされているLLVMツールの
BugPointはLLVM IR専用である一方、C-Reduceの方がより汎用的に見える。自動テストケース最小化ツールと手法は大多数の開発者にはまだなじみが薄いので、この分野で古くから知られているアイデアであっても、この記事は有用かもしれない前後の例がある記事を見つけた: https://pramodkumbhar.com/2024/01/c-reduce-systematically-ta...
それでも各反復で何を削除するかをどうやって知るのかは、まだよく理解できない。ある程度のトークン化はあるはずだが、それが複数のプログラミング言語にわたってどう動くのかは分からない
creduceは素晴らしい私は難解なLLVMターゲットバックエンドを開発していたとき、
CSmithでランダムなテストプログラムを何時間も生成するテストスクリプトを書いていた。クラッシュすると自動でC-Reduceを走らせ、調査用のファイルとして残してくれたので、本当に大いに助かったSQL でもうまく動作する。実務で使っており、https://github.com/sqlancer/sqlancer?tab=readme-ov-file#redu... で知った
C 以外の言語でも動作する理由を説明しなければ信じにくい主張だ。嘘だとは思わないが、LLM なしでそれをやるというのは戸惑う
例えば、C 方式で入力をトークン化したうえで長さ 1〜13 程度の塊をランダムに捨てる方法は、C に似た言語の大半が似たトークン化規則を持つため、不要な修飾子や属性を取り除くのによく効く。対応の取れた括弧
()、{}、[]の単位を削除するパスも、ほぼすべての言語で有用だ。コメントと空白の削除も、多くの言語が C と同じ/* */、//スタイルを使うので効果的だ実際、完全に C/C++ 専用と言えるパスは多くない。経験上、
creduceの大きな弱点の一つは、テンプレートを除去する縮小ステップ、つまり比較的自動化しやすそうに見える作業が本当に苦手な点だ一部の変換は Clang フロントエンドを使うかなり C 特化のものだが、一部はかなり汎用的で、Algol 系言語ならおおむね動作する可能性が高い。モジュール式のツールなので、望むなら他の言語を理解する変換を追加することもできる
ここで言っているのはアルゴリズムのようなもので、不気味な機械学習ではない。Prolog を AI に使うようなものも含まれるが、AI を作る目的ではうまく機能しないという小さな欠点がある
creduceが変形された入力スクリプトを実行して、自分のファイルを消したり昼食を食べ尽くしたりすることもあり得るのだろうか?dustmiteと比べるとどうなのか? https://dlang.org/blog/2020/04/13/dustmite-the-general-purpo...