Static Code Checkers: lint and Friends

There are a number of free and commercial tools that scan your code without compiling it and warn you about errors, possible errors, and deviations from strict C coding standards. They are appropriately named static code checkers. The canonical static code checker for C, written by S.C. Johnson in the late 1970s, was called lint. It was written mainly to check function calls, as early versions of C didn't support prototyping. lint spawned many derivative static checkers. One such checker, written by Dave Evans of the University of Virginia's computer science department, was named lclint and was popular on modern systems like Linux. In January 2002, Dave renamed lclint to splint to emphasize the increased focus on secure programming (and because splint is easier to pronounce than lclint).

The aim of splint is to help you write the most defensive, secure, and error-free program possible. splint, like its predecessors, can be very picky about what constitutes good code.[23] As an exercise, try to find anything in the following code that might cause a warning:

Example Listing 7-5. scan.c

int main(void)
{
   int i;

   scanf("%d", &i);

   return 0;
}

When this code is run through splint, it warns that you're discarding the return value of scanf().[24]

$ splint test.c
Splint 3.0.1.6 --- 11 Feb 2002

test.c: (in function main)
test.c:8:2: Return value (type int) ignored: scanf("%d", &i)
   Result returned by function call is not used. If this is intended, can cast
   result to (void) to eliminate message. (Use -retvalint to inhibit warning)

   Finished checking --- 1 code warning

All splint warnings have a fixed format. The first line of a splint warning tells you the filename and function where the warning occurs. The next line gives the line number and position of the warning. After that is a description of the warning, along with instructions on how to go about suppressing this kind of warning. As you can see here, invoking splint -retvalint test.c turns off all warnings about discarding integer function return values. Alternatively, if you don't want to turn off all reports about discarded int return values, you can suppress the warning for just this call to scanf() by typecasting scanf() to void. That is, replace scanf("%d", &i); with (void) scanf("%d", &i);. (There's yet another way to suppress this warning, by using annotations, which the interested reader can learn about from the splint documentation.)

splint comes with a staggering number of switches, but as you use it, you'll get a feel for which ones typically suit your needs. Many switches are Boolean in nature—they turn a feature on or off. These types of switches are preceded by a + to turn them on or a - to turn them off. For example, -retvalint turns off reporting of discarded int return values, and +retvalint turns this reporting on (which is the default behavior).

There are two ways to use splint. The first is informal and is used mainly when you're running splint on someone else's code or on code that's mostly final:

$ splint +weak *.c

Without the +weak switch, splint is typically too picky to be useful. There are three levels of checking in addition to +weak. You can get more details about them from the splint manual, but they are, briefly, as follows:

+weak Weak checking, typically for unannotated C code
+standard The default mode
+checks Moderately strict checking
+strict Absurdly strict checking

The more formal use of splint involves documenting your code specifically for use with splint. This splint-specific documentation is called an annotation. Annotation is a large topic, and it would take us too far afield to include it in this book, but it is well covered in the splint documentation.

splint supports many, but not all, of the C99 library extensions. It also doesn't support some of the C99 language changes. For instance, splint doesn't know about complex data types or about defining an int variable in the initializer of a for loop.

splint is released under the GNU GPL. Its homepage is at http://www.splint.org/.



[23] Many programmers consider it a badge of honor when splint reports no warnings. When this happens, the code is declared lint free.

[24] The return value of scanf() is the number of input items that were assigned.