CodeQL 2.27.2が10月7日に出た。リリースノートの中で既存のクエリに最も影響し得るのはGoライブラリの変更だ。
今回のリリースはGoの制御フローグラフ(CFG)を共有CFGライブラリで再実装した。CFGはコードが実行され得る順序をノードとエッジで表したグラフだ。
代入、関数の引数と結果、range文、遅延呼び出し(defer)を表すノードが加わった。エントリーポイントから到達できないノードは除かれ、基本ブロックも共有CFGから直接組み立てられる。
特定のノード、エッジ、位置、テキスト表現、基本ブロックの境界に依存する既存のコードは修正が必要になる場合がある。
カスタムクエリパックで探すAPIの変更
BasicBlocks::Cfgが削除され、ControlFlow::EntryNodeとControlFlow::ExitNodeが追加された。
IfStmt.getCondは非推奨となり、代わりにIfStmt.getConditionが推奨される。IfStmt.getThenとLoopStmt.getBodyの戻り値の型はBlockStmtからStmtに広がった。
ReadArgumentInstructionやSelectInstructionなど、複数のIR命令クラスも削除または統合された。
API名を変えるだけでコンパイルエラーは消えても、グラフの形や返される文の型についての深い前提はそのまま残り得る。
macOS 27とXcode 27でのビルドモードの制約
GitHubの10月9日の解説は、別の環境上の制約を加えた。macOS 27とXcode 27からAppleがx86-64/arm64のマルチアーキテクチャバイナリを提供しなくなり、トレース解析に必要なバイナリがなくなった。
そのためコンパイル言語のautobuildとmanualモードは、Xcodeのバージョンを問わずmacOS 27で、またXcode 27を選んだmacOS 26で非対応となる。これらのモードにはmacOS 26とXcode 26以前が推奨される。
macOSでのbuild mode noneの対応改善は進行中の作業だ。今使える汎用の回避策ではなく、すべてのMacですべてのCodeQL検査ができないという意味でもない。
データベース作成とクエリの意味を分ける二つの関門
移行は二つの関門に分けると扱いやすい。一つ目は、選んだランナー、OS、Xcode、ビルドモードが意図したデータベースを作れるかだ。
見慣れたランナー名より、実際に適用されたバージョンを記録するほうが正確だ。
二つ目は、代表的なテスト入力と既知の検出結果でクエリパックを評価することだ。二つを分ければ、抽出も終わっていないクエリをデバッグしたり、対応ランナーだからとクエリの意味が保たれたと誤解したりせずに済む。
クエリの前提を突くGoの入力
Goのレビューには、クエリが実際に前提とする条件に触れる入力が合う。文の境界をたどるクエリなら、変更後のAPIがBlockStmtではなく一般のStmtを返すケースを入れる。
経路をたどるクエリなら、予想した到達可能な経路と、意図的に到達不能にしたコードを合わせて見る。
アラートの総数だけでは足りない。同じ件数の下で一つが消えて別の一つが現れることもあり、件数の変化が意図した修正である場合もある。
注意点:実行していない検証と抽出の失敗
リリースノートと続く解説はこの移行計画の根拠だが、この記事ではクエリ、抽出器、CIランナーを実行していない。
抽出の失敗は失敗したセキュリティ検査だ。検出結果がないからといって安全なコードとして扱う対象ではない。
クエリのコンパイル成功も互換性検証の一段階にすぎない。
アップグレードの結果は、アラートの件数ではなく、どのデータベースでどの意味の検出が保たれたかで説明できてこそ受け入れられる。
