このセクションの内容 :

フロー解析の使用と静的解析によるバグの検出

 

このセクションでは、フロー解析を実行してバグを検出する方法について説明します。たとえば、未初期化メモリの使用、NULL ポインターの間接参照、ゼロによる除算、メモリ リーク、リソース リークなどです。

重要

フロー解析を使用するにはオプションの BugDetective ライセンスが必要です。  

フロー解析の実行

フロー解析は新しい静的解析テクノロジーです。フロー解析は、アプリケーションの実行パスをシミュレートして、実行時のバグ ( 未初期化メモリの使用、NULL ポインターの間接参照、ゼロによる除算、メモリ リーク、リソース リーク ) につながるパスを自動的に特定します。

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

フロー解析の動作と利点の詳細については 「 データフロー解析による静的解析」 を参照してください。

ヘッダーのテスト

C++test は、テスト対象のソース ファイルがヘッダーをインクルードしていない限り、ヘッダーを直接テストしません。

詳細については 「ヘッダー ファイルを解析するには ? どのファイルが解析されるのか ?」 を参照してください。  

テンプレート関数のテスト

C++test は、インスタンス化された関数テンプレートとインスタンス化されたクラス テンプレートのメンバーに対して静的解析と単体テストを実行できます。

詳細については 「C++test でのテンプレート関数のサポート」 を参照してください。  

フロー解析を実行するための基本的な操作手順は次のとおりです。

  1. フロー解析の解析を実行するテスト コンフィギュレーションを選択します。  
  2. 選択したテスト コンフィギュレーションを使ってテストを開始します。  
  3. 結果をレビューします。  
  4. 必要に応じてフロー解析の設定をカスタマイズします。  

cpptestcli によるコマンドライン モードでのフロー解析の実行

定期的にコマンドラインでフロー解析の解析を実行するには、チームにとって重要なルールを選択したフロー解析テスト コンフィギュレーションを使ってプロジェクトを解析します。

たとえば:

 

コマンドラインからのテストの詳細については 「 コマンドライン インターフェイスからのテスト」 を参照してください。

インクリメンタル解析モードでのフロー解析の実行

デフォルトでは、フロー解析は実行対象のスコープの完全解析を実行します。大規模なコード ベースの場合、この解析にはかなりの時間がかかることがあります。

フロー解析を実行する最も一般的な方法は、毎日わずかに変化する 1 つのコード ベースに対して夜間テストを実行することです。インクリメンタル解析モードの目的は、この一般的なフロー解析の解析にかかる時間を短縮することです。 インクリメンタル解析モードのフロー解析では、1 回目の実行中に重要な解析データが記憶され、2 回目以降のテストで再利用されます。再解析は、変更されたコードおよび変更されたコードに密接に関係するコードにだけ実行されます。

インクリメンタル解析を実行するときは次の点に注意してください。

インクリメンタル解析モードはテスト コンフィギュレーションの [静的] タブで設定できます。設定の詳細については 「フロー解析オプションの設定」を参照してください。

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

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

一般的に、 Xmx JVM オプションを使って JVM ヒープのサイズを大きくして C++test を実行することを推奨します。これはスワップを最小限にするためであり、結果としてパフォーマンスが向上します。

充分なメモリがある場合、解析データのスワップは無効化しても構いません。スワップを無効化すると、コード解析の速度が上がる場合があります。解析データのスワップを無効化する方法については、 「[パフォーマンス] タブ」の [ディスクへの解析データのスワップを有効化] の説明を参照してください。

フロー解析ビルトイン テスト コンフィギュレーション

Flow Analysis Fast

Fast には、セキュリティ ルールおよびカスタマイズが必要なルールを除き、すべてのフロー解析ルールが含まれます。Fast は解析の深さとして「最も浅い」を使用するため、 Standard や Aggressive (下記を参照) よりも早く実行します。Fast は適度な量の問題を発見し、違反の数が爆発的に増えるのを防ぎます。新しいプロジェクトでフロー解析ルールを推進するために Fast を 使用することを推奨します。より厳密な解析が必要な場合は、Standard に切り替えることを検討してください。

Flow Analysis Standard

Standard には、カスタマイズが必要なルールを除き、すべてのフロー解析ルールが含まれています。Standard は Fast よりも深い解析を実行するためFast よりも多くのバグを発見する可能性があります。また、Standard は Fast よりも長い実行時間を必要とします。より多くのバグを発見することの方が優先順位が高い場合、Standard に切り替えることを推奨します。解析パラメーターを再定義したりルールを再構成する必要がある場合、Standard を元にしてユーザー定義テスト コンフィギュレーションを作成できます。

Flow Analysis Aggressive

あらゆる疑わしいコードについて違反を検出したい場合、Aggressive の使用を推奨します。Aggressive は、たとえ「偽陽性」がレポートされるかもしれない場合でさえも、問題が疑われる場合に必ず違反をレポートします。Aggressive を使用すると、より多くのバグがレポートされますが、「実際には違反ではないケース」のレポートも増える可能性があります。

フロー解析のスコープ

フロー解析は、解析するために選択したファイルのスコープ内で、関数、クラス、名前空間、コンパイル単位の境界を超えて解析を実行します。 関数の呼び出しが存在し、その関数が別のファイルで定義されている場合、そのファイルが解析スコープに含まれている限り、フロー解析は関数内のパスを追跡できます。そのため、解析の精度はスコープに大きく依存します。

解析スコープ定義する (どのファイルを 1 セッションで解析するかを選択する) ための一般的なガイドラインは次のとおりです。

フロー解析の結果の参照

このセクションでは、フロー解析でレポートされたバグを解析する方法について説明します。

解析結果へのアクセス

フロー解析の結果は、通常の静的解析違反と共に [品質タスク] ビューに表示されます。たださし、その内容と形式は通常の静的解析違反とかなり異なります。フロー解析の結果は、ルール カテゴリと重要度で分類されたタスク リストとしてレポートされます。解析結果を重要度で表示するには、[品質タスク] ビューのプルダウン メニューをクリックし、[表示] > [詳細] をクリックします。

GUI からテストを実行した場合、ルールの違反は [品質タスク] ビューの「静的解析違反の修正」カテゴリにレポートされます。

コマンドライン インターフェイスから実行した場合、ルールの違反はレポートの「静的解析」セクションにレポートされます。解析結果を Team Server に送信した場合は、『Parasoft Test ユーザーズ ガイド』の「ワークフローと使用法」>「GUI へのテスト結果のインポート」 にあるように解析結果を GUI にインポートできます。インポートした解析結果は [品質タスク] ビューの「静的解析違反の修正」カテゴリに表示されます。

レポートされたバグの詳細情報

レポートされたバグについての詳細情報を参照するには、[品質タスク] ビューでバグ メッセージを右クリックし、ショートカット メニューの [ルール ドキュメントの参照] をクリックします。右クリックするのは、黄色の注意アイコンがあるノードです。

違反からのテスト コンフィギュレーションの参照

[ 品質タスク] ビューの違反から、その違反を検出したテスト コンフィギュレーションを表示できます。違反を右クリックし、ショートカット メニューの [テスト コンフィギュレーションの参照] をクリックします。

テストのカスタマイズを担当し、不適切なルールをすぐに無効化したいグループ アーキテクトにとって、違反からテスト コンフィギュレーションにすぐにアクセスできるのはとても便利です。また、サーバー ベースの実行からテスト結果をインポートする開発者も、違反を検出したテスト コンフィギュレーションをレビューしなければならない場合があります。

フロー パスとは

フロー解析の違反は、[品質タスク] ビューで階層的なフロー パスによって表現されます。このパスは検出された問題につながるコードを正確に表します。フロー パス中の各要素は実行時に実行された各コード行です。フロー パス中に関数呼び出しがある場合、その関数呼び出しを表す要素の下のサブノードは関数内の実行フローを表します。フロー パスの最後の要素は常にバグが出現したポイントです。最終ポイントでなぜバグが出現しているのかを説明するために、完全なパスが表示されます。

 

 

フロー パスの要素はアイコンでマークされ、このアイコンは例外処理の動作を説明するのに役立ちます。パス中に、throw 文かまたはそのパスで例外をスローする関数呼び出しがある場合、その throw 文または関数呼び出しのパス要素は、赤い球体のアイコンでマークされます。赤い球体のアイコンは、フローが正常に進まないことを表します。

フロー パスの要素上にマウス ポインターを置くと、違反に関連する変数がツールチップとして表示されます。たとえば NULL ポインターの間接参照の違反の場合、フロー パスのどのポイントでどの変数が null 値を持っているかがツールチップとして表示されます。

 

レポートされた実行パスに関連するコード間を移動するには、[品質タスク] ビューの ツールバーの [次のタスク] または [前のタスク] ボタンをクリックします。

フロー解析の実行後にソース コードを変更した場合、次の処理が行われます。

  • フロー解析の違反は元のフロー パスのソース コードを使用し続けます。このため、確実に有効な違反パスが表示されます。
  • フロー パス中の要素が古い場合 ( つまり解析されたソース コードに現行のソース コードが一致しない場合 )、その要素 (および違反ノード) には特別なアイコンとツールチップが表示されます。また、関連するソース コードにアクセスできないため、要素をダブルクリックしてソース コードを表示する機能は使用不可になります。

パスには省略 (...) が含まれることがあります。これは、 違反の原因から違反のポイントにつながる、異なる複数のパスがあることを表します。

デフォルトでは、解析結果は簡略パス トレースで表示されます。簡略表示では、欠陥のあるパス中の重要な実行可能ステートメントだけが表示されます。このため、レポートされるさまざまな問題の概要をすぐに把握することができます。詳細については 「パス トレースの簡略表示と詳細表示」 を参照してください。

重要な要素の特定

発見された違反に対して重要なパス要素は、濃色のボールのアイコンでマークされます。重要なパス要素の上にカーソルを置くと、その要素が重要な理由がツールチップに表示されます。たとえば、 「NULL の代入箇所」、「重要なデータ フロー」、「重要なデータ フローを含む (重要な要素を持つメソッド呼び出しノードに対する出力)」 などです。

重要な要素には、違反の原因と違反のポイントが該当するほか、違反につながるデータを持つ変数リストを変更する要素が該当します。

たとえば、次のサンプル コードで変数 "a" が null ポインターを持つ場合:

1: b = a;
2: c = k;

行 1 は、後で変数 "b" で違反が発見される場合に重要です。そのため、重要な要素としてマークされます。

行 2 は、不正なデータを持つ変数に関係していないため、重要な要素としてマークされません。

違反の原因と違反のポイント

違反自体は、2 つのマークされたポイントを持つ実行パスとして表現されます。

レポートされた違反 ( 黄色の注意アイコンがあるノード) を右クリックして [違反の原因を表示] または [違反ポイントを表示] を選択するだけで、違反の原因と違反のポイントに簡単にアクセスできます。たとえば、「null 値の間接参照」 ルールの違反では [違反の原因を表示 (Null の代入ポイント)] および [違反ポイントを表示 (NullDereferencing ポイント)] コマンドが表示されます。

違反メッセージが参照しているコードをハイライト表示する

違反メッセージをダブルクリックするだけで、フロー解析違反メッセージが参照しているソース コードを簡単にハイライト表示できます。フロー パスが水色にハイライト表示された状態で、選択した違反に対応するソース コードが表示されます。違反にとって重要なすべての行、つまり違反の原因、違反のポイント、および重要なデータ フローは、濃い色でハイライト表示されます。

 

レポートされた実行パスに関連するコード間を移動するには、[品質タスク] ビューのツールバーの [次のタスク] または [前のタスク] ボタンをクリックします。

ヒント

  • チェック対象から除外するルールは無効にしたり抑制したりできます。詳細については「[静的] タブ - 静的解析の方法を定義する」 を参照してください。
  • C++test に付属の静的解析ルールについては、[Parasoft] メニューの [ヘルプ] をクリックして『Parasoft C++test 静的解析ルール ガイド』ブックを参照してください。

 

パス トレースの簡略表示と詳細表示

簡略表示と詳細表示の違い

デフォルトでは、解析結果のパス トレースは「簡略表示」で表示されます。簡略表示では、欠陥のあるパス中の重要な実行可能ステートメントだけがビューに表示されます。このため、レポートされるさまざまな問題の概要をすぐに把握することができます。

問題についてより詳しい内容を知りたい場合は、「詳細表示」にして完全なパスを表示できます。詳細表示にした場合、 検出されたバグが出現しているとフロー解析が見なした実行パスのすべての要素がタスク ノードに表示されます。言い換えると、フロー解析はこのバグに至る完全な実行パスを表示します。ユーザーは、発見された問題についての完全な情報を得ると共に、フロー解析が行った推測を得ることができます。ときには、フロー解析がこの問題をレポートした理由を知るために、詳細情報が必要不可欠なこともあります。

ほとんどの場合、レポートされた問題を理解するために詳細情報は必要ないかもしれません。そのような場合は簡略表示の方が便利です。簡略表示では、 検出されたバグが出現しているとフロー解析が見なした実行パスの中から、最も重要なものだけがタスク ノードに表示されます。フロー解析は、次の実行パス要素を重要な要素として扱い、簡略表示でレポートします。

次の図は「簡略表示」の例です。

 

次の図は「詳細表示」の例です。


 

ソース コード エディターで詳細な実行パスを確認する

[品質タスク] ビューを簡略表示にして最重要な要素だけを表示している場合でも、違反を選択すると、すべてのパス要素がハイライト表示され、対応するコードが IDE のソース コード エディターに表示されます。したがって、簡略表示によって問題を直ちに見極めた後、違反の発生原因について詳しい情報を得たければ、ソース コード エディターで詳細な実行パスを確認することができます。

詳細表示に設定する

特定の違反の詳細情報を表示するには、次の操作を行います。

常に詳細表示にするには、次の設定を行います。

  1. [Parasoft] メニューの [設定] をクリックします。
  2. 左側のリストから [品質タスク] を選択します。
  3. [フロー解析の違反の完全なパスを表示する] チェックボックスをオンにします。 

 
フロー解析のカスタマイズ

 

このセクションでは、フロー解析をカスタマイズする方法について説明します。検出するバグを指定する方法、ルール パラメーター、解析オプション、および特定のルールでチェックするリソースを指定する方法について説明します。

検出するバグの指定

フロー解析が検出するバグの種類は、通常の静的解析とほぼ同様に、テスト コンフィギュレーションで有効化されたルールによって決定されます。1 ルールあたりレポートされるタスクの最大数など、基本的な静的解析の設定は通常の静的解析とフロー解析のデータフロー解析の両方に適用されます (基本的な静的解析の設定については「[静的] タブ - 静的解析の方法を定義する」を参照してください)。

たとえば、フロー解析ルールを有効化/無効化するには、テスト コンフィギュレーションの [静的] > [ルール ツリー] タブでルールのチェックボックスのオン/オフを切り替えます。

ルール パラメーターの指定

一部のルールではパラメーターを指定することができます。つまり、プロジェクトのニーズに合わせてユーザーがルールをカスタマイズできます。そのため、フロー解析は特定の API の使用に関連する違反でも検出できます。

ルール パラメーターの詳細については 「ルール パラメーターのカスタマイズ」を参照してください。

未検証の違反をレポートする

共通のルール パラメーターの 1 つが [未検証の違反をレポートする] です。

このパラメーターがどのように動作するかを説明するために、まず違反を発見してレポートするプロセスを見てみましょう。まずフロー解析は違反の原因 (不正なデータまたは疑わしいデータが発生しているポイント) から開始し、違反のポイント (不正なデータまたは疑わしいデータが、危険または疑わしい操作で使用されているポイント) で終了するパスを探します。ルールに違反するそのようなパスを発見すると、フロー解析は通常、違反パスの最上位レベルの関数 (他の関数を呼び出す可能性がある、違反パスの階層表現での最上位レベルの関数) からパスが到達可能かどうかを検証することで、違反を検証しようとします。

たとえば次のコードは、完全に 1 つの 関数内に違反のパスがある単純なケースです (違反のパスから他の関数は呼び出されません)。
 

typedef struct SomeStruct {
    int hashCode; 
} SomeStruct;
extern SomeStruct* getObject();
void check(int initialized)
{
    SomeStruct* obj; 
    if (initialized) {
	obj = getObject();
    } else {
	obj = 0;
    }
    int hashCode = 0;
    // some other actions
    if (initialized) {
	hashCode = obj->hashCode;
    }
    // some other actions
}

フロー解析がこのコードを解析すると、次の違反がまず発見されます。

.C program.c (12): obj = 0; // Null value carrier: obj
.  program.c (14): int hashCode = 0; // Null value carrier: obj
.  program.c (16): if (initialized) { // Null value carrier: obj
.P program.c (17): hashCode = obj->hashCode; // Null value carrier: obj

次の段階は、違反のパスが関数の先頭から到達可能かどうかをチェックして、違反を検証することです。この段階でフロー解析は "initialized" が false の場合にだけ "obj" に null 値を代入できることを判断します。ただしこの場合、間接参照が発生している行は到達できません。これは、違反の最上位レベルの関数の先頭からパスが到達可能かを検証することで、違反のパスの検証がどのように「偽陽性」を排除するのに役立つかの一例です。一方、最上位レベルの関数の先頭からパスが到達可能であったなら、違反のパスの検証をパスするでしょう。そして詳細パス モードでは、「パスが到達可能ではない可能性がある」とフロー解析が判断した理由を説明するために、最上位レベルの関数の先頭から開始して、完全なパスと共に違反が表示されます。

複雑なケースでは、解析の深さの設定によって、フロー解析の違反パス検証の処理が終了しない場合があります (解析の深さの制限は、解析速度を適切なレベルに保つために使用されます)。そうなったとき、違反は未検証のままになり、対応する関数から到達可能かどうかがフロー解析には分かりません。この場合、違反がレポートされるかどうかを [未検証の違反をレポートする]パラメーターが決定します。このオプションを有効にすると、フロー解析が発見する欠陥の数が増えますが、「偽陽性」の数も増えることがあります。

フロー解析オプションの設定

テスト コンフィギュレーションでは、基本的な静的解析の設定に加えて、解析の深さ、マルチスレッド API のサポート、違反のレポートの冗長性といったフロー解析固有のオプションを設定できます。[静的] タブの [フロー解析オプション] タブで設定します。

[フロー解析オプション] タブは次のタブから構成されます。

 

[パフォーマンス] タブ

[冗長性] タブ

[冗長性] タブでは次のオプションを設定できます。

例 - [原因が特定できない場合は違反をレポートしない] の影響

次のサンプル コードに対して BD-PB-DEREF ルールを実行した場合、[原因が特定できない場合は違反をレポートしない] オプションが無効な場合にだけ、複数の原因を持つ違反がレポートされます。

#include "stdio.h"
enum Figures {
    SPHERE,
    CIRCLE,
    CUBE,
    SQUARE, 
    HIMESPHERE
};
static void guessFigure(int round, int volumetric)
{
    int figure;
    if (round && volumetric) {
	figure = SPHERE; /* CAUSE 1 */  
    } else if (round && !volumetric) {
	figure = CIRCLE; /* CAUSE 2 */
    } else if (!round && volumetric) {
	figure = CUBE; /* CAUSE 3 */
    } else {
	figure = SQUARE; /* CAUSE 4 */
    }
    switch (figure) {
	case SQUARE:
		printf("This is a sphere");
		break;
	case HIMESPHERE:
		printf("This is a hemispere");
		break;
	case CIRCLE:
		printf("This is a circle");
		break;
	case CUBE:
		printf("This is a cube");
		break;
	default:
		printf("This is a square");
		break;
    }
}

[ターミネータ] タブ

アプリケーションの実行を終了させるターミネータ関数を定義できます。

C/C++ プログラミングでは、回復が不可能な致命的なエラーが発生した場合に、関数を使ってアプリケーションの実行を終了させることがあります。たとえば標準ライブラリの abort() や exit() といった関数です。フロー解析はアプリケーションの実行フローを解析するため、アプリケーションを直ちに停止して実行フローをブレークするターミネータ関数を把握することは、フロー解析にとって非常に重要です。ターミネータ関数を把握していない場合、フロー解析がアプリケーションについて誤った推測を行う可能性があります。

フロー解析は、標準ライブラリで定義されたターミネータ関数を認識します。独自のターミネータ関数をアプリケーションで使用している場合、[ターミネータ] タブのリストにそのターミネータ関数を追加します。ターミネータ関数をリストに追加しない場合、ターミネータ関数による実行パスについてフロー解析が誤った結果をレポートする (本当は違反ではないものを違反としてレポートする) 可能性があります。

次の指定を行って、ターミネータ関数を定義します。

[マルチスレッド] タブ

[マルチスレッド] タブでは、既知のマルチスレッド関数を有効化/無効化するだけでなく、スレッド間の同期化のための関数を定義することができます。このタブで定義した情報は、BD.TRS (スレッドと同期化) カテゴリのルールに影響します。BD.TRS カテゴリのルールは、[マルチスレッド] タブで定義および有効化されているすべての関数をチェックします。

サポートされる API のチェックボックスをオンにして、さまざまな API の同期化関数を有効化するだけでなく、同期化関数を含むユーザー独自の API からの関数を有効化することもできます。特定のライブラリの同期化関数についての情報を追加するには、[追加] ボタンをクリックし、ライブラリの名前を入力して Enter キーを押します。新しいエントリが API のリストに追加されます。次に、エントリをクリックして [編集] ボタンをクリックします。表示されたダイアログで、特定の同期化関数を定義します。このダイアログでは次の種類の関数を定義することができます。

これらの関数を定義する方法は、リソースの場合と非常に似ています。「 BD.RES ルールでチェックするリソースを指定する」を参照してください。

[リソース] タブ

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

リソースを定義する方法の詳細については、以下のセクションを参照してください。

BD.RES ルールでチェックするリソースを指定する

テスト コンフィギュレーションの [静的] > [フロー解析オプション] > [リソース] タブでは、BD.RES (リソース) カテゴリのルールでどのリソースをチェックするかを定義することができます。BD.RES カテゴリのルールは、[リソース] タブで定義および有効化されているすべてのリソースについて、リソースが正しく使用されているかをチェックします。

さまざまな種類のリソースのチェックを有効化/無効化することができます。カスタム リソースを管理するには [追加]、[削除]、[編集] ボタンをクリックします。

特定のライブラリのリソースについての情報を追加するには、次の操作を行います。

  1. [追加] ボタンをクリックします。
  2. [リソースのタイプ] に名前を入力します。
  3. Enter キーを押します。新しいエントリが追加されます。
  4. 適切な場合、[アプリケーション終了時の違反をレポートしない] オプションをオフにします。
  5. エントリをクリックして [編集] ボタンをクリックします。表示されたダイアログで、リソースの割り当て/割り当て解除の方法を定義します。詳細については以下のセクションを参照してください。

アロケーターとクローザーに共通のパラメーター指定

各行は 1 つのアロケーター/クローザーの関数に対応します。明確に 1 つの関数 (ワイルドカードを使用した場合は一連の関数) を特定するのに十分な情報と、リソースの割り当て/解放の方法を定義します 。

リソース アロケーター

リソースを生成する関数についての情報を定義します。

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

リソース アロケーターが整数値を返す場合、[エラー時の戻り値制約] フィールドに条件を入力して、割り当てが失敗した場合の戻り値の制約を指定できます。条件は次の書式で指定する必要があります。
<比較演算子><整数値>
たとえば、0 ではない値をアロケーター関数が返す場合、このフィールドに「!=0」を入力します。 同様に、エラーに対するリターン コードが -1 の場合、「==-1」と入力します。!= と == に加えて、次の演算子を使ってエラー条件を指定できます。
>, >=, <, <=

リソース クローザー

リソースをクローズする関数についての情報を定義します。

ビルトインでサポートされるリソース

デフォルトでは、ビルトインでサポートされるリソースが [リソース] タブに表示されます。ビルトインでサポートされるリソースは次のとおりです。

 

カスタム リソースの定義 

例 #1

カスタム リソースを定義する例として、非標準のリソースを使って、次の単純な C コードについて考えてみましょう。
 

/* returns NULL on allocation failure */
void* myAlloc(void);
void myDealloc(void*);
static void createMyResource_Leak()
{
    void* resource = myAlloc();
} /* 'res' is not closed on the path where it is not NULL */
static void createMyResource_NoLeak()
{
    void* resource = myAlloc();
    if (!resource) {
	return; /* no leak here, if res is NULL, it means allocation failed */
    }
    /* use the resource */
    myDealloc(resource);
}

フロー解析を使ってこの非標準のリソースのリークを発見するために、リソースを割り当て/解放するメソッドを定義します。次の操作を行います。

  1. [リソース] タブで [追加] ボタンをクリックし、新しいリソースの名前を定義します。この名前は、このリソースに関連する違反がレポートされるときに使用されます。
  2. [アプリケーション終了時のリークをレポートしない] オプションをオフにします。
  3. [編集] ボタンをクリックしてこのリソースの操作方法を指定します。
  4. アロケーターとして myAlloc を定義します。
  5. クローザーとして closeMyResource を定義します。

例 #2

別の例を考えてみましょう。ここでは openMyResource 関数がパラメーターとしてリソース ハンドルへのポインターを受け取り、新規に割り当てられたリソースを初期化します。割り当てが失敗する場合、エラー コード -1 が返ります。

int openMyResource(int* pHandle);
void closeMyResource(int handle);
 
static void openMyResource_Leak()
{
    int handle;
    openMyResource(&handle);
 } // 'res' is not closed
static void openMyResource_NoLeak()
{
    int handle;
    int status = openMyResource(&handle);
    if (status == -1) {
	return; // no leak here, status == -1 indicates allocation failure
    }
    // use the resource
    closeMyResource(handle);
}

 

このタイプのリソースに対応するようフロー解析を設定します。次の操作を行います。

  1. [リソース] タブで [追加] ボタンをクリックし、新しいリソースの名前を定義します。このリソースに関連する違反がレポートされるときに、この名前が使用されます。
  2. [アプリケーション終了時のリークをレポートしない] オプションをオフにします。
  3. [編集] ボタンをクリックしてこのリソースの操作方法を指定します。
  4. アロケーターとして openMyResource を定義します。
  5. クローザーを指定します。