ソフトウェアってかなりバグっている

lapla

https://slide.lapla.dev/zatsu/clippy_bugs(.pdf)
whoami
Intro: 本発表の目的
  • 主にOSSとか大きめのソフトウェアに貢献することは敷居が高いと感じている人向け
  • Rustの公式linterであるClippyという,そこそこ規模の大きなソフトウェアで自分が修正した,原因が単純だと思ったバグを2つ紹介
    • 意外にも(?)開発が盛んで大きなOSSなどでも貢献の機会は多いということを示したい1^1
    • Rustを知らなくてもそれなりに分かる内容になっているはず
  • 発表者のスタンス: ミスることは誰にだってある
    • 結果としてバグが混入してしまったことについて責める姿勢は持っていない

1: 一応パッチを投げるペースで言えばここ数カ月1番か2番なので,一定の説得力はあると思っている

Intro: Clippyの主な役割
  • ClippyはRustのコードを解析して,潜在的な問題を指摘する言語公式のlinter
  • lintルールが個別に定義されていていて,各ルールに引っかかると指摘が飛ぶ(参考: ルール一覧
  • lintルールによっては,修正後のコードも提案する
    • 「この部分が問題ですよ~」の指摘にとどまらず,「この部分が問題なので,こう書くと良いですよ~」の提案をする
事例1: no_stdで壊れる提案
  • Rustには標準ライブラリ(std)を使わないでプログラムを書けるno_std環境がある
    • 雑には一般的なOSでない環境でRustを動かしたいときに使うと思えばOK
    • 当然だが,no_stdではstdに所属するモジュールは使えない
事例1: no_stdで壊れる提案
  • あるとき,lintルールによっては,修正後のコードを提案する際に,no_stdかどうかをチェックせずにstdに所属するモジュールを使う提案をするものがあることを発見した
    • すなわち,このようなlintルールをno_std環境で発火できればコンパイルの通らないコードが提案され,明らかにClippyのバグといえる
  • no_stdという特殊な環境で特定のlintルールに引っかかるコードを書く人は少ないので,ろくにバグレポートが上がらず,誰も気付いていなかった(or 気付いていたが誰も出さなかった)
事例1: no_stdで壊れる提案
  • バグレポートは上がらない一方,「このような理由でno_stdでのみ壊れる提案がある」と決め打って調査すると,発見が容易
    • このようなケースの提案は基本的にClippyの実装中でリテラルとしてベタ書きされているので,Clippyのコードベース上でstd::をgrepして丹念に1つ1つ見ていくだけで良いから
  • すなわち誰も見つけないが,一度気付けばバグをたくさん発見できるバグ発見法
  • 結果として5個のlintルールがこういうことをしていたので直した
事例2: エスケープ処理の不備
  • ある提案を作成するlintルールについての話題
  • 提案を作成する際に,元のコードに生文字列が含まれていると,それをエスケープ処理を行って普通の文字列にして,提案に用いる処理があった
    • 生文字列: エスケープしなくても特殊文字そのまま使えるくん.例えばRustでは普通の文字列で\を使うならエスケープして"\\"と書くが,生文字列ならr"\"と書ける(rは生文字列だと示すためのもの)
  • 適当な例: 生文字列の中身がhoge\\foo\"なときに,hoge\foo"に変換する
事例2: 問題の実装
replacement.replace('"', "\\\"").replace('\\', "\\\\")
  • replacementが生文字列
    • すなわち,"\"に置換した後に\\\に置換して"\のエスケープを行う

大丈夫????

事例2: 問題の実装
replacement.replace('"', "\\\"").replace('\\', "\\\\")
  • replacementが生文字列の中身
    • すなわち,"\"に置換した後に\\\に置換して"\のエスケープを行う

大丈夫ではない.例えばreplacement"だと...?

  • replacement.replace('"', "\\\"")\"になる
  • その後.replace('\\', "\\\\")\\"になる
  • 結果の文字列はただの文字列として提案される("で囲まれる)ので,こう解釈されてバグる
事例2: 解決策
  • よってreplacement"が含まれていると変換結果に余計なバックスラッシュが入ってバグる
  • 2つの置換の順番が逆なら,当然この問題は起こらない
    • "が入力でも\"になるだけなので普通の文字列として扱ったときにエスケープされたダブルクオートになってくれる(正しい挙動)
  • git blameを見たところ,このバグは少なくとも3年くらい存在していたらしい
    • まあこの期間直っていなかったのなら,踏んだ人はそこまでいなかった(ので気付かれずいた)と思いたい1^1が...

1: バグレポートでこの問題を調査したので,踏んだ人がいないということはない

まとめ
  • Clippyに存在した,単純だと思った原因のバグの事例を紹介した
    • 時間の都合上2つの紹介だが,他に無いわけではないので,興味があれば聞いてください
  • 「世の中のソフトウェアは大抵バグっている」と考えると,巨大なソフトウェアに対する見方も変わってくるかもしれない