C++
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented C++
-
Section 4: Memory Management
-
Section 5: Templates and Generic Programming
-
Section 6: The Standard Template Library
-
Section 7: Modern C++ Features
-
Section 8: Error Handling
-
Section 9: Multithreading
-
Section 10: Operator Overloading and Type Conversion
-
Section 11: Advanced Topics
-
Section 12: Tooling and Build Systems
-
Section 13: Design Patterns in C++
-
Section 14: Interfacing with C and Systems Programming
-
Section 15: Networking and IPC Basics
-
Section 16: Graphics and Game Programming Basics
-
Section 17: The Boost Libraries
-
Section 18: Data Structures and Algorithms in C++
-
Section 19: Practical Projects
-
Section 20: More Concurrency Patterns
-
Section 21: More OOP and Design Practice
-
Section 22: File I/O and Streams
-
Section 23: More Standard Library
-
Section 24: Practice Exercises
-
Section 25: Interview and Algorithm Practice
-
Section 26: Compiler and Language Internals
-
Section 27: GUI and Application Frameworks Overview
-
Section 28: Testing and Quality Practices
-
Section 29: Numerics Library
-
Section 30: Concepts Library (C++20)
-
Section 31: Ranges Library (C++20) In Depth
-
Section 32: More Utility Library
132: Memory Debugging with Valgrind and Sanitizers
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
strlenandstrcpylogic). - 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.
There are no comments for now.