Catching Bugs in C with Lint

As you all have probably realized by now, C is not known for being a friendly language. In the best case, development is slow for even the simplest of tasks, and in the worst case… well… you’ve probably never been more tempted to through your laptop out the window. A lot of the frustrations with C come from the difficulty of fixing bugs in your code. The error messages can be cryptic unless you have a thorough understanding of the inner workings of your machine. Even then, the error messages may lead you down the wrong path of how to fix your code.

One tool that helps identify issues in your code in between making your change and compiling your code is lint. A linter is a static code checker which evaluates your code without compiling it. You can think of it as an extra set of eyes on your code – a set of eyes that doesn’t miss silly mistakes like memory leaks or uninitialized variables.

Linters exist for pretty much every language out there, and functionality between different tools range from language specific gotchas to styling. The original C lint program has had most of its functionality wrapped into the various C compilers over the years, but other tools have come and improved upon its legacy. One highly recommended option for C is cppcheck (works for both C and C++).

sudo apt-get install cppcheck

To check a file, simply run cppcheck on the file.

cppcheck myfile.c

As an example of the power of cppcheck, here’s a short program with a memory leak.

#include <stdlib.h>

void foo(int size) {
    int *array_pointer;
    array_pointer = (int *)malloc(size*sizeof(int));
    int i;
    for (i = 0; i < size; ++i)
    {
        array_pointer[i] = i;
    }
}

int main() {
    foo(10);
}

What does cppcheck say about this program?

jgibson@ubuntu:~$ cppcheck debugging_exercise.c 
Checking debugging_exercise.c...
[debugging_exercise.c:13]: (error) Memory leak: array_pointer

Cppcheck tells you exactly where the memory leak is, making it quick and simple to fix.

Cppcheck is not perfect. For example, if you add a printf statement at the end of foo(), it tricks cppcheck into not finding the memory leak, even though it is still there.

#include <stdlib.h>
#include <stdio.h>

void foo(int size) {
    int *array_pointer;
    array_pointer = (int *)malloc(size*sizeof(int));
    int i;
    for (i = 0; i < size; ++i)
    {
        array_pointer[i] = i;
    }
    printf("Array at index 6 is %i!\n", array_pointer[6]);
}

int main() {
    foo(10);
}
jgibson@ubuntu:~$ cppcheck debugging_exercise.c 
Checking debugging_exercise.c...

Cppcheck won’t catch all of the problems with your code, but it will help catch a large portion of them before you have to deal with C’s atrocious error messages.

For more info on cppcheck and how to use it, check out their documentation. You can look through their complete list of what they check for as well as some of the more advanced features such as ignoring certain warnings.

Advertisements