Finding improper memory usage

Updated: April 19, 2023

The IDE includes tools that identify lines of code that corrupt memory or cause thread synchronization problems. This information helps you debug process crashing and improper program results.

When you suspect that memory corruption is making a program misbehave, you should run the debugger and try reproducing the bad behavior. This can help in simple cases, but debugging often fails to find the source of corruption because such errors typically appear in unrelated parts of the program. In this case, you must run tools that track memory allocation and report details about illegal operations.

There's a trade-off between the level of memory checking performed and the overhead imposed by an analysis tool. More memory checking uncovers more problems but slows operations noticeably and may exhaust available system memory. In general, you should try using the tools in the following order:
  1. Valgrind Memcheck

    This tool checks all memory reads and writes to detect improper memory uses. It reports out-of-bounds accesses and bad pointer parameters but also finds many subtle bugs including:
    • Overlapping memory regions in source and destination pointers
    • Use of uninitialized or freed memory
    • Suspicious parameters, such as negative or excessively large positive values for allocation sizes

    Memcheck doesn't require recompiling the application but does impose substantial overhead, causing the program to run at one-tenth its normal speed (or slower), and increases the memory footprint by two to three times. Also, Valgrind reports the results only when the program terminates, so you can't see corruption errors in real time with Memcheck.

  2. Memory Analysis

    Based on the data produced by the debug allocation library (librcheck), Memory Analysis reports common memory errors, including out-of-bounds data writes and bad pointers given to memory- and string-management functions.

    This tool is easy to set up, not requiring you to recompile the application, and imposes low overhead compared to Memcheck. However, its memory checks are limited, so it may not find many errors.

In multithreaded programs, bad behavior is sometimes caused by a lack of thread synchronization. But tracking down thread synchronization errors is hard because the timing of operations is unpredictable and thus, results aren't always reproducible. You can debug such programs with the following tool:

You must run a binary built with debug information so the active tool can match binary instructions with lines of code and display the symbols (i.e., backtrace) in the results. To see symbols for shared libraries, your host machine must store debug versions of these libraries. Any binary with debug information has a bug icon (Icon: Small blue bug) next to its name in the Project Explorer. The binary selected for running when you launch a project depends on the launch configuration settings.

If after using the memory-checking tools you still can't find and fix some problems, you should try running a kernel event trace, to find any odd interactions between threads within your program or between your program and another process. Or, you can keep using the conventional debugger to narrow down the cause of improper program results or process crashing.