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

From Insight-10.0

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


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:
  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 GWYN 10.png
    Cond has one child BinaryExpr, indicating that IfStmt contains a condition clause (Cond) that is a binary expression (BinaryExpr).
  7. Click '=' in the Source Code pane.
    This will highlight the BinaryExpr and shows its attributes in the Attributes table to the lower left.
    KAST tutorial1 2 GWYN 10.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 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, and BinaryExpr. Put this together into the KAST expression to produce:

//IfStmt / Cond::BinaryExpr [ @Op = KTC_OPCODE_ASSIGN ]

Note that KAST provides a built-in function that returns the value of the Op attribute for an expression node: getOperationCode(). We will use this function in this tutorial in place of explicitly querying a particular attribute, leading us to the following KAST statement:

//IfStmt / Cond::BinaryExpr [ getOperationCode() = 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.)

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

Test the KAST expression

  1. Type the KAST expression, above, 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 GWYN 10.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 GWYN 10.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 can add it to the checkers.xml file, which is generated by running kwcreatechecker. When this file is first generated, its values are automatically populated with an error ID, severity, message, and title, as well as a sample KAST expression, so that it's obvious what you have to change to define your own checker.

In this particular case, we are interested in the pattern element of this XML file, and will modify it as follows:

// IfStmt / Cond::BinaryExpr [ getOperationCode() = KTC_OPCODE_ASSIGN ]
  1. Replace the sample KAST expression with your tested KAST expression. You can also edit the <error> node’s attributes, for example to 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".
  2. 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 first create the checker.

At minimum, you should provide a useful description for your checker, but you may also find it valuable to provide content for the other sections, such as risks, in which you could describe how a typical mistake that this checker detects could lead to exposure, or prevention, in which you could explain how to address that exposure via code fixes.

When the checker is deployed, any help content you provide will be integrated automatically with the online help collection.

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. To make this simple, kwcreatechecker adds a Makefile to the checker directory when first run.

Under Unix or OS/X (or anything else non-Windows), run:

make install buildspec

Under Windows, make sure that you're using a Visual Studio command prompt, and run:

nmake install buildspec

This generates:

  • a zip file entitled with the code of your checker, suitable for deployment
  • 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.
    If the C/C++ checker is platform-specific, copy the xml file to <username>/.klocwork/<plugins>/<platform-name>.
    When you're ready to deploy the checker at the server project level, uninstall the checker from your desktop.
    For more information, see Deploying the checker package to your desktop .
  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 more built-in functions.

Documentation for custom C/C++ KAST checkers