1. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
1/47
An Introduction to PC-lint
Agenda:
► Introduction
► Features
► Usage
► The true value of PC-lint
Version 1.20
2. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
2/47
“C makes it easy to shoot yourself in the foot...”
(Bjarne Stroustrup)
An Introduction to PC-lint
C is a powerful
but dangerous
language
3. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
3/47
Classic C Mistakes
Only to name a few...
► Array out-of-bounds access
► Null pointer dereferencing
► Using a variable before initialization
► Order of evaluation of operands
► Integer overflow
► Assignment where check for equality was intended
► Illegal printf/scanf format strings
► Forgetting to handle a case in switch statement
► Passing macro arguments with side effects
4. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
4/47
“ ...C++ makes it harder, but when you do,
it blows your whole leg off.”
(Bjarne Stroustrup)
An Introduction to PC-lint
The same holds
for C++
5. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
5/47
Classic C++ Mistakes
Only to name a few...
► Forgetting to initialize class members
► Initializing class members in the wrong order
► Forgetting to declare the base class destructor virtual
► Forgetting to implement the assignment op
► Using auto_ptr on containers
► Memory and resource leaks
► Unhandled exceptions
► Leaking exceptions from destructors
► Order of static initialization
6. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
6/47
The Case For Static Code Checking
C and C++ are powerful but dangerous
Even if code works, it might not be portable/future-proof
► Alignment issues
► Size of scalars
► Compiler-specific features
► …
Traditional testing (checking at run-time)
► Might not detect all issues
► Is expensive
However: static checking
is not meant as a
replacement for testing!
7. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
7/47
What is Lint/PC-lint?
Lint
► Etymology: undesired fibers and fluff in sheep's wool
► Seventh version (V7) of Unix (1979)
► Part of PCC (portable C compiler)
PC-lint
► Commercial version for C and C++
► Produced by Gimpel Software, USA.
► First version appeared 1985
► Current version is 9.00
► FlexeLint: for Unix/Linux
8. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
8/47
What is Lint/PC-lint?
PC-lint
► Works similar to a compiler
► Checks code statically ('at compile-time')
► Doesn't produce machine code
► Performs thousands of checks and will produce the appropriate
warnings, so-called "issues" or "messages
9. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
9/47
Examples
Let's have a look at some code...
10. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
10/47
What's wrong with this C code?
1 #include <stdio.h>
2 #define SUM(x, y) (x) + (y)
3 unsigned long* PerformGizmoAlgorithm(int a, int b) {
4 unsigned long vector[8] = {143, 33, 2l, 76, 83, 222, 45, 45};
5 int i;
6
7 for (i = 0; i < 8; ++i);
8 vector[i + 1] = vector[i] * SUM(a, b);
9
10 return vector;
11 }
11. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
11/47
What's wrong with this C code?
1 #include <stdio.h>
2 #define SUM(x, y) (x) + (y)
3 unsigned long* PerformGizmoAlgorithm(int a, int b) {
4 unsigned long vector[8] = {143, 33, 2l, 76, 83, 222, 45, 45};
5 int i;
6
7 for (i = 0; i < 8; ++i);
8 vector[i + 1] = vector[i] * SUM(a, b);
9
10 return vector;
11 }
file.c:2 I 773 Expression-like macro 'SUM' not parenthesized
file.c:7 I 722 Suspicious use of ;
file.c:8 W 539 Did not expect positive indentation from line 7
file.c:8 I 737 Loss of sign in promotion from int to unsigned long
file.c:8 W 661 Possible access of out-of-bounds pointer (1 beyond end of data) by operator '['
file.c:8 W 661 Possible access of out-of-bounds pointer (2 beyond end of data) by operator '['
file.c:10 W 604 Returning address of auto variable 'vector'
file.c:0 I 766 Header file '/usr/include/stdio.h' not used in module 'file.c'
file.c:4 W 620 Suspicious constant (L or one?)
Would you have
found all of these
issues?
12. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
12/47
What's wrong with this C++ code?
1 class Base {
2 char* mp;
3 int mCount;
4 public:
5 Base(int aCount = 0) { mCount = aCount; if(mCount > 0) mp = new char[mCount]; }
6 void printRuntimeType() { cout << "Base"; }
7 ~Base() { delete mp; }
8 };
9
10 class Derived : public Base {
11 public:
12 void printRuntimeType() { cout << "Derived"; }
13 };
13. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
13/47
What's wrong with this C++ code?
1 class Base {
2 char* mp;
3 int mCount;
4 public:
5 Base(int aCount = 0) { mCount = aCount; if(mCount > 0) mp = new char[mCount]; }
6 void printRuntimeType() { cout << "Base"; }
7 ~Base() { delete mp; }
8 };
9
10 class Derived : public Base {
11 public:
12 void printRuntimeType() { cout << "Derived"; }
13 };
file.cpp:5 I 1732 new in constructor for class Base which has no assignment operator
file.cpp:5 I 1733 new in constructor for class Base which has no copy constructor
file.cpp:5 I 737 Loss of sign in promotion from int to unsigned int
file.cpp:5 W 1541 Member Base::mp (line 4) possibly not initialized by constructor
file.cpp:7 W 424 Inappropriate deallocation (delete) for 'new[]' data.
file.cpp:12 W 1511 Member hides non-virtual member Base::printRuntimeType(void) (line 8)
file.cpp:13 W 1509 base class destructor for class 'Base' is not virtual
Would you have
found all of these
issues?
14. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
14/47
What PC-lint is Not
Focus is on finding C/C++ programming errors:
► No: Java, C#
► No: Metrics
► No: High-level design and architectural analysis
Inexpensive, compact but powerful code checker:
► No: GUI/browsers/wizards
► No: Issue database
► No: License server
15. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
15/47
Features
A quick tour of some features
► Weak definials
► Const-correctness
► Strong types
► Value tracking
► Semantics
► Multi-thread support
► Author files and MISRA
16. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
16/47
Weak definials
PC-lint keeps code (esp. interfaces) clean by reporting
► Unused declarations (types, macros...)
► Unused or redundantly included headers
► Declarations that are only used locally
►
Move from header to .c/.cpp file
►
Make functions/objects static
17. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
17/47
Const-correctness
Const-correctness is an important topic in C/C++
Difficult to add const-correctness later (ripple effect)
PC-lint reports:
► Member function could be made const
► Pointer could be declared as pointing to const
► Even: parameters/objects could be made const
18. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
18/47
Strong types
Neither C nor C++ has strong typing
► Mixing enums, ints, bools, typedefs is permissible
'Strong type' feature lets you selectively enable strong type
checking
typedef int Temperature;
int t1 = 42;
Temperature t2 = t1; // Bad!
if (t1) { // Bad!
...
}
Compatibility of types can be achieved through the 'type
hierarchy' feature
19. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
19/47
Value tracking
PC-lint keeps track of variable values and initialization status:
extern int g_array[10];
int foo(int* arr, int n) { return arr[n]; }
...
if (count == 20) {
cout << "Wow, 20 elements!" << endl;
}
int y = foo(g_array, 20); // -passes(2): likely out-of-bounds access
int x = foo(g_array, count); // -passes(2): possible out-of-bounds access
The more passes, the better (but slower!)
20. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
20/47
Many well-known library functions have certain pre-/postconditions:
► assert(), abort(): never return
► memset(): arg3 may not exceed sizeof arg1 area
► strcpy(): return value is never NULL
► fopen(): args never NULL and '0' terminated; return value may be NULL
Transfer such well-known semantics to user-defined functions
► -function(abort, MyClass::stop)
PC-lint uses additional information during analysis
mc->stop();
foo(42); // Unreachable code!
Semantics -- function mimicry
21. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
21/47
Semantics -- semantic specifications
Function mimicry is based on "semantic specifications"
Use semantic specifications for finer-grained control
Many, many possibilities via -sem option:
r_null, r_no, nulterm(#), #p, inout, thread, thread_unsafe...
Example:
//lint -sem(decode, inout(3))
result_t decode(const void* src, void* dest, int* destLen);
void foo() {
int n;
if (decode(inbuf, outbuf, &n) == OK) { // n not initialized
...
}
}
22. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
22/47
Based on "semantic specifications", specify:
► Thread root functions
► Thread creation functions (eg. pthread_create())
► Begin of thread protected region (eg. pthread_mutex_lock)
► End of thread protected region (eg. pthread_mutex_unlock)
► Thread-safe, thread-unsafe functions
PC-lint reports:
► Unprotected access to static/global data/objects
► Unprotected calls to thread-unsafe functions
► Mismatched lock/unlock calls
Multi-thread support
23. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
23/47
Option files with checks recommended by authors:
► Mainly Scott Meyers, "(More) Effective C++" (au-sm*.lnt)
► Checks for 64-bit issues (au-64.lnt)
► MISRA recommendations:
► MISRA C 1998 (au-misra1.lnt)
► MISRA C 2004 (au-misra2.lnt)
► MISRA C 2012 (au-misra3.lnt)
► MISRA C++ (au-misra-cpp.lnt)
Author files and MISRA
24. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
24/47
Usage
Usage
► Command-line interface
► Lint messages
► Lint policy
► Message inhibition
25. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
25/47
Command-line interface
lint-nt.exe <args>... <files>...
► lint-nt.exe -w3 -I../include main.cpp calc.cpp
Pass options directly or via option file (*.lnt)
► lint-nt.exe settings.lnt main.cpp calc.cpp
► lint-nt.exe settings.lnt files.lnt
Two modes of operation
► Single checkout mode (-u)
►
lint-nt.exe settings.lnt -u calc.cpp
►
Good for quick checks of a single module
► Whole-project mode (w/o -u)
►
Slower, but Lint analysis is much deeper
►
PC-lint knows if and how functions/identifiers are used across translation units
26. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
26/47
Command-line interface
PC-lint output
► Can be tuned
► "Message presentation options" define what and how issues are
reported
► Call PC-lint from within your favorite editor/IDE to navigate code/issues
► Select env-*.lnt files that match your IDE's error parser, e. g.
env-vc9.lnt, env-vim.lnt, env-xml.lnt, env-html.lnt
27. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
27/47
Lint messages
Lint produces around 1000 different warnings
Let's review our previous example...
Kind C C++ Level Think...
Syntax Errors 1 - 199 1001 - 1199 1 Syntax Error
Internal Errors 200 - 299 1200 - 1299 Oops!
Fatal Errors 300 - 399 Oops!
Warnings 400 - 699 1400 - 1699 2 Something likely wrong
Informational 700 - 899 1700 - 1899 3 Something might be wrong
Elective Notes 900 - 999 1900 - 1999 4 Style issue
28. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
28/47
What's wrong with this C code?
1 #include <stdio.h>
2 #define SUM(x, y) (x) + (y)
3 unsigned long* PerformGizmoAlgorithm(int a, int b) {
4 unsigned long vector[8] = {143, 33, 2l, 76, 83, 222, 45, 45};
5 int i;
6
7 for (i = 0; i < 8; ++i);
8 vector[i + 1] = vector[i] * SUM(a, b);
9
10 return vector;
11 }
file.c:2 I 773 Expression-like macro 'SUM' not parenthesized
file.c:7 I 722 Suspicious use of ;
file.c:8 W 539 Did not expect positive indentation from line 7
file.c:8 I 737 Loss of sign in promotion from int to unsigned long
file.c:8 W 661 Possible access of out-of-bounds pointer (1 beyond end of data) by operator '['
file.c:8 W 661 Possible access of out-of-bounds pointer (2 beyond end of data) by operator '['
file.c:10 W 604 Returning address of auto variable 'vector'
file.c:0 I 766 Header file '/usr/include/stdio.h' not used in module 'file.c'
file.c:4 W 620 Suspicious constant (L or one?)
Some 'informationals'
are clearly bugs
in this context!
29. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
29/47
Enabling/disabling messages
Coarse level: -w<level> option
► Example: -w3 // Set warning level to 3.
Fine level: [+-]e<number>
► Example: +e1509 // Warn on non-virtual base class d-tor.
► Example: -e801 // Using 'goto' is fine.
“User Lint Policy” defines the right mix...
30. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
30/47
User Lint policy
The user Lint policy...
► is a text file containing global PC-lint settings for a project
► is fed to PC-lint during a Lint run
► mostly consists of message-related settings
► base warning level (e. g. 3) plus/minus many exceptions
► is not cast in stone but evolves over time
► allows for local overriding of settings in source files
31. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
31/47
Lint policy example
-function(__assert, ASSERT) // copy semantics of assert()
-strong(b,boolean) // BOOLEAN is of type boolean
+macros // enable long lines
-wlib(1) // in lib headers report only errors
-w3 // warning level 3
-A // strict ANSI
+fpn // argument pointers might be NULL
-esym(534,*printf) // often called without checking return
-esym(534,*strncat,*strncpy) // often called without checking return
-esym(534,*strcpy) // often called without checking return
-epn // nominally differing ptrs
-e787 // non-exhaustive switch
-e788 // non-exhaustive switch
-e508 // extern with definition
-e641 // enum to int conversion
-e730 // boolean arg to function
-e46 // fields other than int
-e655 // bit-wise operator used with enums
-"esym(793, external identifiers)" // don't complain about more than 511 external
...
32. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
32/47
Message inhibition
How to get rid of unwanted messages:
► Fully understand what PC-lint is saying (consult msg.txt)
► Modify the code (carefully!)
► Fix indentation
► Parenthesize
►
Use assertions
► cast
► Suppress locally via inhibition comments
(next slide)
► Last resort: #ifdef _lint
► Consider making (suggesting) changes to the Lint Policy
33. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
33/47
Inhibition within source code
Options within Lint comments:
► within source code: /*lint ... */ or //lint ...
► Note! No blank before 'lint' keyword!
//lint -e{888} hollyr: Needed for performance optimization
x = foo() * bar() - a;
Various variants exist that limit the scope of an inhibition
34. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
34/47
Inhibition comments
Next expression suppression:
a = /*lint -e(413) dereferencing 0 is OK */ *(char*)0);
One-line suppression:
if (x = f(34)) //lint !e720 boolean test of assignment is OK
y = y / x;
Within-a-macro suppression:
//lint -emacro(732, MULTIPLY) suppress loss of sign for macro MULTIPLY
Suppression for a particular symbol:
//lint -esym(754, MyClass::foo) suppress 'foo' not referenced
There are many, many more (see chapter 5.2 of PC-lint manual)
Advice: always use the narrowest inhibition scope possible!
35. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
35/47
The true value of PC-lint
Q: What's the purpose of using PC-lint?
A: Find bugs, of course!
36. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
36/47
When to use PC-lint?
1. Check-out
2. Coding
3. Developer testing
4. Check-in
5. Nightly/daily build
6. Integration testing
7. System testing
8. Release
here!
38. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
38/47
When linting late in the life-cycle
Code has already been tested and debugged
► Lots of effort has been spent (wasted) already
► Mostly only “false positives” left
Big mental distance
► Hard to remember the change
► Reluctance to change existing (working) code
►
Fear of introducing real bugs
►
Pride!
Developers often blindly dismiss warnings as “false positives”
39. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
39/47
When linting early in the life-cycle
Less time wasted on debugging
PC-lint acts as a coach
► Reviews code, criticizes
►
“software consciousness”
► Teaches C/C++ best practices
►
Over time, developers become better developers
PC-lint encourages developers to review their own code
► Often, even unrelated problems are found
Low mental distance
Low pride
Code is cleaned-up, rewritten, quality increased
40. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
40/47
How many lint warnings are acceptable?
0
41. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
41/47
“Zero Warnings” process
No warnings allowed when checking-in code
No “can't see the forest for the trees” effects
► Developers see only their issues
No tracking of PC-lint issues
► Management-free
No mental distance
► Issues must be resolved, now!
42. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
42/47
The true value of PC-lint
Q: What's the purpose of using PC-lint?
A: Prevent bugs and keep technical debt low!
This is Ward Cunningham,
inventor of the technical
debt metaphor.
My hero!
43. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
43/47
False positives
“In previously unlinted code, you may get a
discouragingly large number of messages”
The PC-lint Manual
44. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
44/47
False positives
1 #define ADD(x, y) x + y
2 #define MUL(x, y) x * y
3
4 class Base {
5 public:
6 Base(int i) : _i(i) { }
7 int add(int a, int b) { return ADD(a, b); }
8 ~Base() { /* ... */ }
9 private:
10 int _i;
11 };
12
13 class Derived : public Base {
14 };
false_positives.cpp:1 Info 773: Expression-like macro 'ADD' not parenthesized
false_positives.cpp:2 Info 773: Expression-like macro 'MUL' not parenthesized
false_positives.cpp:6 Note 1931: Constructor 'Base::Base(int)' can be used for implicit conversions
false_positives.cpp:7 Info 1762: Member function 'Base::add(int, int)' could be made const
false_positives.cpp:4 Info 1712: default constructor not defined for class 'Base'
false_positives.cpp:4 Info 1790: Base class 'Base' has no non-destructor virtual functions
false_positives.cpp:8 Warning 1509: base class destructor for class 'Base' is not virtual
false_positives.cpp:8 Warning 1512: destructor for base class 'Base' is not virtual
false_positives.cpp:2 Info 750: local macro 'MUL' not referenced
45. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
45/47
False positives
Based on the wrong notion about PC-lint
► Confusing “preventing” bugs with “finding” bugs
Almost every Lint warning is valuable
► Highlights technical debt
► If PC-lint has difficulties understanding code, another developer might
have as well
► Prevents future problems
► Self-reviews
46. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
46/47
Some final thoughts...
PC-lint is more about preventing bugs than about finding bugs
Not a magic weapon but another step towards higher quality
Use PC-lint as early as possible in your life-cycle
Try hard to understand what PC-lint is trying to say
Prefer rewriting code over suppression comments
Keep the number of warnings at all times at zero
PC-lint is your friend, not your enemy!
47. An Introduction to PC-lint Licensed under CC BY-NC-ND 3.0 by Ralf Holly Software Consulting
47/47
License
This presentation is licensed under the terms of the
Creative Commons - Attribution - Non Commercial - No Derivatives license.
See http://creativecommons.org/licenses/by-nc-nd/3.0/legalcode for details.