インテル® C++ コンパイラー XE 13.1 ユーザー・リファレンス・ガイド

スタティック解析の概要

スタティック解析とは、ソースコードの詳細な解析を通じてソフトウェアのエラーとセキュリティーの脆弱性を発見するプロセスです。スタティック解析には、インテル® Parallel Studio XE 製品またはインテル® C++ Studio XE 製品が必要です。解析自体はコンパイラーで行われ、解析結果はインテル® Inspector XE GUI で表示されます。解析を任意のマシンで行い、別のマシンで結果を表示できます。この場合、解析マシンではコンパイラーのみインストールされていれば問題ありません。表示するマシンには、コンパイラーとインテル® Inspector XE がインストールされている必要があり、また有効なインテル® Parallel Studio XE またはインテル® C++ Studio XE ライセンスが必要です。

スタティック解析では、アプリケーションのセキュリティーを突破したり、あるいはアプリケーションを機能不全にするような攻撃者に悪用される可能性のある幅広い範囲のエラーを見つけられます。検知されるエラーには、バッファー・オーバーフロー、ポインターとヒープストレージの誤用、C/C++ または Fortran 言語機能の安全ではない使用、あるいは誤った使用、そして OpenMP* およびインテル® Cilk™ Plus 並列プログラミング構造の誤用などがあります。

スタティック解析により行われる解析の種類と使用方法についての詳細は、インテル® Inspector XE のドキュメントを参照してください。

スタティック解析では、インテル®コンパイラーで重大なエラーなくコードがコンパイルされている必要があります。

スタティック解析は、OS X* システムではサポートされていません。

プロダクション・バイナリーのビルドにインテル® コンパイラーを使用する予定がない場合でも、スタティック解析を使用することができます。 同様に、インテル® コンパイラーでサポートされていないプロセッサーの種類で動作するプログラムにも使用できます。

スタティック解析の動作

コンパイラーは特殊なモードで動作して、要求された解析を実行します。このモードでは、コンパイラーは解析により時間をかけ、命令生成プロセス全体を省略します。これにより、通常のコンパイルでは検知されないエラーを発見することができます。つまり、コードは、インテル® コンパイラーで重大なエラーなくコンパイルされている必要があります。ただし、コンパイルの結果は実行できません。 したがって、プロダクション・バイナリーのビルドにインテル® コンパイラーを使用する予定がない場合でも、スタティック解析を使用することができます。

スタティック解析は最初に、それぞれのソースファイルを個別に処理し、擬似オブジェクト・モジュールを生成します。実際のオブジェクト・モジュールを壊さないように、スタティック解析で生成される擬似オブジェクト・モジュールは実際のオブジェクト・モジュールとは分けられています。

解析結果はリンク段階で生成されます。これは、最終命令がリンク段階でのみ生成されるプロシージャー間の最適化 (IPO) の動作と似ています。これにより、スタティック解析でプロシージャーとファイル境界にわたるエラーを発見できます。 これは、直接リンカーを起動するのではなく、コンパイラーによりリンク段階を起動しなければならないことを意味します。

スタティック解析モード

スタティック解析は、セキュリティーの脆弱性や論理エラーが存在するという決定的でない証拠を検出する場合があります。その場合、ツールの正しい動作というものはありません。サイレントリスクの検出漏れが生じる (つまり、実際のエラーが検出されない) 一方、誤検出の診断メッセージが出力されます。これに対応するため、スタティック解析は 3 つの解析モードを提供しています。最適なモードは、状況と目的に依存します。

  • [Full (フル)]: プログラムのすべての脆弱性を検出し、誤検出の可能性が高くなります。このモードは、セキュリティーを確保する場合に使用します。リリースされる製品にセキュリティーの脆弱性が存在することによる潜在的なコストを考えれば、誤検出の調査にかかる余分な作業時間を正当化できるでしょう。インテル® Inspector XE の GUI は、大規模な結果に対処し、誤検出であると確認された同様のエラーを排除するためのさまざまな手法を提供します。
  • [Concise (簡潔)]: より多くの検出漏れを許容することで誤検出を減らします。このモードは、一般的なエラーを検出する場合に使用します。検出漏れの可能性がわずかに高くなることと引き換えに誤検出の調査にかかる時間が短縮されることを考慮して、慎重に検討する必要があります。このモードでは、信頼度アルゴリズムにより、診断結果が正しいかどうか評価します。信頼度が非常に低い場合は、その診断結果はすべて排除されます。そうでない場合は、信頼度に応じて診断結果の重み付けが調整されます。これにより、影響が小さくても実際にエラーである可能性が高い診断結果の方が、影響が大きくても実際にエラーである可能性が低い診断結果よりも重視されます。

  • [Precise (厳密)]: 誤検出を最小限に抑えつつ、有益なレベルのエラー検出を提供します。このモードは、一般的なエラーを検出する場合に使用します。このモードにより、ソースバージョンの検査判定を迅速に下すことができます。誤検出を最小限に抑えるため、検出されるエラーの数と種類が大幅に減ります。ただし、誤検出が少なくなることで、解析結果の調査を効率良く行うことができます。また、ソース変更をソースコード管理レポジトリーに受け入れる前に、このモードでクリーンな解析結果を要求するプロジェクト・ポリシーを設定すると合理的でしょう。

解析モードは、diag-enable:sc-{full|concise|precise} オプションを使用して指定します。

スタティック解析: プログラム全体と単一ファイル

スタティック解析は、プログラム全体または単一ファイルに対して行うことができます。指定するコンパイラー・オプションにより、スタティック解析で各ソースファイルを個別に処理するかどうかを指示します。プログラム全体の解析をスキップすると、大規模なプログラムでメモリーの使用と解析時間を抑えることができますが、検出される実際のエラーは少なくなります。

多くのエラーは、グローバルなプログラム全体の解析を通してのみ検出することができます。単一ファイルの解析ではこれらのエラーを検出することができません。一方、非常に大きなプログラムでは、プログラム全体の解析に長い時間がかかります。単一ファイルの解析を使用することで、解析にかかる時間を大幅に減らし (数時間から数分に短縮できることもあります)、より頻繁に解析を実行することができます。コストの低い早期に不具合を検出し修正できるため、これはコスト効率の良い方法と言えます。

一部のファイルでは、単一ファイルの解析に長い時間がかかることがあります。多数の小さなファイルからなるプログラムの場合、各ファイルを個別に処理するよりも、いったんすべてをメモリーに読み込んでしまったほうが速くなります。その場合、単一ファイルの分析はその利点が得られないため使用すべきではありません。

単一ファイルの解析は、diag-enable:sc-single-file オプションを使用して指定します。

スタティック解析と列挙型の変数

スタティック解析には、列挙型の変数を関連する列挙リテラルと等しい既知の値として扱うオプションがあります。デフォルトでは、スタティック解析は不明な列挙型の変数を不明な整数値として扱います。

このオプションを有効にすると、より多くのエラーが検出されますが、誤検出の可能性が高まります。

次のプログラムについて考えてみます。

typedef enum {red = -1, yellow = 0, blue= 1} color;
volatile int v1;
volatile color v2;
int x[10];
int f() {
    int y1 = v1;
    int y2 = v1;
    color y3 = v2;
    if ((y2 >= -1) && (y2 <= 1))
       return (x[y1] + x[y2] + x[y3]);
    else return 0;
}

このプログラムは、不明な値のソースとして volatile グローバル変数を使用します。不明な値が発生する場合はほかにもあります。

3 つの配列インデックスの操作のいずれも、境界違反を引き起こす可能性があります。

  • スタティック解析は、x[y1] をレポートしません。 y1 は全く不明な整数値なので、このインデックス操作をレポートする理由がありません。

  • スタティック解析は、x[y2] をレポートします。 "if" 文により y2 の値は {-1,0,1} に制限されますが、この値のいずれかが境界違反を引き起こします。 これは論理エラーの可能性が高いものとしてレポートされます。

  • 3 つ目のインデックス x[y3] は、やや不明瞭です。 "if" 文がないため、開発者の意図が不明です。y3 は列挙型として宣言されているため、y3 の値は {-1,0,1} に制限されます。 このような場合はエラーが存在するという根拠が乏しいため、x[y3] のような配列のインデックス操作は、sc-enum オプションが有効な場合のみレポートされます。

列挙型の扱いは、diag-enable:sc-enums オプションを使用して指定します。

スタティック解析と SAL

インテル® コンパイラーは、Microsoft* の標準ソースコード注釈言語 (SAL) をサポートしています。SAL は、ソース形式で提供されていない外部ルーチンへの呼び出しを静的にチェックできます。サブルーチンの宣言に正しい使用方法を示す SAL マクロを付けられます。

コンパイラーは、スタティック解析を有効にしてコンパイルしない限り、すべての注釈を無視します。スタティック解析が有効な場合、SAL 注釈によって示された制限の違反が診断されます。

SAL 注釈の詳細は、Microsoft* Visual C++* のドキュメントを参照してください。

スタティック解析の推奨事項

スタティック解析を使用するために、インテル® C++ コンパイラーでビルドを行うようにアプリケーションを変換する必要はありませんが、インテル® コンパイラーとのソースレベルの互換性は必要です。インテル® C++ コンパイラーでまだビルドを行っていない場合は、移植ガイドラインに従ってください。 インテル® C++ コンパイラーは、Microsoft* Visual C++* コンパイラーと GNU* コンパイラーの両方と互換性があるため、ほとんどのアプリケーションでは互換性の問題は発生しません。

スタティック解析は、完全なプログラムで最も効果を発揮します。これは、問題の中にはソースファイル間の対話を解析することによりのみ検知できるものがあるためです。スタティック解析を部分的なプログラム、あるいはより少ないモジュールをリンクして単一ファイルでも実行可能です。 単一ファイルの解析オプションを使用して、処理速度を向上することもできます。ただし、この場合、プログラム全体の解析なら発見できるような問題を検知できないことがあります。常にはプログラム全体の解析を使用しない場合であっても、プログラムエラーの検出漏れがないように、定期的にプログラム全体の解析を行ってください。

スタティック解析をライブラリーに対してビルド、リンクを行うプロジェクトで使用する場合、そのライブラリーにリンクするプロジェクトを解析する前にライブラリーを解析してください。 解析済みのライブラリーにリンクするプロジェクトを解析する際、ライブラリー・ソースがあたかもアプリケーションの一部であるかのように、ライブラリーのモジュールは完全に解析に含められます。

ライブラリー自体を解析すると、そのライブラリー内の問題のみが診断されます。コンパイル段階中に生成された擬似オブジェクト・モジュールは、標準的なライブラリアン・ユーティリティーを使用して、スタティック・リンク・ライブラリーに結合できます。ダイナミック・ライブラリーの解析時に、スタティック・ライブラリーは通常のエクスポート・ライブラリーの代わりに、リンク段階中に生成されます。解析されないライブラリーへのリンクも許可されていますが、解析されていないライブラリーは解析には含まれません。

多くの場合、スタティック解析は [Precise (厳密)] モードで開始すると良いでしょう (diag-enable:sc-precise)。そうすることで、最も明白な問題を素早く見つけることができます。その後、より強力な解析モードに移ることができます。

列挙型変数のより厳密なチェックにより、その他のエラーが検出されることがありますが、誤検出の可能性も高くなります。diag-enable:sc-enums オプションを使用すべきかどうか判断するには、まず diag-enable:sc-enums を指定せずにスタティック解析を実行し、その後、ソース変更をしないで再度 diag-enable:sc-enums を指定して解析を実行します。 新しい問題がいくつか見つかった場合は、それらを調査します。新しい問題が多数見つかった場合は、このオプションは使用しないほうが良いでしょう。

関連情報


このヘルプトピックについてのフィードバックを送信