ObjectSquare [2012 年 9 月号]

[技術講座]


静的解析ツール AdLint (アドリント)

株式会社オージス総研 組み込みソリューション第 1 部
矢野尾 裕
嶋 里江

はじめに

概要

ソフトウェア開発現場では、静的解析ツールによるソースコードの検査が行われています。 しかし、商用の静的解析ツールの多くは高価なため、開発者全員が自由に利用することができず、製品の統合時に品質保証に関する部門がまとめて検査するという運用方法が多く見られる状況です。 そして、統合時の検査で見つかった問題を修正した場合は、再びテストと統合が必要となるため、大幅な工程の手戻りが発生し、またはそれを嫌って致命的でない問題への対応を実施しないということが起こり得ます。

静的解析ツールは、コードレビューを補助するためのツールであり、製品の統合前や実行環境が整う前からコードを検査できるという長所があります。 このような特徴を活かし、効果的にコード品質を向上するためには、開発者ひとりひとりが開発中から頻繁に静的解析ツールによるコードレビューを実施するべきです。

そこで、我々は商用のツールに劣らない機能を持つ静的解析ツールを無償で利用可能なオープンソースソフトウェアとして公開することで、ソフトウェア開発業界のコード品質を底上げする一助となるべく、AdLint を開発しています。

本稿では AdLint について、ツールの概要、現状の課題、及び今後の予定を紹介します。

AdLint(オープンソース)プロジェクト、及びAdquaのご提供は終了しています(2016/1/28更新)

対象読者

本稿は、下記のような悩みを持つソフトウェア開発者を対象とします。

また、AdLint 自体の開発に興味のある方も是非ご一読ください。

1 静的解析ツールとは

1.1 静的解析ツールができること

静的解析ツールとは、一言で表現すると「ソフトウェアに含まれる 不具合の可能性 や、ソフトウェアの 内部品質に関する問題 を知るためのツール」だといえます。

また、静的解析ツールの「静的」という言葉は「テストなどとは違い、ソフトウェアを実際にビルドして実行することなく、ソースコードをもとに問題を解析する」ことを表します。 したがって、ターゲットのハードウェアや、そのシミュレータなどの実行環境が整っていない場合でも、事前にソースコード中の問題を知ることができます。

不具合の可能性とは

不具合の可能性とは具体的に、NULL ポインタの使用や、範囲外の配列インデックスの使用、演算式中の値のオーバーフロー、暗黙の変換による値のラップアラウンド、などといったものの可能性のことで、静的解析ツールによりこれらを知ることができます。

内部品質に関する問題とは

内部品質に関する問題とは具体的に、個々の関数の規模が大き過ぎる、関数内の制御構造が複雑過ぎる、モジュール間の依存関係が強すぎる、などといったもので、ソースコードの保守性や再利用性を損なうような問題を知ることができます。


以上をまとめると、静的解析ツールは 「従来からの開発者が手作業で行っていたコードレビューの活動を一部自動化してくれるもの」 と考えることができます。

1.2 静的解析ツールができないこと

静的解析ツールができないことを前もってお伝えします。

ソースコードの論理的な正しさの検証

ソースコードに実装されたロジックの正しさは、現在の静的解析技術では検証できません。 したがって、ロジックが求める仕様を満たしていることを検証するためには、現状どおり別途テストが必要です。

ソースコードの品質が妥当であるかの判断

ソースコードの品質を知るために、さまざまな視点から定量的な数値を算出することはできますが、その数値が解析対象ソフトウェアにとって妥当であるかは判断できません。

指摘した問題が確実に不具合であることの保証

静的解析ツールは、実際にソフトウェアを実行して解析するものではないので、指摘した問題が実際に不具合として現れるものかは判断できません。 したがって、この点に関しても現状どおり別途テストが必要です。

2 AdLint とは

2.1 AdLint の特徴

静的解析ツールはソースコード品質を向上するために有用ではありますが、商用の静的解析ツールは高価なものが多く、また、無償のものは機能が少なかったり、解析できる内容が限られている、という問題があります。

この問題に対し我々は、商用のツールに劣らない機能を持つ静的解析ツールを独自に開発し無償提供することで、ソフトウェア開発業界のコード品質を底上げしたいという思いから、AdLint を開発しています。

AdLint は、ソースコード中の問題となる可能性がある部分について警告メッセージを出力し、同時に、ソースコード品質に関するメトリクスを測定、また、ソースコードの構造情報を抽出することができます。

無償の静的解析ツール

AdLint は無償で利用できるオープンソースソフトウェアとして GNU GPL バージョン 3 のライセンスで 2012 年 2 月に公開開始しました。 したがって、導入費用を一切必要とせず、組織の開発者全員に気軽に利用していただけます。

(現時点では) C 言語のソースコードを解析可能

現時点では、ANSI C89 / ISO C90 、及び、一部 ISO C99 規格に準拠した C 言語のソースコードを解析可能です。 また、コンパイラ製品独自の拡張機能にも対応できるよう考慮して設計しているので、さまざまなビルド環境やターゲット環境のソースコードでも解析可能です。

100% Pure Ruby

AdLint の開発には、国産のオブジェクト指向スクリプト言語である Ruby を全面的に使用しています。 全てを Ruby で実装しているため、AdLint は Windows や Mac OS X 、Linux など、多くのプラットフォームで利用できます。 また、Ruby はシンプルな文法で非常に生産性の高い言語なので、比較的簡単に AdLint をお客様の組織に合わせてカスタマイズする、といったことも可能です。

AdLint(オープンソース)プロジェクト、及びAdquaのご提供は終了しています(2016/1/28更新)

2.2 AdLint の機能

ソースコード中の問題の可能性を指摘

AdLint は、ソースコード中の問題の可能性を 720 種類の警告メッセージで指摘することができます。 警告メッセージは、現時点では日本語と英語に対応しています。 不具合の指摘方法は、ソースコードの構文を解析することで指摘できる問題だけではなく、「抽象解釈」により制御やデータの流れなど、「プログラムの意味」に基づいた解析を行うことで、より高度でコードレビューでも見落としがちな問題も発見することができます。

ソースコードの品質メトリクスを測定

AdLint は、ソースコード品質に関するメトリクスを測定することができます。 モジュールや関数の規模、関数内の制御構造の複雑度など 15 種類の有用なメトリクスに対応しています。

ソースコードの構造情報を抽出

AdLint は、ソースコードの構造情報を抽出することができます。 ソースコードの構造情報とは、関数や変数の定義、型の定義、関数呼び出しやグローバル変数アクセスによるモジュール間の依存関係など、ソースコードの内容を要約したものです。


2.3 公開後の状況

AdLint は、2012 年 2 月 28 日にバージョン 1.0.0 を公開しました。 機能拡張と不具合修正を継続し、現時点での最新バージョンは 2.0.6 です。

2012 年 8 月末の時点で、総ダウンロード数は 6,000 件を超えています。

日本国内はもちろん、中国、アメリカ、フランス、インドなど、約 40 ヶ国からダウンロードされています。

また、Linux ディストリビューションの Debian GNU/Linux や Ubuntu にも収録を検討していただいてます。

3 AdLint の静的解析技術

AdLint の静的解析エンジンの中心部は「抽象インタプリタ」と呼ばれる機構です。

下図は、静的解析とテストなどの動的解析を含めた、ソースコード解析技術の分類を表しています。

category.png
ソースコード解析技術の分類

図の一番下の矢印が示すように、問題の指摘精度は右に行くほど高くなります。 また、その上の線は、解析技術が静的解析と動的解析のどちらに分類されるものかを表しています。

静的解析と動的解析の大きな違いは、静的解析では解析対象ソフトウェアの実行環境が不要なのに対し、動的解析ではソフトウェアのビルドと実行が必要なため、ターゲットハードウェアやそのシミュレータなどの実行環境が必要な点です。

一般的なオープンソースの静的解析ツールの多くは、図中のピンクの箱で囲まれた字句解析と構文解析による解析をサポートしていますが、これらの解析技術のみでは問題の指摘精度はあまり高くありません。

AdLint は図中の青い箱で囲まれた解析技術を実現しています。 前述の字句解析と構文解析による解析に加え、中心の黒い箱で囲まれた「抽象インタプリタによる解析」をサポートしています。

AdLint の抽象インタプリタは、C 言語の完全なインタプリタをベースに静的解析のための機能を盛り込んだもので、ソースコードの意味論を得るために必要な部分のみを実際にインタプリタで実行します。 実行パスの分岐を抽象化することで、動的解析では難しい、ソースコード中の全実行パスの解析を高速に実行することができます。

3.1 全実行パスを高速に解析

では、AdLint の静的解析エンジンがどのように全実行パスを高速に解析しているかを解説します。

まず、関数毎に全実行パスを洗い出して、その全てを愚直に実行することを考えて見ます。

if-else-stmt-seq.png

このコードのように、関数の最上位ブロックに単純な if-else 文が 32 個並んでいる場合、その関数の全ての実行パス数は 2 の 32 乗 (≒ 42 億) 通り存在することになります。

当然、実行パス毎に 42 億回インタプリタで実行していては、実用的な時間では解析が終わらないことになります。

そこで、AdLint では、インタプリタが辿る実行経路となる「制御側」をブランチするのではなく、変数値などの実行環境側をバージョン管理することで、関数毎に 1 回インタプリタを実行するだけで、デッドコードを除く全ての実行パスの評価を実現しました。

つまり、次のコード中のコメントが示すように、関数の本体を上から下に辿りながら各変数が取り得る値の定義域を追跡する、ということです。

nested-if-stmt.png

AdLint は、このようなアイデアで高速な全実行パスの解析を実現しています。 実際に、ある商用の静的解析ツールと同一条件で解析時間を比較した結果、約 3 倍ほど AdLint の方が高速であることがわかりました。

3.2 コードチェック機能の実装例

ここまでの内容で、AdLint 内部の実装は複雑すぎてカスタマイズするのが難しそうと感じられたかもしれません。 ここでは、具体的に AdLint 内部でコードチェック機能がどのように実装されているかを説明します。

以下が、「ゼロ除算が起こる可能性」をチェックする機能の Ruby による実装です。

W0093.png

1 行目から、コードをチェックするための check メソッドの定義が始まります。 この check メソッドは、AdLint の抽象インタプリタが掛け算系の演算式を実行したときに、コールバックされるよう予め登録されています。

3 行目で、抽象インタプリタが実行した掛け算系の演算式が、除算か剰余であることを判定しています。

そして、割り算が実行された場合は 5 行目で、右辺の値がゼロになることがあるかを判定しています。

右辺値がゼロになる可能性がある場合は、7 行目で W0093 警告メッセージを出力しています。

AdLint の内部は、機能の抽象度により整然としたレイヤ構成として設計しています。 したがって、最上位レイヤに位置するコードチェック機能は、この例のように 10 行にも満たない簡素なスクリプトで実現することができます。

したがって、ユーザー独自のコーディング規約を容易に組み込むことができます。

4 AdLint の展望

4.1 現状の課題

静的解析ツールを既に利用されている方は、身をもって体験されていると思いますが、静的解析ツールには「誤検知」と「検知漏れ」がつき物です。

challenge.png
全ての静的解析ツールの課題

上図の一番上の両端が矢印になっている線は、静的解析ツールの特性を表しています。 右に行くほど「誤検知」が多い、つまり問題でないにも関わらず誤って陽性と判定してしまう、いわゆる false-positive な傾向が強いことを表します。 そして、左に行くほど「検知漏れ」が多い、つまり問題であるにも関わらず誤って陰性と判断してしまう、いわゆる false-negative な傾向が強いことを表しています。

その下の右矢印が示すように、「誤検知」が多すぎると、本当に有用な警告メッセージを探し当てるのが難しく、解析結果の精査に膨大な工数がかかってしまいます。

その下の左矢印が示すように、「検知漏れ」が多すぎると、せっかくツールで解析したのに問題が十分に検知されず、静的解析の意味が無くなってしまいます。

一番下の線は、静的解析ツールのユーザーが感じる満足度を表しています。 当然、「誤検知」率と「検知漏れ」率がバランス良く共にゼロに近いツールが最も問題の検知には効果的で、ユーザーも満足するはずです。

したがって、静的解析ツールにとって「誤検知」率と「検知漏れ」率を共に低くすることが理想となります。 しかし、「誤検知」率と「検知漏れ」率は本質的に反比例するものなので、現実には左右のどちらかに偏った特性を持ってしまいます。

現時点での AdLint は、設計方針として「誤検知より検知漏れの方が悪」と考えているため、図の右側に偏った特性を持っています。

4.2 今後の予定

静的解析ツールはまだ未成熟な分野だと感じており、AdLint や商用の静的解析ツール、学術的な研究成果を含めて、誤検知率と検知漏れ率を下げるための工夫の余地はまだまだたくさんあると考えています。

今後は、AdLint をテストベッドとして、みなさまからのフィードバックをもとに、より静的解析ツールの理想に近づけるよう解析精度を向上していきます。

また、解析結果をソースコード品質の改善に活用しやすくするために、AdLint 自体の操作性向上や周辺ツールの充実なども予定しています。

AdLint(オープンソース)プロジェクト、及びAdquaのご提供は終了しています(2016/1/28更新)

更新履歴


記事の内容を 5 点満点で評価してください。
1 点 2 点 3 点 4 点 5 点
記事に関するコメントがあれば併せてご記入ください。

© 2012 OGIS-RI Co., Ltd.
Prev. Index
PREV INDEX