4 モダン技術:テスト自動化

この資料はテスト技法セミナーのスライドに関する補助資料です.目次は右側に表示されます.

概要

  1. テストハーネス系のテスト自動化
  2. ターゲット環境の仮想化技術
  3. ファズテストの原理と,盛んになった背景・歴史
  4. ファズテストの進化
  5. 静的解析
  6. 動的解析の種類と役割

4.1 テストハーネス系のテスト自動化

― JUnit などのユニットテスト技術の背景・歴史・仕組み・代表的製品(組込み寄り)


1.背景:なぜユニットテスト技術が必要になったか

ソフトウェア開発が複雑化するにつれ,手動テストの限界が明確になりました.

  • コード変更の影響範囲が広く,人手で毎回確認するとコストが高い
  • バグが早期に検出されず,修正コストが上昇
  • 組込みソフトではハード依存のため再現が難しい
  • CI/CD の登場で,変更ごとに自動検証する流れが必須に

こうした課題の中で,プログラム自体がテストを持ち,自己検証を行うという発想が確立され, JUnit を中心に「xUnit テストフレームワーク」が標準化しました.


2.ユニットテスト技術の歴史

1990年代初期:テストの自動化が少ない時代
  • 手動テストが主流で,テストコードを書く文化はほぼなかった.
  • 組込みではベアメタル環境での手動デバッグが中心だった.
1997:SUnit(Smalltalk Unit Test)誕生

Kent Beck が Smalltalk のオブジェクト指向開発支援として SUnit を開発. これが xUnit 系フレームワークの祖となる.

1999:JUnit の登場

Erich Gamma と Kent Beck により JUnit が Java 向けとして登場.

  • テストコードをクラスとして書く
  • 期待値と実行結果を assert 系 API で比較
  • 全テストの自動実行
  • グリーン/レッドバーによる可視化

JUnit の成功により,多くの言語で xUnit が派生した. 例: CppUnit, NUnit, PyUnit, RubyUnit など.

2000年代:TDD(テスト駆動開発)とアジャイルの普及
  • テストコードを先に書く TDD の普及によりユニットテストが開発標準に.
  • リファクタリングと回帰テストが高効率化.
  • 組込みでは host-side テストとして採用され始める.
2010年代:CI/CD と自動化パイプラインの一般化
  • Jenkins, GitLab CI, GitHub Actions などでユニットテストが必須タスクに.
  • 組込みでもホストテスト→ターゲットテストの2段構成が一般化.

3.ユニットテストの仕組み

(1) テストコード (Test Case)
  • 各関数・クラスに対して期待値を定義したテストメソッドを作成.
  • assertEquals などの assert API を使用して合否判定を自動化する.
(2) テストランナー (Test Runner)
  • すべてのテストケースを自動収集して実行.
  • 成功/失敗を集約してレポート化.
  • CI 上で自動実行される.
(3) テストフィクスチャ (Test Fixture)
  • テスト前後に実行されるセットアップ/ティアダウン処理.
  • 組込みの I/O モジュールなどはモック化して切り替える.
(4) モック / スタブ / フェイク

ハード依存処理や外部APIの代わりに模擬オブジェクトを用いてテスト可能化する.

  • モック:呼び出し確認や期待動作を設定
  • スタブ:簡易返り値のみ返す
  • フェイク:軽量実装を提供

組込みではモック生成自動化ツールが重要.


4.代表的なユニットテストフレームワーク(組込み寄り)

1.Ceedling(C言語、Unity + CMock)
  • 組込みC向けの事実上のスタンダード.
  • Unity: 軽量ユニットテストフレームワーク
  • CMock: モック自動生成
  • Ceedling: ビルド・テスト実行・レポート一体化
  • Makefile や CMake と相性良く,ホスト環境でも動作する.
2.CppUTest(C/C++)
  • 組込み用途を重視した軽量 xUnit 系フレームワーク.
  • メモリリーク検出やテスト結果のシンプル表示が特徴.
  • プラットフォーム非依存で小型ターゲットに向く.
3.GoogleTest / GoogleMock(C++)
  • 非常に豊富なアサートとモック機能.
  • 大規模 C++ に強い.
  • 組込みでもホストテストやPCシミュレーションで使われる.
  • ただしメモリフットプリントは大きめ.
4.Tessy(商用テストツール)
  • 目的は 組込みターゲットでのユニット・モジュールテスト
  • C/C++のコード解析,テストケース生成,ターゲット実行を統合.
  • 特に自動車・医療・産機など安全規格対応で利用される.
  • ISO 26262 / IEC 62304 などの適合性支援が強い.
5.Parasoft C/C++test(商用)
  • 静的解析 + 単体テスト + カバレッジを統合したツールチェーン.
  • 組込みコンパイラ対応が充実.
  • エンタープライズ向けで品質管理機能が豊富.
6.VectorCAST(商用)
  • 自動コード計測とテスト実行が可能.
  • 目標:ミッションクリティカルシステムの単体/結合テスト自動化.
  • カバレッジ分析,ハーネス自動生成が強力.

5.組込み開発でユニットテストを適用するときの課題と解決策

課題1:ハードウェア依存部が多く,ホストで動かない

→ I/O 部分を抽象化し,モック生成ツールを併用する. → Ceedling + CMock の自動モック生成が有効.

課題2:レガシーコードはテストハーネスが書きづらい

→ 依存関係を切り出すリファクタリングを小さく積み上げる. → 「継承より委譲」や抽象インターフェース化が有効.

課題3:メモリやフラッシュが小さいターゲット

→ ホストPCでテスト,必要部分のみターゲットで実行する2段構成. → CppUTest など軽量フレームワークを使う.

課題4:安全規格準拠が必要

→ Tessy, VectorCAST, Parasoft など認証支援製品を利用. → テストエビデンス(トレース,レポート)の自動生成が重要.


6.ユニットテスト技術の位置づけ

ユニットテストは「レガシー」ではなく, 現代の自動テスト文化の基盤技術であり,ファズテスト・動的解析・静的解析を支える根幹です.

  • 小さな単位の確実な品質保証
  • 回帰テストの自動化
  • 継続的インテグレーションの中心
  • 安全性規格への適合性証跡の提供

こうした役割により,組込みを含むあらゆる開発で必須技術として位置づけられています.


4.2 ターゲット環境の仮想化技術

QEMUとは:背景と目的

QEMU(Quick Emulator)は,オープンソースの高速エミュレータ/仮想化基盤であり,異なるCPUアーキテクチャ間の実行を可能にするために開発された.Linuxカーネル開発者として知られる Fabrice Bellard によって 2003 年頃に公開され,その後は大規模なコミュニティによって改良が続けられている.当初は「異種アーキテクチャ向け」コード実行が主目的だったが,現在では KVM との統合で高速なハードウェア仮想化基盤としても利用される.


QEMU誕生の背景

1. 異なるCPUアーキテクチャ開発の困難さ

組込み機器やサーバ,デスクトップなど,多様なアーキテクチャ(x86, ARM, MIPS, PowerPC など)が存在しており,実機が高価・入手困難という課題があった.QEMU はこれをソフトウェアで再現し,どんなCPUのバイナリでもどんなホスト上で実行できるという開発者のニーズに応えた.

2. OS開発・ブートローダ開発のための仮想環境

OSや低レベルソフトウェアの開発にはハードウェア挙動の精密なエミュレーションが必須であり,QEMU はディスク,ネットワーク,PCI デバイス,シリアルコンソール等の再現に強みを持つ.特に Linux カーネル開発者にとって重要なツールとなった.

3. 仮想化技術の進化

2008 年以降,KVM (Kernel-based Virtual Machine) との連携により,QEMU は エミュレーションだけでなく仮想化プラットフォームとしても主流になった.以後,Red Hat 系を中心にクラウド基盤(OpenStack など)で広く使われている.


QEMU の主な仕組み

1. TCG(Tiny Code Generator)による動的バイナリ翻訳

QEMU の心臓部は,TCG と呼ばれる小型 JIT コンパイラである. 仕組みは次の通り:

  • ゲスト CPU 用の命令を解析
  • TCG 中間コードへ変換
  • ホスト CPU 用のネイティブ命令へ JIT コンパイル
  • キャッシュして高速に実行

これにより,異種アーキテクチャでありながら実用的な速度を達成している.

2. デバイスモデルのエミュレーション

QEMU は以下をソフトウェアで再現する:

  • 仮想CPU
  • メモリ・MMU
  • PCI / USB / VGA / NIC
  • ストレージ(IDE, SCSI, Virtio など)

特に Virtio は QEMU/KVM のために設計された高速I/O仮想化標準であり,クラウド基盤で広く使われている.

3. KVM によるハードウェア支援仮想化

KVM を有効にすると:

  • ゲストOSはホストCPU上でほぼネイティブ実行
  • QEMU はデバイスモデルと制御ループに専念

これにより VMware や VirtualBox と同等の性能を発揮できる.


QEMUがもたらした影響

1. 組込み開発の効率化

ARM,RISC-V,MIPS などの実機がなくても OS やファームウェアを開発・デバッグできるようになった.特に RISC-V エコシステム拡大に大きく寄与した.

2. クラウド基盤の標準技術

OpenStack,oVirt,Proxmox など多くの仮想化・クラウド基盤で QEMU/KVM が標準として使われている.

3. セキュリティ研究

マルウェア解析やOS脆弱性検証において,安全に隔離した環境を提供するため,サンドボックスとしても利用される.


まとめ

QEMU は「異種アーキテクチャ実行のためのエミュレータ」として生まれたが,現在では 汎用ハイパーバイザとしても不可欠な存在となっている.TCG による動的翻訳,豊富なデバイスモデル,KVM との統合という3つの柱により,研究,開発,クラウド,セキュリティと幅広い分野で活躍している.


Docker / Docker Compose と KVM の違い(要点だけ)

1. 役割の違い
技術 何をするものか
KVM 仮想マシン(VM)を動かすための「ハイパーバイザ」.完全なOSを丸ごと仮想化.
Docker OS上で動作するアプリケーションを「コンテナ」として軽量に実行.
Docker Compose 複数コンテナをまとめて定義・起動するための管理ツール.

2. 仮想化レイヤの違い

KVM
  • ハードウェアレベルで仮想化
  • 1台のPC上に 複数の仮想マシンを作り, 各VMの中で 別々のOS(Linux/Windowsなど) が動く
  • 完全な隔離・本物のマシンに近い動作
Docker
  • OSレベルでの軽量な仮想化
  • 「プロセスの隔離」で動く
  • OSカーネルを共有する(Linuxカーネルを共用)

3. 重さ(オーバーヘッド)の違い

KVM
  • OSごと仮想化 → 重い
  • メモリ・CPUを VM ごとに確保する
  • 起動も比較的遅い(数秒〜数十秒)
Docker
  • OSのプロセス隔離 → とても軽い
  • 数百MB どころか数十MBのコンテナも普通
  • 起動は一瞬(0.1秒〜1秒程度)

4. 用途の違い

KVM が向く場面
  • 異なるOSを動かしたい(Linux & Windowsなど)
  • 完全な隔離が必要(セキュリティ)
  • OSレベルのテスト(カーネル開発・デバイスドライバ)
  • クラウド基盤(OpenStackなど)
Docker が向く場面
  • アプリケーションを軽くて速く配布したい
  • マイクロサービス構成
  • CI/CD,開発環境の統一
  • Webサーバやデータベースを複数組み合わせて動かす(Docker Compose)

5. Docker Compose は何をする?

Docker Compose は 「複数のコンテナを 1つのアプリとしてまとめるツール」 例:

  • web コンテナ
  • db コンテナ
  • redis コンテナ
  • nginx コンテナ

などを docker-compose.yml に書くと, docker compose up 1コマンドで全部起動できる.


まとめ(最も短い説明)

  • KVM = 仮想マシン。OSを丸ごと動かす仮想化。重いが強力。
  • Docker = コンテナ。アプリだけを隔離して動かす。軽い。
  • Docker Compose = 複数のコンテナをまとめて管理するためのツール。

目的が全く違うため,

  • OSレベルのテスト → KVM
  • Webアプリ構成・開発環境 → Docker/Compose という使い分けになる.

4.3 ファズテストの原理と,盛んになった背景・歴史

ファズテストとは

ファズテスト(fuzz testing, fuzzing)は,ソフトウェアに大量の無作為または変異させた入力データを投げ込み,クラッシュや例外,未定義動作を誘発させることで脆弱性やバグを検出するテスト手法です. 通常のテストでは想定しない異常系入力を自動生成できるため,セキュリティ分野を中心に広く利用されています.


ファズテストの原理

ファズテストは基本的に次の構造で成り立っています.

  1. 入力生成器(Generator)

    • ランダム入力
    • 既知の入力に小さな変異を加える(Mutation fuzzing)
    • プロトコル仕様に沿った構造化データを生成(Generation-based fuzzing)
  2. ターゲット実行器(Executor)

    • 生成した入力を対象プログラムに高速に注入し,実行させる.
    • クラッシュ,assert失敗,例外,タイムアウトなどの挙動を監視する.
  3. フィードバック(Feedback loop)

    • 実行トレースやカバレッジ情報を利用し,より多くのコードパスに到達する入力を学習し続ける.
    • 代表的技術: Coverage-guided fuzzing (AFL系)

このフィードバック型ファズテストにより,探索効率が劇的に向上し,手作業では見つけにくい脆弱性を大量に発見できるようになりました.


ファズテストが盛んになった背景

1. セキュリティ脆弱性の深刻化

インターネット普及とともに,バッファオーバーフローや整数オーバーフローなど典型的なメモリ破壊バグが悪用されやすくなりました. ファズテストはこれらの脆弱性を低コスト・自動的に発見できるため重要性が増しました.

2. OSS の巨大化・複雑化

Linuxカーネル,OpenSSL,ブラウザなど大規模OSSの品質確保が重要になり,GoogleやMicrosoftは大規模ファジング基盤(ClusterFuzz, OneFuzz)を構築しました. OSSプロジェクトはCIにファジングを組み込み,品質向上サイクルに組み込むようになりました.

3. 計算資源の向上とクラウド化

ファズテストは大量の試行が必要ですが,クラウドの並列計算環境により大規模分散ファジングが容易になり,適用範囲が飛躍的に広がりました.

4. カバレッジ指向ファジング(CGF)の登場

2013年に公開された AFL(American Fuzzy Lop) が革命的でした. AFLはプログラムのコードカバレッジを計測し,未到達パスを探索するよう入力を自動進化させることで,非常に効果的なファジングを実現しました. この成果により,ファズテストは研究者だけでなく一般開発者にも普及しました.


ファズテストの歴史

出来事
1988年 Barton Miller らが「Fuzz Generator」実験を実施,UNIXコマンドにランダム入力を与えて多くのクラッシュを発見.ファジングの起源とされる.
1990年代 プロトコルファジング,ファイル形式ファジングが研究分野として成長.
2000年代初頭 Microsoft, CERT/CC がファジング研究を強化.Windows向けのプロトコルファズツールが登場.
2013年 AFL公開.カバレッジ指向ファジング革命が起こる.
2016年以降 Google OSS-Fuzz が稼働し,多くのOSSで継続的ファジングが実施される仕組みが普及.
2020年以降 クラウドネイティブファジング,AI支援入力生成,コンコリックテストとのハイブリッド手法が実用化.

4.4 ファズテストの進化

(1)黒箱・灰色箱・白箱ファジングの登場と高度化

ファズテストは対象システムへの理解度とフィードバック量に応じて進化してきました.

黒箱ファジング (Black-box fuzzing)

  • 仕組みを知らずにランダム入力を投げる初期型.
  • 実装依存の情報が得られないため探索効率は低い.
  • しかしプロトコルや外部サービスに対しては今でも有効.

灰色箱ファジング (Grey-box fuzzing)

  • AFLやlibFuzzerが代表で,実行時のコードカバレッジを取得し,入力を最適化する.
  • パフォーマンスと探索効率のバランスが良く,現在もっとも広く使われている方式.
  • 対象に軽い計測器(instrumentation)を挿入するだけで適用可能.

白箱ファジング (White-box fuzzing)

  • ソースコードやバイナリを解析し,制御フローを理解した上で入力を生成する方式.
  • 後述のシンボリック実行やSMTソルバを使うものが多い.
  • 精度は高いが計算コストも大きいため,ハイブリッド化が主流.

(2)コンコリックテスト(Concolic Testing)との統合

コンコリックテストは,Concrete + Symbolic の融合で,実行可能経路を狙い撃ちするテスト方法です. 近年はファジングと統合され,お互いの弱点を補う進化を遂げています.

  • ファジングは広く浅く探索するが,深い経路条件で失速しやすい.
  • シンボリック実行は狙ったコード分岐に到達可能だが,状態爆発で計算が重い.

両者を統合することで

  • ファジングで探索しながら,行き詰まった分岐だけシンボリック実行で突破
  • SMTソルバで条件を満たす入力を生成し,ファジングのシードに追加 といった形で,より深いカバレッジを達成している.

代表例:

  • Driller (AFL + angr)
  • QSYM (lightweight symbolic execution)
  • S2E (Selective Symbolic Execution)

(3)動的解析ツールとの連携

ファズテストは動的解析ツールと組み合わせることで検出力が拡大しました.

ASan(AddressSanitizer)

  • メモリ破壊バグ(バッファオーバーフロー,Use-after-free)を高感度で検出.
  • libFuzzerやAFLとの併用が標準になっている.

UBSan(UndefinedBehaviorSanitizer)

  • C/C++の未定義動作(整数オーバーフロー,シフト異常)を捕捉.
  • 安全性の高い入力生成に役立つ.

MSan(MemorySanitizer)

  • 未初期化メモリアクセスを検出.

これらのサニタイザはクラッシュを引き起こさない潜在バグも検出できるため,ファジングの有効範囲を大きく広げた.


(4)継続的ファジングとCI/CDへの統合

Google OSS-Fuzz 以降,ファズテストは継続的テスト(Continuous Fuzzing)として組み込まれるようになった. 特徴は次の通り.

  • CIでビルドすると自動的にファジングが開始する.
  • 24時間×365日でクラウド上のファズ基盤が実行.
  • バグを検出すると自動レポートと再現用最小入力を生成.
  • OSSプロジェクトでは品質向上と脆弱性発見が劇的に進んだ.

例:

  • Google OSS-Fuzz
  • Microsoft OneFuzz
  • GitHub Actions を用いた軽量ファジング設定

(5)構造化ファジングとスキーマ対応ファジングの発展

初期のファジングはバイト列中心だったが,現在は構造化データが主流.

  • JSON,XML,protobuf,ASN.1
  • 画像フォーマット(PNG, JPEG)
  • 圧縮・アーカイブ形式(zip, gzip)
  • ネットワークプロトコル(TLS, HTTP2)

ファジングエンジンは

  • データモデルを理解した入力変異
  • 仕様を反映した生成ベース入力作成 が可能になり,複雑な仕様実装の欠陥検出が容易になった.

代表例: libprotobuf-mutatorPeach FuzzerBoofuzz


(6)クラウドネイティブ・分散ファジングへの進化

近年はクラウドリソースを活用した大規模分散ファジングが一般化した.

  • 数千コアによる高速並列ファジング
  • 自動スケールアウト
  • 結果を集約するダッシュボード
  • コンテナ化で再現性を確保

OSS-FuzzやOneFuzzだけでなく,社内向けの自動ファジングシステムを構築する企業も増えている.


(7)AI支援ファジング (AI-assisted fuzzing)

最新の研究では,大規模言語モデル(LLM)や深層学習を組み合わせたファジングが登場している.

  • LLM による構造化入力の推定・生成
  • 実行ログを読ませて未到達部分の推測
  • バグクラッシュログの自動分類・分析
  • 深層学習で分岐条件を推定する「Neural Fuzzing」

まだ実験段階だが,高度な仕様理解やより効率的な探索が期待されている.


4.5 静的解析

静的解析の背景と歴史

初期の背景:安全性と信頼性要求の高まり

1990年代以降,自動車,医療,産業機器,航空宇宙などでソフトウェアが急速に複雑化し, 「バグは現場での事故につながる」という課題が顕在化した. 特に C 言語はメモリ管理を手動で行う必要があり,多くの組込み製品で利用されているため, 品質ルールの標準化が求められた.


MISRA-C の登場(1998〜)

MISRA-C は自動車産業の団体 MISRA により策定された「安全な C コーディング規約」であり, C の危険な機能を制限し,安全性と可読性を向上させる目的で誕生した.

  • 1998年 MISRA-C:1998
  • 2004年 MISRA-C:2004
  • 2012年 MISRA-C:2012(現在主流)
  • 2023年 MISRA C++ と統合的運用もされつつある

MISRA は静的解析ツールと強く結びついており,多くのツールが MISRA 対応を売りにした.


コベルティ(Coverity)以降:本格的なバグ検出へ(2002〜)

2002年,スタンフォード大学の研究プロジェクトから生まれた Coverity により, 静的解析は「形式的解析」から「実用的なバグ検出ツール」へ進化した.

Coverity の革新点は以下の通り.

  • 抽象解釈(Abstract Interpretation)を高度化し,大規模コードでも実用的な速度を維持.
  • C,C++ の深い制御フロー,データフローを解析して NULL参照,メモリ破壊などを高精度で検出.
  • Linux カーネルを解析し,実際に多数のバグが発見されたことで有名に.

これ以降,静的解析は「高精度なバグ検出装置」として産業界で急拡大した.


静的解析の技術的仕組み(簡易)

静的解析はソースコードを実行せずに解析する技術であり,主に以下の手法が組み合わされる.

  1. 字句解析・構文解析(Parsing) C/C++ の構文を理解し,AST(抽象構文木)を構築する.

  2. 制御フロー解析(CFG) if/while/switch などをつないだ制御フローダイアグラムを生成する.

  3. データフロー解析 変数の値の流れ(def-use)を解析し,未初期化,NULL参照を検出する.

  4. 抽象解釈(Abstract Interpretation) 値を「抽象領域」に写像して解析し,

  • ゼロ割り
  • バッファオーバーフロー
  • 整数オーバーフロー などを推定する.
  1. パターンマッチング(コーディング規約チェック) MISRA-C,CERT-C,企業独自ルールなどをチェックする.

メジャーな静的解析製品と特性

1. Coverity(Synopsys)

  • 高精度のバグ検出が最も評価されている.
  • 大規模プロジェクトにも強く,CI/CD と統合しやすい.
  • コストは高いが完成度は業界トップクラス.

2. Polyspace(MathWorks)

  • 抽象解釈をベースに ゼロ割りやオーバーフローを数学的に証明する点が特徴.
  • 自動車や航空など高安全性領域で利用される.
  • 色分けされた証明結果がわかりやすい.

3. QA·C / QA·C++(Perforce / 元 PRQA)

  • MISRA-C 対応では業界最古参かつ信頼性が高い.
  • コーディング規約の遵守チェックに特化.
  • 組込み企業で広く採用されている.

4. clang-tidy / clang static analyzer(オープンソース)

  • LLVM ベースで軽量かつ高速.
  • モダンC++向けチェックに強い.
  • CI との相性が良く,現代的環境で普及.

5. PVS-Studio

  • C/C++/C#/Java まで対応する多言語ツール.
  • コメントに警告を埋め込む独自スタイルが特徴.
  • 開発速度が速く,モダン言語仕様への追従性も良い.

6. Klocwork(Perforce)

  • 大規模コードの高速スキャンに強い.
  • セキュリティルール(CWE, CERT)対応が豊富.
  • coverity より軽く,組込みでもよく使われる.

まとめ

  • 静的解析は安全性要求の高まりから誕生し,MISRA-C により標準化が進んだ.
  • Coverity 以降,バグ検出精度が飛躍的に向上し,実開発で不可欠なツールとなった.
  • 近年は CI/CD に組み込んで 定期的に全コードをスキャンする DevSecOps の一要素となっている.
  • ツールごとに「規約チェックに強い」「数学的証明に強い」「大規模プロジェクトに強い」など特色が異なる.

4.6 動的解析の種類と役割

動的解析(dynamic analysis)は,プログラムを実際に実行しながら動作を観測し,バグや脆弱性,パフォーマンス問題を検出する手法です. 静的解析では発見できない実行時依存の問題を扱えるため,ファズテストと並んで品質保証の重要な柱となっています.


(1)サニタイザ系動的解析(SAN 系)

C/C++を中心に広く使われる,実行時に異常動作を検知するための軽量インストルメンテーション. ファズテストと組み合わせると,クラッシュしない潜在バグまで高精度に検出できる.

AddressSanitizer (ASan)

  • バッファオーバーフロー
  • ヒープのUse-after-free
  • スタック外/ヒープ外アクセス を検出する. 低オーバーヘッドで精度が高く,ファズテストの標準構成となっている.

UndefinedBehaviorSanitizer (UBSan)

  • 整数オーバーフロー
  • ゼロ除算
  • シフトの未定義動作 など,C/C++の未定義動作を検出. クラッシュを伴わないバグの発見に有効.

MemorySanitizer (MSan)

  • 未初期化メモリの読み取りを検出.
  • セキュリティ上極めて危険なバグを早期発見できる.

ThreadSanitizer (TSan)

  • データ競合(race condition)
  • ロック順序の問題 など並行バグを検出.

(2)プロファイラ系動的解析

主にパフォーマンス改善やボトルネック分析に使用される. 性能要件の診断に不可欠で,テスト中の挙動把握にも役立つ.

CPU プロファイラ

  • どの関数が CPU 時間を消費しているか
  • ホットパスの特定 例: perf, gprof, VTune

メモリプロファイラ

  • メモリ使用量の推移
  • リーク検出 例: Valgrind massif, heaptrack

I/O プロファイラ

  • ディスクアクセスやネットワークトラフィックを計測.
  • 遅延の根本解析に使われる.

(3)トレーシング系動的解析

プログラムの実行過程を詳細に記録し,制御フローやシステムコールの履歴を把握する手法. デバッグ,高度な障害解析,セキュリティフォレンジクスに用いられる.

システムコールトレーシング

  • strace, dtruss などでシステムコールを記録.
  • 入出力の順序や失敗の原因を特定できる.

関数トレーシング

  • eBPF / ftrace を用いて関数呼び出しの流れを監視.
  • 実行パスを詳細に復元可能.

動的バイナリ計測 (DBI)

  • Pin, DynamoRIO などのフレームワークを使い,任意の命令単位で計測を挿入.
  • きめ細かい解析が可能だがオーバーヘッドは大きめ.

(4)メモリチェッカ・動的検証ツール

実行時の正確なメモリ動作を追跡し,不正アクセスやリークを検出する. サニタイザより詳細で強力だが,オーバーヘッドは高い.

Valgrind / Memcheck

  • メモリリーク
  • 不正メモリアクセス
  • 未初期化値使用 を高精度に検出. テスト対象を小規模に絞って使うと効果的.

Dr. Memory

  • Windows/Linux対応のメモリチェッカ.
  • Valgrindより軽量な場合もある.

(5)動的モデル検査(Dynamic Model Checking)

プログラムを実行しながら状態空間を探索する. 並行プログラムのデッドロックや競合検出に特に強い.

代表例:

  • CHESS(Microsoft)
  • Inspect
  • スケジューラを操作し並行バグを確実に再現する技術が中核.

(6)ファジングとの相性と役割の違い

技術 特徴 ファジングとの相性
サニタイザ系 欠陥を即時検知 最強の組み合わせ
プロファイラ 性能ボトルネック調査 カバレッジ向上のためのヒント取得
トレーシング 実行パスの深い理解 クラッシュ再現性向上
メモリチェッカ 高精度検査 少数ケースを重点検査
動的モデル検査 並行バグ検出 入力生成と併用で強力

動的解析は,ファズテストが発見したクラッシュの原因分析カバレッジ向上の支援にも大きく貢献する. 両者を組み合わせることで,セキュリティバグからパフォーマンス問題まで広範にカバーするテスト戦略が実現できる.


4.7 まとめ

  • モダンテスト技法は,現代も進化中
  • 専門性が高くなっている