Techniques for debugging memory problems in C++

Length: Two days


C++ is a powerful, efficient language that allows developers to build sophisticated software systems. While it is a relatively modern language supporting object-oriented design, C++ is an extension of C and thus inherits C's explicit memory management model. Unfortunately, even the most competent and disciplined programmer has struggled at times with memory errors that plague the C/C++ memory management model. Memory leaks, memory smashes, and uninitialized pointer access are bugs that are often very difficult to track down and fix since the code that fails due to their presence can be quite distant both spatially and temporally from the code responsible for the error. Sometimes these logic errors can remain largely hidden until the code is ported to a different operating system or platform that manages memory differently. Large projects with large teams are especially susceptible to this memory mismanagement, and debugging memory problems can consume a significant portion of the development time.

Many books are available that describe programming and design in C++, but none provide much practical information to programmers about how to find these elusive memory errors. This tutorial identifies the types of memory problems that arise in C++. Many of these problems are shared with C, while some are unique to C++. Debugging strategies are discussed, and preventive measures are examined.


I.  Overview of the problem

A. Review of memory usage in C++

1. Code
2. Static data

3. Stack

4. Heap

B. The spatial and temporal distance of the introduction of memory error to its manifestation

1. Spatial--the global effects of memory errors

2. Temporal--memory errors as ticking time-bombs

C. Hidden errors that go unnoticed until porting to different platform

1. Operating system support for memory protection

2. Architectural differences in memory management

II. Memory errors

A. Memory leaks

1. The problem with long running programs like operating systems and web servers

2. The problem of determining in certain circumstances exactly when memory should be deallocated

B. Memory smashes

1. Array overruns
2. Using pointers to deallocated or unallocated memory

C. Uninitialized pointer access


III. Debugging techniques--finding the errors

A. Overview of features available to most debuggers

B. Absolute and conditional breakpoints

C. Debugger stack traces--navigating the execution stack

D. Inspecting memory and addresses

E. Structured data and objects

F. Interactive manipulation of data

IV. Object construction and destruction

A. The infamous "C++ Three"--assignment, copy construction, and destruction

B. Shallow vs. deep copying

C. "Secret" memory deallocation

V. Preventive measures

A. Defensive coding

1. Manual array range checking

2. Initializing all pointers and checking each access

3. Using conditional preprocessor directives and assertions

B. C++ smart pointers (handles)

1. Custom memory management

2. Customizing the pointer access operator to implement "smart" pointers

3. Instrumenting a custom memory manager for better debugging information

C. Implementing a garbage collector in C++

1. Garbage collection strategies

2. A simple reference counting garbage collector for C++


Send mail to [email protected] with questions or comments about this web site.
Copyright © 2014 Korson-McGregor.  All rights reserved.