Start here

Home
About Klocwork
What's new
Fixed issues
Release notes
Installation

Reference

C/C++ checkers
Java checkers
C# checkers
MISRA C 2004 checkers
MISRA C++ 2008 checkers
MISRA C 2012 checkers
MISRA C 2012 checkers with Amendment 1
Commands
Metrics
Troubleshooting
Reference

Product components

C/C++ Integration build analysis
Java Integration build analysis
Desktop analysis
Refactoring
Klocwork Static Code Analysis
Klocwork Code Review
Structure101
Tuning
Custom checkers

Coding environments

Visual Studio
Eclipse for C/C++
Eclipse for Java
IntelliJ IDEA
Other

Administration

Project configuration
Build configuration
Administration
Analysis performance
Server performance
Security/permissions
Licensing
Klocwork Static Code Analysis Web API
Klocwork Code Review Web API

Community

View help online
Visit RogueWave.com
Klocwork Support
Rogue Wave Videos

Legal

Legal information

Tutorial 2 - Creating a C/C++ KAST checker with built-in functions

Tutorial 2 - Creating a C/C++ KAST checker with built-in functions

In this tutorial, we create a custom C/C++ KAST checker that searches code for assignment statements and finds instances of possible data loss through the assignment. To do this, we define a KAST expression that uses KAST built-in functions to specify the way the checker will work.

This tutorial assumes that you've become familiar with Checker Studio and the basic process of creating a checker through Tutorial 1 - Creating a C/C++ KAST checker.

Generate the checker stub files

Using a checker name of CHECK.VAR.SIZE, run kwcreatechecker to generate the checker files:

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

The stub files are placed in the CHECK.VAR.SIZE directory.

Create the test case

To start with, the test case for the checker should be the simplest code that includes the situations the checker will be looking for. You can extend the test cases and add more complexity as you develop the checker.

Edit the automatically generated testcase.cc file and replace the template code with this sample code:

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;
}

Create the KAST expression

In this step, we begin finding the building blocks that will form our KAST expression, starting by studying the AST hierarchical tree that Checker Studio creates from our test case code.

Finding the KAST nodes of interest

In the AST tree, we can find the first elements of the expression: the KAST node names, hierarchy information, and operation attributes.

  1. Open Checker Studio, and paste the test case code into the Source Code pane.
  2. Click 'x = y' in the first block of code.
    Checker Studio highlights the first instance of an ExprStmt node in the AST tree. The ExprStmt node has one child node, BinaryExpr. These two node names will be the first two elements of our first KAST expression building block:
    //ExprStmt / Expr::BinaryExpr
  3. Click the '=' sign in the source code expression.
    Checker Studio highlights the BinaryExpr node and displays the KTC attribute code for the "=" operator in the Attributes pane. This attribute expression completes the first element of the KAST expression:
    //ExprStmt / Expr::BinaryExpr [@Op = KTC_OPCODE_ASSIGN]
    The elements of the KAST expression we've created so far can be read as "Find all binary operations whose operation is assign."
  4. Place the expression in any text file while we continue to develop it.

Defining KAST conditions

The next few elements of the KAST expression provide the conditions we want to apply to the checker's search. Using KAST variables (terms prefixed by "$"), we can define the LHS and RHS of our search expressions:

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

In accordance with KAST syntax, the square brackets indicate conditions in the expression.

We also want to specify that we're only looking for variables in this checker, and we can do that using our variables and the KAST built-in functions isConstant, isArray, and isPointer in the following conditions:

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

Adding these conditions to our KAST expression, we get:

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

The next step in creating the KAST expression is to add conditions that retrieve the variable size by using two new KAST variables and the built-in function, getTypeSize:

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

The last step is to add the conditions that compare the variables from each side of the statement to zero and to each other:

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

When we add these conditions, we have the completed KAST expression:

//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]

This expression can now be read as "Find all binary operations whose operation is assign, and in which the LHS type size is less than the RHS type size."

Test the expression in Checker Studio

To make sure the checker is working the way you want it to, type or copy the KAST expression into the Pattern pane in Checker Studio, and adjust your KAST expression and test case in Checker Studio as needed.

For more examples of KAST expressions, see C/C++ KAST examples, and for more details of KAST syntax, see C/C++ KAST syntax reference.

Edit the stub files

At this stage, we edit the automatically generated checkers.xml and help.xml files with the information specific to our new checker.

Edit the checkers.xml file

Edit the checkers.xml file with the KAST expression:

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> 

In this file, we've replaced the original template data with

  • the checker title and the message that the checker will generate during analysis
  • the KAST expression in the <pattern> field

Edit the help.xml file

When you create and deploy a checker, the help.xml file populates Klocwork Documentation and is available through context-sensitive help in Klocwork Static Code Analysis. At minimum, you must provide a description of the issue.

Build the checker

Build the checker with make install buildspec in Linux, or nmake install buildspec in Windows (from the VS prompt).

This process generates:

  • a file called CHECK.VAR.SIZE.zip containing the checker files
  • a build specification file that allows you to test your compiled checker

Test the checker

While you're still testing, it's best to deploy the checker to your desktop, rather than the server project.

  1. Deploy the custom checker to your desktop by extracting the zip file into the <username>/.klocwork/plugins directory, creating the directory if it doesn't already exist.
  2. Set up a local project in the directory where you developed the checker.
    kwcheck create -b <build_specification>
    

    <build_specification> was created with make install buildspec or nmake install buildspec. By default, the build specification is written to kwinject.out in the current working directory.

  3. Run kwcheck to see if the issue is detected in your test case:
    kwcheck run
    
    Tip: When you're running the kwcheck command repeatedly, use kwcheck with the -r option to make sure Klocwork doesn't skip files that have no apparent changes.

    When you run kwcheck with the default testcase.cc file, the checker will find the three instances of assignment with possible loss of data, and Klocwork will display a message like this one:

    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
    
  4. If you are satisfied with the results, you can deploy your checker to the server.
  5. Uninstall the checker from your desktop by deleting the files that you extracted in Step 1 from the plugins directory .

What's next?

Now that you've successfully created and run your checker, you could add more complex test cases to this checker, or create a new checker for your own project using some of the other Klocwork built-in functions.

For a list of the built-in functions, launch Checker Studio, and go to Help > Help topics > KAST reference > C/C++ KAST built-in functions reference. Always make sure you consult the latest list of built-in functions to avoid recreating something that's already available.

Then check out the links below for more checker activity.