Tutorial 1 - Creating a C/C++ KAST checker

From current

Custom C/C++ checkers > Custom C/C++ KAST checkers > Tutorial 1 - Creating a C/C++ KAST checker

Contents

Run kwcreatechecker

Move to the directory where you want the checker files to be created, and from the VS prompt if you're in Windows, run kwcreatechecker with the following options:

kwcreatechecker --language cxx --type kast --code MY.C.KAST.CHECKER

The --code option specifies the name we're assigning to the checker.

Note: Multibyte characters are not supported in error IDs (checker names), and there's a 255-character limit.

A directory is created with the name you specified with --code. This directory contains the checker stub files. In the case of the example above, the directory is named MY.C.KAST.CHECKER. The MY.C.KAST.CHECKER directory contains:

  • the checker configuration files (checkers.xml and help.xml)
  • a test case sample (testcase.cc)
  • a build file (Makefile)


Create the simplest test case

The first test case for the checker should be as simple as possible. As you develop the checker, you can add and test more complex cases.

The checker we're going to create in this tutorial detects variable assignment in an if statement. It is easy to mis-type the equal operator a == b as the assignment operator a = b (single equal sign instead of double equal sign), which still results in valid C/C++ code. The simplest code fragment that will generate this Klocwork Insight error is:

void f(int a, int b) {  
 if (a = b) { //Error: assignment of b to a in if statement  
 /* do stuff */
 }
}

Replace the template code in the testcase.cc file with this code MY.C.KAST.CHECKER/testcase.cc).

Use Checker Studio to find KAST nodes of interest

Now that you have a simple test case, the next step is to open Checker Studio.

  1. Double-click the Checker Studio icon on your desktop, or at the command line, type:
    kwstudio
  2. Paste your testcase code snippet into the Source Code section of Checker Studio to view the KAST node names, example code and hierarchy information. These will form the building blocks of your KAST expression, which will trace a path to the issue you are identifying with your checker. Don't forget to set the language button in the upper right corner of the window.
  3. Click "if" in the snippet in the Source Code pane.
    The IfStmt node in the AST is highlighted. This is the first node of interest in your KAST expression.
  4. View context-sensitive help for the expression by selecting a tree node and pressing F1, or clicking View > Context Help Window. Context-sensitive help displays below the Source Code pane, providing more node information, such as supertypes and subtypes, and applicable functions. (For reasons of image clarity, the illustrations in this tutorial don't show the Context Help panel.)
  5. In the AST, expand IfStmt.
    It has children Cond, Then and Else. This checker deals with the if statement’s condition expression.
  6. Expand the Cond: :AnyExpr node.
    KAST tutorial1 1.png
    Cond has one child BinaryExpr, indicating that IfStmt contains a Cond of type BinaryExpr.
  7. Click '=' in the Source Code pane.
    This will highlight Op which is, in this case, a binary operator. The attributes of OP are displayed in the Attributes table in the lower left.
    KAST tutorial1 2.png
    Note: If you don’t see the attributes, click the Show Hide Attributes button.jpg Show Attributes icon. Attributes are only displayed for the currently-selected node.
  8. Make a note of its Code Value (KTC_OPCODE_ASSIGN).
    Now that we have the AST nodes, it’s time to draft the KAST expression.

Draft the KAST expression

The nodes you identified in the previous step are: IfStmt, Cond, BinaryExpr, Op and Code (where Code is KTC_OPCODE_ASSIGN).

  1. Put this together into the KAST expression to produce:
    //IfStmt/Cond::BinaryExpr[Op::Op[@Code=KTC_OPCODE_ASSIGN]]
    This KAST expression will search the AST for if statements that contain an assignment in the condition statement. (For detailed information about the elements of KAST expressions, see C/C++ KAST syntax reference.)
  2. Type your KAST statement into a text file. (If you add it to the checkers.xml file at this stage, you will have to build the checker files to test your expression. It’s simpler to test your KAST expression in Checker Studio while you're still developing it.)

Now that we have a KAST expression, our next step is testing the expression.

Test the KAST expression

  1. Type or paste the KAST expression into the Pattern pane in Checker Studio.
    The AST nodes matched by the expression are selected and the corresponding source code fragments are highlighted.
    KAST tutorial 1 3.png
  2. Adjust your KAST expression and test case as needed and re-test. Checker Studio automatically responds to your changes by searching the source code and AST. (Make sure that KAST tutorial1 auto button.png Automatic Pattern Application is on.)
    You can look in the context-sensitive help for functions that are applicable to the currently highlighted expression.

Add more complexity to the test case

The next step in the KAST checker development process is to add more tests to the test case. Tests to add can be:

  • false positive tests - ensure that the checker does not generate errors for certain conditions
  • more complex tests - ensure that the checker will generate an error for special or more complex cases

For the sample checker in this tutorial, we’ll add three more false-positive test cases:

  • non-assignment boolean operation
  • boolean equals operation
  • assignment in complex expression

These cases should not generate a Klocwork Insight error.

1. Change the code in testcase.cc to:

  void f(int a, int b)
  {
   if (a = b) { /* ERROR - assignment in condition */ 
   }
 
   if (a > b) { /* OK - no assignment */
   }
 
   if (a == b) { /* OK - equal check, not assignment */  
   }
 
   if ((c = getc()) != EOF) { /* OK - assignment as part of more complex expression */  
   }
  }


2. Paste the new code into Checker Studio, and run the test again.

KAST tutorial 1 4.png

The results indicate that no false positives were generated (all the test cases were covered).

Add the KAST expression to the checkers.xml file

Now that the checker’s KAST expression is complete and tested, we’ll add it to the checkers.xml file, which we generated with Run kwcreatechecker. #: When the file was generated, its values were automatically populated with an error ID, severity, message, and title, as well as a sample KAST expression:

<checkers version="1.3">
<categories>
<category name="C and C++">
<category name="Custom checkers">
<error id="MY.C.KAST.CHECKER"/>
</category>
</category>
</categories>

<checkergroup language="C/C++" api="tree_pattern">
<checker id="MY.C.KAST.CHECKER">
<libraries>
<library path="nodelib"/>
</libraries>

<error id="MY.C.KAST.CHECKER"
enabled="true"
severity="3"
title="Assignment in if condition"
message="Assignment in if condition">
<pattern>
// IfStmt / Cond::BinaryExpr / Op::Op [ @Code = KTC_OPCODE_ASSIGN ]
</pattern>
</error>
</checker>
</checkergroup>
</checkers> </blockquote>


  1. Open the checkers.xml file in an editor of your choice. This file is located in MY.C.KAST.CHECKER/checkers.xml.
  2. Look for the <pattern> tag.
  3. Replace the sample KAST expression with your tested KAST expression, which is:
    //IfStmt/Cond: :BinaryExpr[Op: :Op[@Code=KTC_OPCODE_ASSIGN]]
  4. You can also edit the <error> node’s attributes, as required. For this tutorial, we’ll change the title attribute to read "Variable assignment in if statement" and the message attribute to read "Possible undesired variable assignment in an if statement".
  5. Save the file.

Create help for your checker

Checker documentation can be added by editing the help.xml file, which is bundled with the other checker files when you build the checker:

<help language="cxx">
<defect id="MY.C.KAST.CHECKER">
<description>
Issue description. It may contain any HTML tags.
</description>
<risks>
Description of possible vulnerability and risks caused by this issue (optional section).
</risks>
<prevention>
Issue mitigation and prevention description (optional section).
</prevention>

<-- Optional -->
<examples>
<example line="1">
<![CDATA[
Code snippet
]]>
<description>
Detect variable assignment in an if statement.
</description>
</example>
<-- Here you can add more examples -->
</examples>
</defect>
</help>

At minimum, you must provide a <description> for your checker. Typically, of course, the checker name would also be more descriptive.

When the checker is deployed to a server project (and connected desktop), the help contents appear in the online help in Klocwork Review.

Build the checker

Now that we’ve added the checker’s KAST expression to the checkers.xml file and created help, it’s time to build the checker using 'make'.

A makefile was automatically generated in the checker directory created in Run kwcreatechecker.

In Unix, run:

make install buildspec

In Windows, from the Visual Studio prompt, run:

nmake install buildspec

This generates:

  • a file called MY.C.KAST.CHECKER.zip
  • a build specification file that allows you to test your compiled checker using kwcheck or kwbuildproject

Test the checker

  1. Unzip the archive file into the directory of your choice.
    Tip: You may want to unzip the archive file into the same directory that you created your checker stub files in.
  2. In the same directory, set up a local project:
    kwcheck create -b <build_specification>
    where <build_specification> was created with make install buildspec or nmake install buildspec
  3. Run kwcheck to see if the issue is detected in your test case:
    kwcheck run
    Your checker will detect the issue from your test case.
  4. If you are satisfied with the results, you can deploy your checker to the server.

What's next?

Try writing a checker with custom functions.

Documentation for custom C/C++ KAST checkers

Overview

How-to

Tutorials

Examples

Deployment

Reference