Walk-through 1: Handling NPD false positives with the __KLOCWORK__ macro
A typical use of the __KLOCWORK__ macro is in handling NPD false positives caused by custom asserts.
Assertions
Assertions are widely used in C/C++ code to implement validity checks and the pre- and post-conditions of a function. For example, if a function expects its argument to be a non-NULL pointer, the code typically looks like this:
1 void my_function(my_data_t *ptr) 2 { 3 MY_ASSERT(ptr != NULL); 4 char *name = ptr->name; 5 }
It's important for a static analysis tool to recognize assertions in the code and handle them properly, as a condition check. For example, if MY_ASSERT in the above code sample is not recognized as "check ptr for NULL", Klocwork would report a NULL pointer dereference issue at line 4 (a false positive).
Although the standard C/C++ library provides a default implementation of assert() in assert.h (typically a macro that checks the condition and aborts on failure), it is common practice to define a custom ASSERT macro, to provide:
- better diagnostics-the standard version typically prints a failed condition, filename, and line number; a custom assert could possibly add the function or module name to the error message, or report the error through some logging system to file.
- more flexibility with respect to build configuration-the debug version of the product could define assert to implement extended error reporting or automatically start a debugger, whereas the release version of assert could expand into an empty statement to eliminate the overhead of extra sanity checks.
Using the __KLOCWORK__ macro
Adding conditionally compiled code to your source is a very familiar way of dealing with differing environments. The __KLOCWORK__ macro, which is always defined by the Klocwork compiler, allows certain code to be active only when Klocwork is working and is otherwise ignored. Adding an alternative definition of an assert-type macro in a __KLOCWORK__ block can be non-intrusive and simple to manage.
For example, assume we have the following code:
1 MY_ASSERT(a!=NULL); 2 use(a->mm);
If Klocwork incorrectly processes your production definition of MY_ASSERT so that it doesn't understand the abort condition, it may report a false positive NPD on line 2. You can reduce the probability of this happening by providing Klocwork with a simpler, more standard, definition of your custom assert:
1 #ifdef __KLOCWORK__ 2 # define MY_ASSERT(x) do { if (!(x)) abort(); } while (0) 3 #else 4 # define MY_ASSERT(x) ... production, advanced definition of assert ... 5 #endif