Visual Leak Detector 1.0

Enhanced Memory Leak Detection for Visual C++

Table of Contents

Introduction

Visual C++ provides built-in memory leak detection, but its capabilities are minimal at best. This memory leak detector was created as a free alternative to the built-in memory leak detector provided with Visual C++. Here are some of Visual Leak Detector's features, none of which exist in the built-in detector:

Other after-market leak detectors for Visual C++ are already available. But most of the really popular ones, like Purify and BoundsChecker, are very expensive. A few free alternatives exist, but they're often too intrusive, restrictive, or unreliable. Here's some key advantages that Visual Leak Detector has over many other free alternatives:

Visual Leak Detector is licensed free of charge as a service to the Windows developer community. If you find it to be useful and would like to just say "Thanks!", or you think it stinks and would like to say "This thing sucks!", please feel free to drop me a note. Or, if you'd prefer, you can contribute a small donation. Both are very appreciated.

Using Visual Leak Detector

This section briefly describes the basics of using Visual Leak Detector (VLD). If your project contains DLLs that you'd like to also check for memory leaks, please see Detecting Leaks in DLLs.

To use VLD with your project, follow these simple steps:

  1. Copy the VLD library (*.lib) files to your Visual C++ installation's "lib" subdirectory.
  2. Copy the VLD header files (vld.h and vldapi.h) to your Visual C++ installation's "include" subdirectory.
  3. In the source file containing your program's main entry point, include the vld.h header file. It's best, but not absolutely required, to include this header before any other header files, except for stdafx.h. If the source file includes stdafx.h, then vld.h should be included after it.
  4. If you are running Windows 2000 or earlier, then you will need to copy dbghelp.dll to the directory where the executable being debugged resides.
  5. Build the debug version of your project.

VLD will detect memory leaks in your program whenever you run the debug version under the Visual C++ debugger. A report of all the memory leaks detected will be displayed in the debugger's output window when your program exits. Double-clicking on a source file's line number in the memory leak report will take you to that file and line in the editor window, allowing easy navigation of the code path leading up to the allocation that resulted in a memory leak.

Note: When you build release versions of your program, VLD will not be linked into the executable. So it is safe to leave vld.h included in your source files when doing release builds. Doing so will not result in any performance degradation or any other undesirable overhead.

Configuration Options

There are a few optional preprocessor macros that you can define to control certain aspects of VLD's operation, including the level of detail provided in the memory leak report:

VLD_AGGREGATE_DUPLICATES

Normally, VLD displays each individual leaked block in detail. Defining this macro will make VLD aggregate all leaks that share the same size and call stack under a single entry in the memory leak report. Only the first leaked block will be reported in detail. No other identical leaks will be displayed. Instead, a tally showing the total number of leaks matching that size and call stack will be shown. This can be useful if there are only a few sources of leaks, but those few sources are repeatedly leaking a very large number of memory blocks.

VLD_MAX_TRACE_FRAMES

By default, VLD will trace the call stack for each allocated block as far back as possible. Each frame traced adds additional overhead (in both CPU time and memory usage) to your debug executable. If you'd like to limit this overhead, you can define this macro to an integer value. The stack trace will stop when it has traced this number of frames. The frame count includes the "useless" frames which, by default, are not displayed in the debugger's output window (see VLD_SHOW_USELESS_FRAMES below). Usually, there will be about five or six "useless" frames at the beginning of the call stack. Keep this in mind when using this macro, or you may not see the number of frames you expect.

VLD_MAX_DATA_DUMP

Define this macro to an integer value to limit the amount of data displayed in memory block data dumps. When this number of bytes of data has been dumped, the dump will stop. This can be useful if any of the leaked blocks are very large and the debugger's output window becomes too cluttered. You can define this macro to 0 (zero) if you want to suppress data dumps altogether.

VLD_SELF_TEST

VLD has the ability to check itself for memory leaks. This feature is always active. Every time you run VLD, in addition to checking your own program for memory leaks, it is also checking itself for leaks. Defining this macro forces VLD to intentionally leak a small amount of memory: a 21-byte block filled with the text "Memory Leak Self-Test". This provides a way to test VLD's ability to check itself for memory leaks and verify that this capability is working correctly. This macro is usually only useful for debugging VLD itself.

VLD_SHOW_USELESS_FRAMES

By default, only "useful" frames are printed in the call stacks. Frames that are internal to the heap or VLD are not shown. Define this to force all frames of the call stacks to be printed. This macro is usually only useful for debugging VLD itself.

VLD_START_DISABLED

Define this macro to disable memory leak detection initially. This can be useful if you need to be able to selectively enable memory leak detection from runtime, without needing to rebuild the executable; however, this macro should be used with caution. Any memory leaks that may occur before memory leak detection is enabled at runtime will go undetected. For example, if the constructor of some global variable allocates memory before execution reaches a subsequent call to VLDEnable, then VLD will not be able to detect if the memory allocated by the global variable is never freed. Refer to the following section on controlling leak detection at runtime for details on using the runtime APIs which can be useful in conjunction with this preprocessor macro.

Controlling Leak Detection at Runtime

Using the default configuration, VLD's memory leak detection will be enabled during the entire run of your program. In certain scenarios it may be desirable to selectively disable memory leak detection in certain segments of your code. VLD provides simple APIs for controlling the state of memory leak detection at runtime. To access these APIs, include vldapi.h in your source file. These APIs are described here in detail:

VLDDisable

This function disables memory leak detection. After calling this function, memory leak detection will remain disabled until it is explicitly re-enabled via a call to VLDEnable.

void VLDDisable (void);

Arguments:

This function accepts no arguments.

Return Value:

None (this function always succeeds).

Notes:

This function controls memory leak detection on a per-thread basis. In other words, calling this function disables memory leak detection for only the thread that called the function. Memory leak detection will remain enabled for any other threads in the same process. This insulates the programmer from having to synchronize multiple threads that disable and enable memory leak detection. However, note also that this means that in order to disable memory leak detection process-wide, this function must be called from every thread in the process.

VLDEnable

This function enables memory leak detection if it was previously disabled. After calling this function, memory leak detection will remain enabled unless it is explicitly disabled again via a call to VLDDisable().

void VLDEnable (void);

Arguments:

This function accepts no arguments.

Return Value:

None (this function always succeeds).

Notes:

This function controls memory leak detection on a per-thread basis. See the remarks for VLDDisable regarding multithreading and memory leak detection for details. Those same concepts also apply to this function.

Detecting Leaks in DLLs

VLD is capable of detecting memory leaks in DLLs. But DLLs can present special situations that need to be carefully considered to ensure that VLD can properly do its job. When using DLLs, you will have more than one module. Each DLL is a module and the main executable is also a module. VLD should be linked with only one module per process. So the question is: which module should VLD be linked with? The answer will depend on whether your DLLs are load-time linked or run-time linked. The general rule of thumb is that VLD should always be linked with the module that is initialized first.

Load-Time Dynamic Linking

This is probably the most commonly used way to link with DLLs. If your program doesn't use LoadLibrary to load your DLL, then this is the type of dynamic linking your program uses. With this form of linking, the DLL is initialized before the program's main executable. Therefore, the DLL is the first module to be initialized and VLD should be linked with the DLL. Include vld.h in the main source file for the DLL.

Of course, there will most likely be several system DLLs that are loaded before any of your own DLLs. You don't need to worry about linking VLD with those DLLs, because those DLLs are not being checked for memory leaks. Only your own DLLs will be checked for leaks so VLD only needs to be linked with the first DLL of your own which is loaded first.

As was mentioned earlier, you should only link VLD with one module. In almost all situations, linking VLD with just one module that will be loaded in a given process will enable VLD to detect memory leaks in all other modules loaded in the same process. This means that if your program links with several load-time DLLs, you only need to link with one of them -- the one that is loaded first. This rule also applies if a mix of load-time linked and run-time linked DLLs are used.

One obvious question all of this gives rise to is: which DLL will load first and how will you know? That is a difficult question to answer. Because DLL dependencies can be circular, there is no guaranteed way to determine DLL load order. It is entirely up to the DLL loader and any seemingly innocuous change can alter the order that DLLs are loaded. But in general, DLLs that are dependencies of many other DLLs will probably be loaded sooner rather than later. If you just want to know which DLL is loaded first with your project, run it under the Visual C++ debugger. It will display a list of all the DLLs that are loaded and in which order. But be aware that changes to the project might unexpectedly change the DLL load order.

Runtime Dynamic Linking

You know you're using this type of dynamic linking if your program calls LoadLibrary to load your DLL. With this type of dynamic linking, the DLL is not initialized until LoadLibrary is called. Therefore, if all of your DLLs are runtime linked, then the main executable is the first module to be initialized and VLD should be linked with the main executable. Include vld.h in the main source file for the main executable.

Using DLLs and the Static C Runtime Libraries

This refers to using DLLs in conjunction with the /ML or /MT compiler options. If you do this, then there are some things you should be aware of. This creates more than one copy of the CRT in the same process. There are many things that you cannot do across CRT boundaries. For example, you can't allocate memory in one CRT instance and free it in another. This isolation of CRT instances has important ramifications for VLD. VLD can normally only monitor memory allocations from a single CRT instance. If there are two CRTs in the same process then a single instance of VLD can only detect memory leaks in one of the CRT instances (even though both exist in the same process). If you want to be able to detect memory leaks in two instances of the CRT, then you'll need two instances of VLD -- one for each CRT instance. To do this, link VLD with both the main executable (where one of the CRT instances resides) and one of the DLLs (usually all DLLs will share one instance of the CRT). The same rules from above apply when deciding which DLL to link with. The downside to this is that each instance of VLD will generate its own memory leak report.

Building Visual Leak Detector from Source

Because Visual Leak Detector is open source, the libraries can be built from source if you want to tweak them to your liking. The hardest part about building the VLD libraries from source is getting your build environment correctly set up. But if you follow these instructions carefully, the process should be fairly painless.

  1. VLD depends on the Debug Help library header file, dbghelp.h. This header file won't exist unless you have a recent Platform SDK installed. If you don't see dbghelp.h in your Platform SDK's "include" directory, then you probably need to update your Platform SDK.
  2. Visual C++ will need to be made aware of where it can find the Debug Help library header file. If you have not done so already, add the "include" subdirectory from the Platform SDK installation directory to the include search path in Visual C++:
    • Visual C++ 7: Go to Project Properties -> C/C++ -> General -> Additional Include Directories and add the "include" subdirectory from the Platform SDK. Make sure it's at the top of the list.
    • Visual C++ 6: Go to Tools -> Options -> Directories. Select "Include files" from the "Show Directories For" drop-down menu. Add the "include" subdirectory from the Platform SDK. Make sure it's at the top of the list.
  3. VLD also depends on two other header files (dbgint.h and mtdll.h) that will only be installed if you elected to install the CRT source files when you installed Visual C++. If you didn't install the CRT sources, you'll need to re-run the Visual C++ installer and install them. If you are not sure whether you installed the CRT sources when you installed Visual C++, check to see if dbgint.h and mtdll.h exist in the "CRT\src" subdirectory of your Visual C++ installation directory. If those files are missing, or you don't have a "CRT\src" directory, then chances are you need to re-install Visual C++ with the CRT sources selected.
  4. Make sure that your Visual C++ installation's "CRT\src" subdirectory is in the include search path. Refer to step 2 for instructions on how to add directories to the include search path. The "CRT\src" subdirectory should go after the default include directory. To summarize, your include search path should look like this:
    • C:\Program Files\Microsoft Platform SDK\Include
    • C:\Program Files\Microsoft Visual Studio\VCx\Include
    • C:\Program Files\Microsoft Visual Studio\CRT\src

    In the above example, "VCx" would be "VC7" for Visual Studio .NET or "VC98" for Visual Studio 6.0. Also, the name of your Platform SDK directory might be different from the example depending on which version of the Platform SDK you have installed.

Once you've completed all of the above steps, your build environment should be ready. To build VLD, just open the vld.dsp project and do a batch build to build all six of the configurations:

Note: The "release" builds of the VLD libraries are not like typical release builds. Despite the "release" name, they are actually meant to be linked only to debug builds of your own programs. When doing release builds of your programs, VLD will not be linked to them at all. In the context of VLD, "release" simply means the versions that are optimized and have the symbols stripped from them (to make the libraries smaller). They are the versions of the libraries that are included in the release of VLD itself (hence the "release" name). So when you are building the release libraries, you're really building the same libraries that are included in the main VLD distribution. The "debug" builds of VLD are strictly for debugging VLD itself (e.g. if you want to modify it or if you need to fix a bug in it).

Windows x64 Support

The VLD source code has been modified to add support for x64-based 64-bit Windows. However, the binaries contained in the distributed versions of VLD are 32-bit only. To take advantage of the 64-bit support, you'll need to build 64-bit versions of the libraries from source. To build the 64-bit versions, follow the instructions for building VLD from source. So long as they are built using a x64-compatible compiler in 64-bit mode, the resulting libraries will be 64-bit libraries.

Note: I have not personally tested the 64-bit extensions so they are not absolutely guaranteed to work out-of-the-box. There may be a few lingering 64-bit compiler errors that still need to be worked out. If you need 64-bit support and run into problems trying to build the source in 64-bit mode, please let me know. I'll be glad to assist in getting the 64-bit code working properly.

Frequently Asked Questions

When running my program with VLD linked to it I get an error message saying, "the procedure entry point SymFromAddr could not be located in the dynamic link library dbghelp.dll".

This typically only happens on Windows 2000. It will happen if the Debug Help Library is out-of-date. Copy the included version of dbghelp.dll (version 6.3) to the directory where the executable you are debugging resides. If dbghelp.dll is missing for some reason, you can get it by installing Debugging Tools for Windows. I recommend installing version 6.3.

When building VLD from source, I get the fatal error "C1189: #error : ERROR: Use of C runtime library internal header file." in either the file stdio.h or in the file assert.h (or possibly in some other standard header file).

Visual C++ is including the wrong copies of the standard headers. Be sure that the "CRT\src" subdirectory of your Visual C++ installation directory is listed after the "include" subdirectory in Visual C++'s include search path.

When building VLD from source, I get Compile Error C1083: "Cannot open include file: 'dbgint.h': No such file or directory"

This will happen if the CRT source files are not installed. These are an optional part of the installation when you first install Visual C++. Re-run the Visual C++ installation, if needed, to install them. If the CRT sources are already installed, make sure the "CRT\src" subdirectory of the Visual C++ installation directory is in Visual C++'s include search path.

Is Visual Leak Detector compatible with platforms other than Microsoft Windows?

No. It is designed specifically for use with Visual C++, and it depends on heap debugging functions found only in Microsoft's C runtime library. It's called Visual Leak Detector for a reason.

Known Restrictions

Known restrictions in the current version of VLD, as of the time of this writing, include:

License

Visual Leak Detector is distributed under the terms of the GNU Lesser General Public License. See the COPYING.txt file for details.

The Debug Help Library (dbghelp.dll) distributed with this software is not part of Visual Leak Detector and is not covered under the terms of the GNU Lesser General Public License. It is a separately copyrighted work of Microsoft Corporation. Microsoft reserves all its rights to its copyright in the Debug Help Library. Neither your use of the Visual Leak Detector software, nor your license under the GNU Lesser General Public license grant you any rights to use the Debug Help Library in ANY WAY (for example, redistributing it) that would infringe upon Microsoft Corporation's copyright in the Debug Help Library.

NO WARRANTY

BECAUSE VISUAL LEAK DETECTOR ("THE SOFTWARE") IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE LICENSING TERMS SET FORTH ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

Contacting the Author

Please forward any bug reports, questions, comments or suggestions to me at dmoulding@gmail.com.

Donations to help support ongoing development of Visual Leak Detector are very appreciated!

Valid XHTML 1.0! Valid CSS!