EN JP CN

チュートリアル 2 - 組み込み関数を使用した C/C++ KAST チェッカーの作成

チュートリアル 2 - 組み込み関数を使用した C/C++ KAST チェッカーの作成

チュートリアル 2 - 組み込み関数を使用した C/C++ KAST チェッカーの作成

チュートリアル 2 - 組み込み関数を使用した C/C++ KAST チェッカーの作成

このチュートリアルでは、代入文のコードを検索し、代入によるデータ損失のインスタンスを検索するカスタム C/C++ KAST チェッカーを作成します。これを行うには、KAST 組み込み関数を使用してチェッカーの機能方法を指定する KAST 式を定義します。

このチュートリアルは、Checker Studio と、チュートリアル 1 - C/C++ KAST チェッカーの作成によるチェッカー作成の基本プロセスに精通していることを前提としています。

チェッカースタブファイルの作成

CHECK.VAR.SIZE というチェッカー名を使用して、kwcreatechecker を実行して次のチェッカーファイルを作成します。

kwcreatechecker --language cxx --type kast --code CHECK.VAR.SIZE

スタブファイルは CHECK.VAR.SIZE ディレクトリに配置されます。

テストケースの作成

開始するには、チェッカーのテストケースを、チェッカーを検索する状況を含めた最も単純なコードにする必要があります。チェッカーの開発が進むとともに、テストケースを拡張してより複雑にすることができます。

自動的に生成された testcase.cc ファイルを編集し、テンプレートコードを次のサンプルコードに置き換えます。

int main(){

  short x;
  int y = 4;
  x = y;
  
  short* xp = 3;
  int yy = 4;
  *xp = yy;

  short xx;
  int ya[7];
  xx = &ya;

  return 0;
}

KAST 式の作成

このステップでは、KAST 式を形成する構成要素の検索を始めます。これは、Checker Studio がテストケースコードから作成する AST 階層ツリーを調査することから始めます。

目的の KAST ノードの検索

AST 階層ツリーに、KAST ノード名、階層情報、演算属性といった、式の最初の要素を見つけることができます。

  1. Checker Studio を開き、テストケースコードを [ソースコード] ペインに貼り付けます。
  2. コードの最初のブロックで 'x = y' をクリックします。
    AST ツリーの ExprStmt ノードの最初のインスタンスがハイライトされます。ExprStmt ノードには 1 つの子ノード BinaryExpr があります。これらの 2 つのノード名は、次に示すように、最初の KAST 式の構成要素の最初の 2 つの要素になります。
    //ExprStmt / Expr::BinaryExpr
  3. ソースコード式の '=' 記号をクリックします。
    BinaryExpr ノードがハイライトされ、"=" 演算子の KTC 属性コードが [属性] ペインに表示されます。この属性式は、次に示す KAST 式の最初の要素を実行します。
    //ExprStmt / Expr::BinaryExpr [@Op = KTC_OPCODE_ASSIGN]
    ここまで作成した KAST 式の要素は、"演算が代入であるすべてのバイナリ演算を検索する" として解釈できます。
  4. その開発を行っている間に、すべてのテキストファイルに式を配置します。

KAST 条件の定義

KAST 式の次の要素は、チェッカーの検索に適用する条件を提供します。KAST 変数 (先頭に "$" が付く語) を使用すると、検索式の LHS および RHS を定義できます。

[$expr1:=Left]
[$expr2:=Right]

KAST 構文では、角括弧は式内の条件を表します。

また、このチェッカーの変数のみを検索することを指定することもあります。 それを行うには、変数と KAST 組み込み関数である isConstant、isArray、および isPointer を次の条件で使用します。

[not $expr2.isConstant()]
[not $expr1.isPointer() | not $expr2.isArray()]

これらの条件を KAST 式に追加すると、次のようになります。

//ExprStmt / Expr::BinaryExpr [@Op = KTC_OPCODE_ASSIGN]
[$expr1:= Left]
[$expr2:= Right]
[not $expr2.isConstant()]
[not $expr1.isPointer() | not $expr2.isArray()]

KAST 式作成の次のステップは、2 つの新しい KAST 変数と組み込み関数である getTypeSize を使用して変数サイズを取得する条件の追加です。

[$size1:=$expr1.getTypeSize()]
[$size2:=$expr2.getTypeSize()]

最後のステップは、文の両側の変数とゼロを比較し、両側を互いに比較する条件の追加です。

[$size1 > 0]
[$size2 > 0]
[$size1 < $size2]

これらの条件を追加すると、KAST 式が完成します。

//ExprStmt / Expr::BinaryExpr [@Op = KTC_OPCODE_ASSIGN]
[$expr1:= Left]
[$expr2:= Right]
[not $expr2.isConstant()]
[not $expr1.isPointer() | not $expr2.isArray()]
[$size1:= $expr1.getTypeSize()]
[$size2:= $expr2.getTypeSize()]
[$size1 > 0]
[$size2 > 0]
[$size1 < $size2]

この式は、"演算が代入であるすべてのバイナリ演算を検索し、その LHS 型サイズは RHS 型サイズより小さい" として解釈できます。

Checker Studio での式のテスト

チェッカーが意図したとおりに機能していることを確認するには、KAST 式を Checker Studio の [パターン] ペインに入力またはコピーします。 必要に応じて、Checker Studio で KAST 式とテストケースを調整します。

KAST 式のその他の例については C/C++ KAST 例を、KAST 構文の詳細については C/C++ KAST 構文リファレンスを参照してください。

スタブファイルの編集

この段階では、自動的に生成された checkers.xml および help.xml ファイルを新しいチェッカーに固有の情報を使用して編集します。

checkers.xml ファイルの編集

KAST 式を使用して checkers.xml ファイルを編集します。

checkers version="1.3">

    <categories>

        <category name="C and C++">

            <category name="Custom checkers">

                <error id="CHECK.VAR.SIZE"/> 

            </category> 

        </category> 

    </categories> 


    <checkergroup language="C/C++" api="tree_pattern">

        <checker id="CHECK.VAR.SIZE">

            <libraries>

                <library path=""/> 

            </libraries> 


            <error id="CHECK.VAR.SIZE"

                        enabled="true" 
                        severity="3" 
                        title="Check variable size" 
                        message="Assignment with possible loss of data"> 

                    <pattern>

                        //ExprStmt / Expr::BinaryExpr [@Op = KTC_OPCODE_ASSIGN] 
                        [$expr1:=Left] [$expr2:=Right] [not $expr2.isConstant()] 
                        [not $expr1.isPointer() | not $expr2.isArray()] 
                        [$size1:=$expr1.getTypesize()] [$size2:=$expr2.getTypesize()] 
                        [$size1 &gt; 0] [$size2 &gt; 0] [$size1 &lt; $size2] 

                    </pattern> 

            </error> 

        </checker> 

    </checkergroup> 

</checkers> 

このファイルでは、元のテンプレートデータを次のものに置き換えました。

  • チェッカーが解析時に生成するチェッカーのタイトルおよびメッセージ
  • <pattern> フィールドの KAST 式

help.xml ファイルの編集

チェッカーを作成して展開すると、help.xml ファイルが Klocwork ドキュメンテーションに表示され、Klocwork Static Code Analysis のコンテキスト依存ヘルプで使用できるようになります。少なくとも指摘の説明を入力する必要があります。

チェッカーをビルドする

Linux の場合はmake install buildspec、Windows の場合は nmake install buildspec を (VS プロンプトから) 使用してチェッカーをビルドします。

このプロセスによって、次のものが生成されます。

  • チェッカーファイルが含まれている CHECK.VAR.SIZE.zip というファイル
  • コンパイル済みのチェッカーをテストするための build specification (ビルドスペック) ファイル

チェッカーをテストする

テスト中は、サーバープロジェクトではなくデスクトップにチェッカーを展開するのが最適です。

  1. 選択したディレクトリにアーカイブファイルを解凍します。
  2. 同じディレクトリに次のようにローカルプロジェクトを設定します。
    kwcheck create -b <build_specification>
    
    フィールド <build_specification> は、make または nmake を使用して作成した build specification (ビルドスペック) です。
  3. 次のように kwcheck を実行して、テストケースで指摘が検出されたかどうか確認します。
    kwcheck run
    
    kwcheckを繰り返し実行する場合は、kwcheck を -rオプションとともに使用して、明らかな変更がないファイルが Klocwork でスキップされないようにします。

デフォルトの testcase.cc ファイルで kwcheckを実行すると、チェッカーはデータ損失の可能性がある代入の 3 つのインスタンスを見つけ、Klocworkから次のようなメッセージが表示されます。

1(Local) /.../testcase.c:7 CHECK.VAR.SIZE (3:Severity 3) Analyze
Assignment with possible loss of data
2 (Local) /.../testcase.c:11 CHECK.VAR.SIZES (3:Severity 3) Analyze
Assignment with possible loss of data
3 (Local) /.../testcase.c:15 CHECK.VAR.SIZE(3:Severity 3) Analyze
Assignment with possible loss of data

次は何?

これで、チェッカーを正常に作成して実行できたので、より複雑なテストケースをこのチェッカーに追加するか、Klocwork のその他の組み込み関数を使用して独自のプロジェクトに新しいチェッカーを作成できます。

組み込み関数のリストについては、Checker Studio を起動し、[ヘルプ] > [ヘルプトピック] > [KAST リファレンス] > [C/C++ KAST 組み込み関数リファレンス] に移動します。既に入手可能になものを再作成しないように、必ず最新の組み込み関数のリストを参照してください。

次に、チェッカーの活動の詳細については、次のリンクを確認してください。