In programming, bugs happen. They take a number of forms:

  • Syntax errors
  • Link-time errors
  • Runtime errors
  • Logic errors
  • Memory leaks

The aim of debugging is to find and fix such errors. With compiled code, syntax and link-time errors can often be identified through messages issued by the compiler and linker. The compiler may also aid in debugging runtime errors, via compiler options that enable trapping certain error conditions at runtime.

But the focus of this topic is on debugging trickier kinds of errors, such as when the program runs to completion but gives wrong answers due to a logic error, or when it runs for some time before crashing mysteriously. These cases generally call for runtime debugging, perhaps using tools that are designed for the purpose. Runtime debugging can be challenging—and its difficulty is compounded for parallel programs, where interactions among multiple processes or threads introduce further complications.

Runtime debugging involves inspecting the state of a running application, potentially pausing execution at certain points so that the contents of variables in memory can be inspected. The general idea is to understand what is happening when an application is running, and compare that against one's own notion about what should be happening.

In general, there are two main forms of debugging an application at runtime: ad-hoc instrumentation (e.g., with strategic "print" statements), and symbolic debugging with a debugger application. It turns out that these approaches are also useful for understanding why a program has terminated abnormally, after a crash has occurred.

This topic will not cover memory leaks, a type of problem in which memory continues to be allocated incrementally without being released as the program runs. This situation generally requires different tools such as valgrind.

 
©   Cornell University  |  Center for Advanced Computing  |  Copyright Statement  |  Inclusivity Statement