Finding Memory Leaks in Linux Programs with VisualGDB

This tutorial shows how to find memory leaks in Linux programs using the VisualGDB integration with valgrind. Before you begin, install VisualGDB 5.3 or later.

We will create a basic projectthat will randomly leak memory and will then use the Dynamic Analysis feature of VisualGDB to automatically run the program under Valgrind and produce a detailed report on memory leaks.

  1. Start Visual Studio and open the VisualGDB Linux Project Wizard:01-prj
  2. Select “Create a new project” -> “Application” -> “MSBuild”:02-app
  3. Select the Linux computer you would like to target. VisualGDB will automatically check that it has all necessary tools and will install the missing ones:03-target
  4. Proceed with the default option of keeping all source files on the Windows machine and uploading them during builds:
    04-disp
  5. Press “Finish” to create your project. Replace the contents of the main source file with the following code demonstrating memory leaks:
    #include <iostream>
    #include <stdlib.h>
    #include <string>
     
    template <int X> void AllocAndMaybeFree()
    {
        char *pTest = new char[X];
        if (rand() % 5)
            delete[] pTest;
    }
     
    int main(int argc, char *argv[])
    {
        AllocAndMaybeFree<1>();
        AllocAndMaybeFree<2>();
        AllocAndMaybeFree<3>();
        AllocAndMaybeFree<4>();
        AllocAndMaybeFree<5>();
        AllocAndMaybeFree<6>();
        AllocAndMaybeFree<7>();
        AllocAndMaybeFree<8>();
        AllocAndMaybeFree<9>();
        AllocAndMaybeFree<10>();
        return 0;
    }

    In real-world scenarios the memory is allocated in multiple different parts of the program, and if some of those allocations are not released, the memory leaks. We are simulating this with the AllocAndMaybeFree() function that will “forget” to free the allocated memory block with a 20% probability. We use the template argument to make different invocations of the function appear differently in the call stack, as if we had 10 distinct functions potentially leaking memory. Build the project and ensure is results in no errors:05-code

  6. Now we will show how to run the program under Valgrind. Open VisualGDB Project Properties, go to the Dynamic Analysis page and enable the “Analyze program behavior during runtime” checkbox:
    06-analyze
  7. Press OK and start debugging your program. VisualGDB will automatically launch valgrind and attach gdb to it. You will see the diagnostic output in the Valgrind Diagnostics window, but the rest of the debugging experience will be the same as if you were debugging your program regularly:07-debug
  8. Once the program exits, Valgrind will display the summary of the discovered memory leaks:
    08-summary
  9. Open VisualGDB Project Properties again and switch the “Memory leaks” setting to “Full list”:
    09-full
  10. Run the program again. Valgrind will now report full call stacks of the allocations that were never freed, showing how calls #4 and #6 resulted in memory leaks:10-stacks
  11. You can also analyze the leaks in real time using the GDB Session window in VisualGDB. Simply run the “mon leak_check” command while debugging under valgrind:11-check
  12. Valgrind will output the summary of the current allocations:
    12-initial
  13. If you re-run the command after a memory block is allocated, not freed and not pointed by any other block, the “mon leak_check” command will report it as “definitely lost” showing the allocation stack:13-new
  14. Valgrind will also automatically handle references between the blocks. We will demonstrate this by allocating an instance of a class that includes an STL string. Replace the main file contents with the following code:
    #include <iostream>
    #include <stdlib.h>
    #include <string>
     
    using namespace std;
     
    class DemoClass
    {
    public:
        std::string Test = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
    };
     
    void func()
    {
        DemoClass *p = new DemoClass();
    }
     
    int main(int argc, char *argv[])
    {
        func();
        return 0;
    }

    14-class

  15. Set a breakpoint in the func() function and start debugging. Once the breakpoint is hit, run the “mon leak_check” command (use the ‘up’ button in the GDB Session window to repeat the previous command instead of re-typing it):
    15-reach
  16. Step over the allocation line and re-run the “mon leak_check” command: 16-reach2Note how the “still reachable” blocks have grown by 2 and no leak is reported yet. This happens because the ‘p’ variable still points to the newly allocated memory and valgrind assumes it might be freed later.
  17. Step out of the func() function and re-run “mon leak_check”. Now valgrind will report a memory leak. Note how the memory block allocated by the STL string is not reported separately (it is  shown as +1) as it is only referenced by the already reported block:
    17-leak

VisualGDB also provides a convenient way to analyze your program performance using Valgrind. See our Linux Profiling Tutorial for a detailed step-by-step guide.