Segmentation faults and other memory bugs (reading uninitialized memory, reading/writing beyond the bounds of an array, memory leaks, etc.) can be hard to track down with a traditional debugger. Memory errors can be elusive, and may not cause the program to crash immediately. A program with memory errors may even appear to work correctly on some datasets or on some machines.
We'll discuss the Dr. Memory and Valgrind memory debugging tools and the memory error reports these tools produce at the end of Lecture 7 and during Lab 5. You'll be expected to use one of these tools for debugging starting with Homework 3. The homework submission server and the TAs will use these tools for grading your homework.
Dr. Memory is available for GNU/Linux, Microsoft Windows, and MacOSX operating systems. For questions, bug reports, and discussion, use the Dr. Memory Users group: http://groups.google.com/group/drmemory-users
Please report issues with Dr. Memory to the Dr. Memory Users Group by email: email@example.com. Be sure to include details about your operating system and the Dr. Memory version number. Don't send your full homework submission (it is a public mailing list).
Dr. Memory on GNU/Linux or Windows Subsystem for Linux (WSL)
Dr. Memory on Mac OSX
tar -xvzf DrMemory-YourOperatingSystem-VersionXX.tar.gz
We'll assume DrMemory is in the directory "~/DrMemory-YourOperatingSystem-VersionXX/" for the rest of these instructions.
g++ -g -m32 main.cpp foo_main.cpp foo_other.cpp -o foo.out
~/DrMemory-YourOperatingSystem-VersionXX/bin/drmemory -brief -- foo.out arg1 arg2
Installing Dr. Memory on Windows (not Windows Subsystem for Linux (WSL))
Dr. Memory and MinGW
Dr. Memory does not support programs that use the Cygwin emulation layer. Thus, we cannot use Dr. Memory with programs built using the Cygwin version of g++. Instead, we will build our program with the MinGW g++ compiler (Minimalist GNU for Windows):
i686-w64-mingw32-g++.exe --static -ggdb -o foo.exe foo_main.cpp foo_other.cppIf you've made the shortcut suggested under Helpful edits to the Cygwin .bashrc file, you can equivalently type:
memg++ -o foo.exe foo_main.cpp foo_other.cpp
This makes a program called foo.exe, using source files foo_main.cpp and foo_other.cpp . The below example assumed that your program is called foo.exe and takes two arguments arg1 and arg2. If you don't know what arguments are, your program probably doesn't take any.
drmemory -brief -batch -- foo.exe arg1 arg2
Replace "foo.exe arg1 arg2" with your program name and any command line arguments for your program.
Dr. Memory and Visual Studio
Alternatively, you can use Dr. Memory with the Microsoft Visual Studio compiler:
Using the Visual Studio compiler without the Visual Studio Integrated Development Environment (IDE)
cl /Zi /MT /EHsc /Oy- /Ob0 /Fehw.exe *.cpp
drmemory -brief -batch -- foo.exe arg1 arg2
If you don't see any extra output from Dr. Memory as your program runs, remove the -batch flag and the Dr. Memory output will be sent to a file and notepad will launch automatically to display this file.
drmemory -brief -- foo.exe arg1 arg2
Valgrind only works on Unix-based systems (e.g., GNU/Linux, FreeBSD, and MacOSX). Valgrind does not work on Cygwin because Cygwin emulates UNIX at the library layer, but Valgrind operates at the system call layer and the Windows system calls are significantly different than UNIX system calls. Note: Valgrind on the more recent Mac OSX versions 10.8 & 10.9 is still a work in progress -- you will likely see false positive memory errors, but it may still be a helpful tool in debugging.
To use Valgrind...
brew install valgrind
g++ -g main.cpp foo_main.cpp foo_other.cpp -o foo.out
valgrind --leak-check=full --show-reachable=yes ./foo.out arg1 arg2
If that example run of your program contains any memory errors Valgrind will output information to help you track down the error. Note that using Valgrind can significantly slow down execution time as it inspects every memory action. You may need to craft a smaller test case that exhibits the same bug you would like to solve.
Note: Because some STL classes (including string) use their own allocators (and do other optimization tricks), there may be a warning about memory that is ``still reachable'' even though you've deleted all your dynamically allocated memory. The newer versions of Valgrind automatically suppresses some of these common false positive errors, so you may see this listed as a ``suppressed leak''.
Suppression of False Positives in Valgrind
If you see false positive error messages in Valgrind (this is likely to happen with Valgrind on the newest versions of Mac OSX), you will probably want to create an error suppression file to allow you to focus on your actual errors.
valgrind --leak-check=full --gen-suppressions=all ./foo.out arg1 arg2
valgrind --leak-check=full --suppressions=my_suppressions.txt ./foo.out arg1 arg2
Read more about Valgrind suppressions here:
ASAN (Address Sanitizer) is a memory debugger developed by Google, and is built into recent versions of C/C++ compilers. Note: It currently only works on unix-based systems. ASAN does not currently work in Windows (including the WSL) due to differences in memory allocations.
Unlike the other memory debuggers, which require you to rerun your code through the memory debugger, ASAN just requires you to recompile it with two extra flags, and then rerun it as usual. Because ASAN is built-in to the compiler, it tends to be much faster than the other debuggers. ASAN also will immediately abort at the first error (i.e. invalid read/write) unlike the other debuggers, which will continue running if possible. ASAN's method tends to be a bit more helpful, since you only have one error to focus on, but it doesn't always give you the full picture that you may need. Additionally, unlike the other memory debuggers, ASAN doesn't print anything if it detects no errors. The other debuggers will always end up printing some output when you run them, but since ASAN is built into your program, there's no additional output when there are no errors. If you run a program after compiling it with ASAN, and you see no extra output, that doesn't mean that ASAN isn't working - it means that you don't have any memory errors!
On OS X and Linux, you should already have g++ and/or clang already installed, which is all you need. To compile your program with ASAN, add the -g, -fsanitize=address, and -fno-omit-frame-pointer flags like so:
g++ -g -fsanitize=address -fno-omit-frame-pointer main.cpp foo_main.cpp foo_other.cpp -o foo.out
You can now just rerun your program as usual (i.e. ./foo.out arg1 arg2) and it will run with memory debugging.
Optional helpful edits for ASAN
If you don't wish to have to remember the compile flags, you can add the following alias to your shell rc like so:
echo 'alias memg++="g++ -g -fsanitize=address -fno-omit-frame-pointer"' >> ~/.bashrc && source ~/.bashrc
With this, you can then compile programs for ASAN by just specifying memg++ instead of g++ or clang. For example, the following two commands are equivalent:
g++ -g -fsanitize=address -fno-omit-frame-pointer main.cpp foo_main.cpp foo_other.cpp -o foo.out memg++ main.cpp foo_main.cpp foo_other.cpp -o foo.out
Additionally, ASAN tends to be a bit verbose, with its output, so unless you understand what shadow memory is, it's recommended that you add the following ASAN runtime options:
echo 'export ASAN_OPTIONS=print_legend=0' >> ~/.bashrc && source ~/.bashrc
If you encounter a memory error, you'll see some un-suppressable output that indicates what part of memory the error is occuring. You'll generally want to look at the output above it that includes line information about where objects were allocated, freed, and accessed from, instead.