Skip to Content
Course content

132: Memory Debugging with Valgrind and Sanitizers

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Which one should I use: Valgrind or AddressSanitizer?

I get asked this a lot because, on the surface, they seem to do the same thing. The short answer is: use both, but at different times. AddressSanitizer (ASan) is built into the compiler (GCC and Clang). It's incredibly fast—usually only a 2x slowdown—because it instruments your code during compilation. If you're running a massive test suite, ASan is your best friend.

Valgrind is different. It's a virtual machine that runs your binary. It doesn't require special compilation flags (though you still want -g for symbols), and it's far more thorough when it comes to detecting uninitialized memory reads. The trade-off? It's slow. Like, "I can go grab a coffee while this runs" slow. I usually start with ASan during active development and run Valgrind in my CI pipeline or before a big release to catch the subtle stuff ASan might miss.

To use ASan, just add the flag to your compile and link steps:

g++ -fsanitize=address -g main.cpp -o my_app

I'm seeing "Invalid write of size 4"—how do I actually find the bug?

When Valgrind or ASan screams about an "Invalid write" or "Heap buffer overflow," they're telling you that you've stepped outside the memory you actually allocated. This is the classic C++ nightmare: you're corrupting memory, and the program might not crash until ten functions later, making the debugger useless.

Take a look at this snippet. It looks harmless, but it's a landmine:

void process_data(int size) {
    int* buffer = new int[size];
    for (int i = 0; i <= size; ++i) { // Off-by-one error!
        buffer[i] = i * 2;
    }
    delete[] buffer;
}

If you run this through Valgrind, it won't just say "it crashed." It will tell you exactly which line performed the invalid write and, more importantly, where that memory was originally allocated. If you didn't compile with -g, you'll just see hex addresses, which are useless to us humans. Always use debug symbols when debugging memory.

What's the difference between "definitely lost" and "possibly lost" in a leak report?

This is where Valgrind's reporting can get confusing. When you see "definitely lost," it means you've leaked memory and you no longer have any pointer pointing to the start of that block. You've effectively deleted the map to the treasure; that memory is gone until the process ends.

"Possibly lost" is a bit more nuanced. It means Valgrind found a pointer to the memory, but it's not pointing to the beginning of the block. For example, if you have a pointer that you've incremented (ptr++) and you then try to free it, or if you're using some clever internal pointer arithmetic, Valgrind gets suspicious.

I've found that "possibly lost" is often a false positive if you're using a custom memory allocator or a very complex data structure. However, if you're writing standard C++, a "possibly lost" warning is usually a sign that you're doing something risky with your pointers that will eventually lead to a crash.




📋 Practical Task

Fixing the Corrupted Registry Buffer

You've been handed a piece of legacy code that manages a simple system registry. The program currently crashes intermittently or reports "garbage" values in the logs. Your task is to use AddressSanitizer or Valgrind to find and fix two distinct memory errors: a heap buffer overflow and a memory leak.

#include <iostream>
#include <cstring>

class Registry {
    char* data;
public:
    Registry(const char* input) {
        data = new char[strlen(input)]; 
        strcpy(data, input); 
    }
    ~Registry() {
        // The developer forgot something here!
    }
    void print() { std::cout < "Registry value: " < data < std::endl; }
};

int main() {
    Registry* reg = new Registry("SystemConfig_v1");
    reg->print();
    // The registry object itself is never cleaned up!
    return 0;
}

Requirements:

  • Compile the code with -fsanitize=address -g.
  • Run the binary and identify the "heap-buffer-overflow" (Hint: look closely at the strlen and strcpy logic).
  • Identify the "memory leak" (Hint: there are two different allocations happening).
  • Fix both bugs so that the program runs with zero errors and zero leaks.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.