views:

94

answers:

3

I am interested to know on what things I need to concentrate on debugging c code without a debugger. What are the things to look for?

Generally I look for the following:

  1. Check whether correct value and type is being passed to a function.
  2. Look for unallocated and uninitialized variables
  3. Check for function syntax and function is used in right way.
  4. Check for return values
  5. Check for locks are used in the right way.
  6. Check for string termination
  7. Returning a varible in stack memory from a function
  8. Off by one errors
  9. Normal syntax errors
  10. Function declaration errors

Any structured approach is very much appreciated.

+2  A: 

Most of these errors will be picked up by passing the appropriate warning flags to the compiler.

However from the original list, points 1, 5, 6, 7, 8 are very much worth checking as a human, some compiler/flag combinations however will pick up on unhandled values, pointers to automatic memory, and off-by-one errors in array indexing etc.

You may want to take a look at such things as mudflap, valgrind, efence and others to catch runtime cases you're unaware of. You might also try splint, to augment your static analysis.

For the unautomated side of things, try statically following the flow of your program for particular cases, especially corner cases, and verify to yourself that it appears to do the right thing. Try writing unit tests/test scripts. Be sure to use some automated checking as discussed above.

If your emphasis is on testing without any test execution, splint might very well be the best place to start. The technique you want to research is called static code analysis.

Matt Joiner
@Matt Thank you very much
mousey
+1  A: 

I recommend trying one of the many static code analyzers. Those that I used personally and can recommend:

  • cppcheck - free and open-source, has cmd-line program and windows gui
  • Clang Static Analyzer - Apple's free and open-source, best supported on mac, also built in recent XCode versions
  • Visual Studio's static checker, only available in Premium and Ultimate (i.e. expensive) versions
  • Coverity - expensive

If you want more details, you can read an article I wrote on that subject.

Krzysztof Kowalczyk
@kryz What does static analyzers do and how is it useful ?
mousey
To quote from the article I linked to "Static code analysis tools can analyze C/C++ code without running it (hence the “static” part) and find a multitude of issues, like memory leaks, using uninitialized variables, freeing memory twice etc."
Krzysztof Kowalczyk
@kryz how they can do it without compiling or running ?
mousey
Writing a static analyzer for C is super advanced topic that can't be explained in few words. See http://stackoverflow.com/questions/411682/introduction-to-static-analysis for tips on where to start learning about it.I don't know what your definition of compiler is (or why does it matter how static analyzers do their job). Clearly, a lot of the techniques they use are similar to what compiler does. However, compiler's goal is to generate executable code, static analyzer's goal is to find bugs in the code.
Krzysztof Kowalczyk
@Krzysztof Kowalczyk thank you very much
mousey
+1  A: 

A big one you left out is integer overflow. This includes both undefined behavior from overflow of signed expressions, and well-defined but possibly-dangerous behavior of unsigned overflow being reduced mod TYPE_MAX+1. In particular, things like foo=malloc(count*sizeof *foo); can be very dangerous if count came from a potentially untrusted source (like a data file), especially if sizeof *foo is large.

Some others:

  • mixing of signed and unsigned values in comparisons.
  • use of functions with locale-specific behavior (e.g. radix character, case mapping, etc.) when well-defined uniform behavior is needed.
  • use of char when doing anything more than copying values or comparison for equality (otherwise you probably want unsigned char or perhaps in rare cases, signed char).
  • use of signed expressions with /POWER_OF_2 and %POWER_OF_2 (hint: (-3)%8==-3 but (-3)&7==5).
  • use of signed division/modulo in general with negative numbers, since C's version of it disagrees with the usual algebraic definition when a negative number is divided by a positive one, and rarely gives the desired result.
R..
@R.. Thank you very much.
mousey