Identifying the Root Causes of Memory Bugs Using Corrupted Memory Location Suppression Dennis Jeffrey Univ. of California, Riverside jeffreyd@cs.ucr.edu Neelam Gupta guptajneelam@gmail.com Rajiv Gupta Univ. of California, Riverside gupta@cs.ucr.edu Abstract We present a general approach for automatically isolat- ing the root causes of memory-related bugs in software. Our approach is based on the observation that most memory bugs involve uses of corrupted memory locations. By itera- tively suppressing (nullifying) the effects of these corrupted memory locations during program execution, our approach gradually isolates the root cause of a memory bug. Our ap- proach can work for common memory bugs such as buffer overflows, uninitialized reads, and double frees. However, our approach is particularly effective in finding root causes for memory bugs in which memory corruption propagates during execution until an observable failure such as a pro- gram crash occurs. 1. Introduction Software programming is an error-prone activity. Mis- takes and misunderstandings can translate to program source code in the form of errors called bugs. These bugs can affect the behavior of programs in potentially disastrous ways. Due to the prevalence of software systems presently in use – including those used in critical, life-or-death do- mains – the task of locating and removing software bugs is a necessity. This task is called Software Debugging. Debug- ging involves a series of steps that can be slow, tedious, and difficult. These steps include: locating bugs in the source code; understanding the nature of the bugs; and modifying the source code to eliminate the bugs without introducing any new bugs. The task of debugging can be especially challenging in large and complex software systems. Tech- niques to help automate the debugging process can assist developers in more efficiently eliminating bugs, resulting in more robust and reliable software. Memory-related bugs, such as buffer overflows and uninitialized reads, are an important class of software bugs that are particularly tricky to handle. This is because the corrupted memory locations resulting from these bugs can sometimes make it difficult to link an observed program failure – such as a crash or corrupted value – to the root cause. The effect of one corrupted memory location can propagate (spread) to other memory locations during pro- gram execution. By the time an observable program fail- ure occurs due to some corrupted memory location, many other memory locations could have already become cor- rupted. Thus, the root cause of the bug may be far removed from the point at which the bug becomes apparent. Also, different kinds of memory-related problems can influence each other even though they may all be due to a single root cause. For instance, a program bug could lead to a buffer overflow that unexpectedly corrupts the value of some vari- able, yet does not immediately exhibit any obvious failure. Later on, the corrupted variable may be used to read from an uninitialized memory location containing an arbitrary value, and that arbitrary value could then be passed to the function “free” which may finally result in a program crash. In a complex case such as this, it may take considerable effort to sort through all of the memory-related problems to isolate the root cause. Tools and techniques for debugging that do not work well for memory bugs, or that specialize in detect- ing only certain kinds of memory bugs, may therefore have limited effectiveness in general at isolating the root causes of memory bugs. In this paper, we present a generalized approach that fo- cuses on isolating the root causes of memory bugs. Our approach views a memory-related bug as an instruction that corrupts some memory location, which can in turn corrupt other memory locations as the effect propagates arbitrar- ily far during execution until an observable program fail- ure occurs. The key assumption motivating our approach is the following: if a program execution reveals a mem- ory bug and the effect of the root cause of that bug is sup- pressed (nullified) during program execution, then all re- sulting memory corruption will be avoided and no memory- related failure will occur. Based on this assumption, we propose an approach that searches for the root cause of a memory bug by repeatedly executing a program on the same failing input; on each re-execution, we suppress the direct 978-1-4244-2614-0/08/$25.00 2008 IEEE ICSM 2008 356