このセクションの内容

パターンベース解析

パターンベース解析は、CWE や OWASP などのプログラミング規約に基づいて、ソフトウェアの欠陥をもたらすことが知られているコード構造を検出します。パターンベースの静的解析は、開発者がコーディングのベスト プラクティス、単体テストのベスト プラクティス、組織の開発ポリシーに従っていることを保証するのに役立ちます。

すべてのタイプの解析は、ビルトイン テスト コンフィギュレーションまたはユーザー定義テスト コンフィギュレーションを使用して実行されます。参照: テスト コンフィギュレーションの設定

重複コード解析


DTP Engine は重複コードをチェックできます。重複コードはアプリケーションの設計が不適切であることを表す場合があり、保守のコストが増大する可能性があります。重複コードの解析では、コードが小さな言語要素 (トークン) に分解されます。重複と見なすコードを定義したルールのセットに従ってトークンが分析されます。

トークンを解析するルールには次の 2 つのタイプがあります。

  • 文字列リテラルなど、単一のトークンの重複を発見するための単純なルール
  • 重複メソッドやステートメントなど、複数のトークンの重複を発見するための複合ルール

重複コード検出ルールを実行するには、Find Duplicated Code テスト コンフィギュレーションを実行します。

builtin://Find Duplicated Code

メトリクス解析


DTP Engine はコードの複雑性、オブジェクト間の結合、凝集性の欠如などのコードの潜在的な弱点を理解するのに役立つコード メトリクスを計測できます。メトリクス解析ルールを実行するには、Metrics テスト コンフィギュレーションを実行します。

builtin://Metrics

メトリクス解析の結果は、DTP Engine が生成する HTML および XML レポートファイルに追加されます。「レポートの参照」を参照してください。

メトリクスしきい値の設定

上限または下限を指定して、メトリクスが指定された値範囲を超えた場合に静的解析違反をレポートすることができます。たとえば、論理行数を制限する場合、論理行数メトリクスが制限を超えた場合に違反をレポートするよう、Metrics テスト コンフィギュレーションを設定することができます。

Metrics ビルトイン テスト コンフィギュレーションには、デフォルトのしきい値が設定されています。ファイル数 (METRIC.NOF) など、しきい値を設定できないルールもあります。

メトリクスしきい値を設定するには、次の方法があります。

  • DTP のテスト コンフィギュレーション インターフェイスを使用する (詳細については『 Development Testing Platform ユーザーズ ガイド』の 「Report Center」 > 「テスト コンフィギュレーション」 > 「テスト コンフィギュレーションの編集」 > 「[メトリクス] タブ」を参照)
  • IDE のインターフェイスを使用してテスト コンフィギュレーションを編集する (「カスタムテスト コンフィギュレーションの作成」を参照)
  • テスト コンフィギュレーション ファイルを手動で編集する
    1. Metrics ビルトイン コンフィギュレーション ([INSTALL_DIR]/configs/builtin) をユーザー コンフィギュレーション ディレクトリ ([INSTALL_DIR]/configs/user) に複製します。
    2. 複製されたコンフィギュレーションをエディターで開き、[METRIC.ID].ThresholdEnabled プロパティに true を設定します。
    3. 次の書式に従って [METRIC.ID].Threshold プロパティに上限および下限を指定します。
      [METRIC.ID].Threshold=l [lower boundary value] g [upper boundary value] 
    4. テスト コンフィギュレーションを保存し、カスタム メトリクス テスト コンフィギュレーションを使用して解析を実行します。

フロー解析


フロー解析は、静的解析テクノロジの一種です。アプリケーションの実行パスのシミュレーションをはじめ、複数の解析手法を利用して実行時のバグを引き起こす可能性があるパスを特定します。フロー解析が検出するバグには、未初期化メモリの使用、NULL ポインターの間接参照、ゼロによる除算、メモリ リーク、リソース リークなどが含まれます。

フロー解析は複雑なパスを特定してトレースするため、人間によるテストや検査では発見が難しく、静的解析や単体テストでも発見されないことが多いバグを検出します。 コードを実行せずにバグを検出するフロー解析の機能は、特にレガシー コード ベースや組込みコード (つまりそのようなエラーの実行時検出が効果的ではなかったり不可能だったりするコード) に有効です。

 フロー解析ルールを実行するには、解析にフロー解析用テスト コンフィギュレーションのいずれかを実行します。

builtin://Flow Analysis Fast
builtin://Flow Analysis Standard
builtin://Flow Analysis Aggressive

フロー解析エンジンは、解析されたコードからパスを分析し、さまざまな問題を検出します。アプリケーション全体にわたって「実行される可能性があるパス」をすべて解析するのは現実的ではない場合もあるため、解析レベルの深さを設定できます。解析レベルが深いほど、発見される違反の数が増えます。ただし、パフォーマンスが低下し、若干メモリの消費量が増加します。

解析の深さは、DTP でテスト コンフィギュレーション インターフェイスを使用して設定します。Report Center > [テスト コンフィギュレーション] > [静的解析] > [フロー解析詳細設定] > [パフォーマンス] > [解析の深さ] にアクセスし、以下のいずれかのオプションを選択します。

  •  最も浅く (最も高速): ソース コード中の最も明らかな問題だけを発見します。発見する対象は、問題が発生しているコード箇所に「問題の起点」が近い場合だけに制限されます。発見される違反の実行パスは通常、1 つの関数のいくつかの行にわたります。4 以上の関数呼び出しにわたることはまずありません。
  • 浅く (高速): [最も浅く] オプションと同様、ソース コード中の最も明らかな問題だけを発見します。ただし、[浅く] オプションは [最も浅く] オプションよりも多くの問題を検出し、より長いパスを検証できます。
  • 標準: 何十もの要素を含む実行パスにおける、多くの複雑な問題を発見します。[標準] オプションは、[浅く] オプションよりも深い解析を実行するのに加えて、より複雑な問題を探します。たとえば、「不正なフローのために1 つの関数で発生する問題」や、「解析対象プロジェクト中の異なる箇所にある異なる関数間で不適切なやり取りがあるために発生する問題」などです。多くの場合、[標準] オプションが発見する違反は、解析対象ソース コード中の重要なバグを明らかにし、そのコード行は何十行にも及びます。
  • 深く (低速): [標準] オプションで定義されているのと同等の複雑さと性質の問題を、より多く検出できます。 ただし、解析速度は [標準] オプションよりも遅くなります。
  • 徹底的 (より低速): より複雑な問題を発見します。コードベースを徹底的に解析するため、時間を必要とします。しかし、アプリケーション中の異なる場所にある何百行というコードに違反パスがわたるような、非常に複雑な問題を数多く発見します。このオプションは夜間のテスト実行で使用することを推奨します。

デフォルトの解析レベルの深さは [標準] です。

タイムアウトの方針の設定

解析レベルの深さの他に、フロー解析エンジンはタイムアウト設定を利用して、妥当な時間内で解析が終了するようにします。タイムアウトの設定を行うには、DTP でテスト コンフィギュレーション インターフェイスを使用します。Report Center > [テスト コンフィギュレーション] > [静的解析] > [フロー解析詳細設定] > [パフォーマンス] > [タイムアウトの方針] にアクセスし、以下のいずれかのオプションを選択します。

  •  時間: 指定時間が過ぎると、指定したホットスポットの解析が停止します。注意:このオプションを選択すると、レポートされる違反件数がやや不安定になる場合があります。
  •  インストラクション: フロー解析エンジンのインストラクションの実行回数が指定の回数を超えると、指定したホットスポットの解析が停止します。注意: 環境に合った適切なインストラクション数を決定するには、生成されたレポートの [セットアップの問題] セクションでタイムアウト情報を確認してください。
  •  オフ: タイムアウトしません。注意: このオプションを選択すると、解析が終了するまで時間がかかる場合があります。

デフォルトのタイムアウト オプションは [時間] であり、タイムアウト秒数は 60 秒です。解析中に発生したフロー解析タイムアウトについての情報を得るには、解析後に生成されるレポートで [セットアップの問題] セクションを確認してください。

解析データのスワップを有効にしたフロー解析の実行

スワップ モードでは、解析データをハードディスクに書き込みます。解析データのスワップは、インクリメンタル解析と同じ永続性記憶装置を使用し、インクリメンタル解析と似たプロセスで実行されます。大きなプロジェクトで解析を実行する場合、解析するソース コードの意味論的モデルを表す解析データが、フロー解析が使用できるすべてのメモリを消費する可能性があります。この現象が発生した場合、フロー解析は現在必要ない解析データをメモリから削除し、後でディスクから再び読み込みます。

一般的に、  Xmx JVM オプションを使って JVM ヒープのサイズを大きくして


を実行することを推奨します。これはスワップを最小限にするためであり、結果としてパフォーマンスが向上します。充分なメモリがある場合、解析データのスワップは無効化しても構いません。スワップを無効化すると、コード解析の速度が上がる場合があります。

スワップ モードを有効化/無効化するには、DTP のテスト コンフィギュレーション画面を使用します。

ディスクへの解析データのスワップを有効化:デフォルトで無効 

です。大量のメモリを必要としない小さなサイズのプロジェクトに対してフロー解析を実行する場合、または 64-bit システムのように十分なメモリがある場合、このオプションを無効化すると、解析のパフォーマンスが向上する場合があります。

フロー解析の冗長性の設定

DTP のテスト コンフィギュレーション画面では、次のオプションを設定できます。

  • 原因が特定できない場合は違反をレポートしない   原因を表示できない場合に違反をレポートするかどうかを指定します。 一部のフロー解析ルールでは、フロー解析はあるポイントに至るすべての可能なパスをチェックし、すべてのパスについて特定の条件が満たされることを検証する必要があります。そのような場合、1 つの違反が複数のパスに関連付けられます (単純なケースでは、1 つの違反が 1 つのパスによって表されます)。そのような違反のすべてのパスは、違反のすべてのパスに共通する違反ポイントで終わります。ただし、別のパスがコード中の別のポイントで開始する可能性もあります。各パスの開始点が違反の原因 (コード中のポイント。それよりも後の違反ポイントのコードで特定の条件の違反を規定する) です。「複数パスの違反」でパスによって原因が異なる場合、フロー解析は違反のポイントだけを表示します (違反の原因は表示しません)。違反の原因から違反ポイントまでの完全なパスが表示される通常のケースと比較すると、違反ポイントだけの違反は、理解しにくい場合があります。そのため、違反の原因を表示できない場合に違反を非表示にするこのオプションが用意されています。
  • 疑わしいポイントごとに違反を 1 つだけ表示    1 つの疑わしいポイントにつき、( 1 つのルールに対する) 1 つの違反だけをレポートします。たとえば、null 値のソースが複数ある null 間接参照の可能性が検出された場合、1 つの違反だけがレポートされます。このオプションを選択すると、 フロー解析のパフォーマンスが若干速くなります。

null チェック メソッド

[null チェック メソッド] オプションを指定すると、メソッドに null パラメーターが渡されたときに返す期待値を指定できます。そのため、偽陽性が減少するほか、null 変数の値が不明なときに通常作成される過剰なパスが減少します。

[有効 ] チェックボックスをオンにして、以下の情報を指定します。

  • 完全修飾型名(ワイルドカード)    メソッドを含む型の完全修飾名を指定します。
  • メソッド名     メソッド名を指定します。
  • Null の場合の戻り値    メソッドに null パラメーターが渡されたときに返される値を指定します。
  • + サブクラスの定義    サブクラス中の null チェック メソッドの定義も、null チェック メソッドとして見なすかどうかを指定します。

null チェック メソッドの例

フロー解析は解析スコープでメソッドを解析します。たとえばサード パーティのライブラリなど、現在の解析スコープの外にメソッドがある場合、null チェック メソッドでパラメーターを指定する必要があります。この例のクラス  Account および AccountManager は、別のアセンブリに定義されており、解析スコープの外にあります。AccountManager クラスは、静的メソッドを使って次のように Account クラスをチェックします。 

public class Account
    {
        public int Balance { get; set; }
    }

    public class AccountManager
    {
        public static bool IsNullOrEmpty(Account account)
        {
            return account == null || account.Balance == 0;
        }
    }

そして、フロー解析の ルール BD.EXCEPT.NR ルールによって解析される次のクラスがあります。

public class SomeClass
{
    void SomeMethod()
    {
        Account account = null;
        //some other actions
        if (!AccountManager.IsNullOrEmpty(account))
        {
            Console.WriteLine(account.Balance);
        }
    }
}

フロー解析は メソッド IsNullOrEmpty() の戻り値が不明であると仮定します。その理由は、このメソッドは解析スコープ中にないからです。フロー解析は if ブランチを解析し、それらの文の 1 つで違反を発見します。しかし、変数が null の場合、IsNullOrEmpty() メソッドの呼び出しは true を返します。
null チェック メソッドのメソッド リストに AccountManager.IsNullOrEmpty() を追加して戻り値を指定することで、追跡された変数がこのメソッドに渡されたときにフロー解析は違反をレポートしなくなります。なぜなら、if ブランチが解析されず、その結果として偽陽性が回避されるからです。

null チェック メソッドの制限事項

null チェック メソッドのパラメーターに追加されるメソッドは、単純な Bool 型の戻り値を持つ、static メソッドであるべきです。 この制限事項は、パラメーター指定が複雑になり過ぎることを防ぎ、null チェック メソッドの結果に影響しかねない変数が他にないことを保証します。

リソースの指定

[リソース] タブでは、BD.RES (リソース) カテゴリのルールを使ってチェックするリソースを定義することができます。BD.RES カテゴリのルールは、[リソース] タブで定義および有効化されているすべてのリソースについて、リソースが正しく使用されているかをチェックします。

  1. [リソースのタイプ] に名前を入力します。
  2. [有効] チェックボックスをオンにします。
  3. 適切な場合、[アプリケーション終了時の違反をレポートしない] オプションをオフにします。
  4. 矢印をクリックして [リソース アロケーター] および [リソース クローザー] タブを開き、表示されたテーブルにリソースのアロケーター/クローザーの情報を入力します。詳細については以下のセクションを参照してください。


リソース アロケーターの設定

[リソース アロケーター] テーブルには、リソースを生成するメソッドの記述を入力できます。テーブルには以下の列があります。

  • 有効    解析中にアロケーターを考慮するかどうかを指定します。
  • 完全修飾型名または名前空間 (ワイルドカード)    メソッドが宣言された型または名前空間の完全修飾名です。任意の型 (または名前空間) で宣言された関数、また型や名前空間の外で宣言されたグローバル メソッドを指定するには '*' を使用します。
  • メソッド名 (ワイルドカード)     アロケーター メソッドの名前を指定します。任意の数の任意の文字を表すには '*' を使用します。
  • リソース パラメーター     メソッドが リソースを割り当てる1つ以上のパラメーターを指定します。パラメーターの位置 (1 から開始) を指定するか、アスタリスク (*) を指定して、すべてのパラメーターにリソースを割り当てます。
  • + サブクラスの定義    サブクラス中の (指定された名前の) アロケーター メソッドの定義も、アロケーター メソッドとして見なすかどうかを指定します。 この設定は、インスタンス メソッドと非インスタンス メソッドの両方に適用されます。
  • "this" オブジェクトが リソース    メソッドが呼び出されたオブジェクトのリソースを割り当てることを示します。
  • リソース オブジェクトを返す     メソッドが割り当てられたリソースを返すことを示します。

一般的に、アロケーター メソッドはエラー コードを返してリソース割り当ての失敗を表します。アロケーター メソッド はリソースへのポインターを返し、通常 NULL ポインターはリソース割り当ての失敗を表します。リソース リークを探すときに、フロー解析はリソースの割り当てが成功したか失敗したかを把握できる必要があります。これは、割り当てが実際に発生したパス上で発見されないクローザー メソッドへの呼び出しだけをフロー解析がレポートするのに役立ちます。リソース アロケーター関数がリソースへのポインターを返し、このポインターが NULL でない場合、フロー解析はリソースが正常に割り当てられたと推測します。

リソース クローザーの設定

[リソース クローザー] テーブルには、リソースをクローズするメソッドの記述を入力できます。テーブルには以下の列があります。

  • 有効    解析中にクローザーを考慮するかどうかを指定します。
  • 完全修飾型名または名前空間 (ワイルドカード)    メソッドが宣言された型または名前空間の完全修飾名です。任意の型 (または名前空間) で宣言されたメソッド、また型や名前空間の外で宣言されたグローバル メソッドを指定するには '*' を使用します。
  • メソッド名 (ワイルドカード)     クローザー メソッドの名前を指定します。任意の数の任意の文字を表すには '*' を使用します。
  • + サブクラスの定義    サブクラス中の (指定された名前の) クローザー メソッドの定義も、クローザー メソッドとして見なすかどうかを指定します。 この設定は、インスタンス メソッドと非インスタンス メソッドの両方に適用されます。
  • "this" オブジェクトが リソース    メソッドが呼び出されたオブジェクトのリソースをクローズすることを示します。
  • リソース パラメーター     メソッドが リソースをクローズする1つ以上のパラメーターを指定します。パラメーターの位置 (1 から開始) を指定するか、アスタリスク (*) を指定して、すべてのパラメーターがリソースをクローズすることを示します。





  • No labels