-
Notifications
You must be signed in to change notification settings - Fork 401
/
codeproject-article.html
334 lines (300 loc) · 32.4 KB
/
codeproject-article.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
<!-- HTML for article "Visual Leak Detector - Enhanced Memory Leak Detection for Visual C++" by Dan Moulding,Dan Moulding
URL: http://www.codeproject.com/tools/visualleakdetector.asp
Article content copyright Dan Moulding,Dan Moulding
All formatting, additions and alterations Copyright © CodeProject, 1999-2006
-->
<!----------------------------- Ignore ----------------------------->
<link rel="stylesheet" type=text/css href="http://www.codeproject.com/styles/global.css">
<p><b>Please choose 'View Source' in your browser to view the HTML, or
File | Save to save this file to your hard drive for editing.</b></p>
<hr size=1 noshade>
<!----------------------------- Ignore ----------------------------->
<!----------------------------- Article Starts ----------------------------->
<UL class=download>
<LI><A href="http://www.codeproject.com/tools/visualleakdetector/vld-10.zip">Download Visual Leak Detector 1.0 - 535 Kb</A>
<LI><A href="http://www.codeproject.com/tools/visualleakdetector/vld-19d-setup.zip">Download the 1.9d beta version of Visual Leak Detector (includes source) - 729 Kb</A>
<LI><A href="http://www.codeproject.com/tools/visualleakdetector/vld-10-src.zip">Download the source code (version 1.0) - 50.3 Kb</A> </LI></UL>
<P><IMG height=436 alt="Screenshot of Visual Studio 6.0 with Visual Leak Detector's memory leak report displayed." src="http://www.codeproject.com/tools/visualleakdetector/screenshot.png" width=600></P>
<H2>Table of Contents</H2>
<UL>
<LI><A href="#intro">Introduction</A>
<LI><B><A href="#new">What's New?</A></B>
<LI><A href="#use">Using Visual Leak Detector</A>
<LI><A href="#make">Making a Memory Leak Detector</A>
<LI><A href="#source">Key Parts of the Source Code</A>
<LI><A href="#bandr">Known Bugs and Restrictions</A>
<LI><A href="#credits">Credits</A>
<LI><A href="#references">References</A>
<LI><A href="#license">License</A>
<LI><A href="#history">History</A> </LI></UL>
<H2><A name=intro></A>Introduction</H2>
<P>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:</P>
<UL>
<LI>Provides a complete stack trace for each leaked block, including source file and line number information when available.
<LI>Provides complete data dumps (in hex and ASCII) of leaked blocks.
<LI>Customizable level of detail in the memory leak report. </LI></UL>
<P>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 are some key advantages that Visual Leak Detector has over many other free alternatives:</P>
<UL>
<LI>Visual Leak Detector is cleanly packaged as an easy-to-use library. You don't need to compile its source code to use it. And you only need to make minor additions to your own source code to integrate it with your program.
<LI>In addition to providing stack traces with source files, line numbers, and function names, Visual Leak Detector also provides data dumps.
<LI>It works with both C++ and C programs (compatible with both <CODE>new</CODE>/<CODE>delete</CODE> and <CODE>malloc</CODE>/<CODE>free</CODE>).
<LI>The full source code to the library is included and it is well documented, so it is easy to customize it to suit your needs. </LI></UL>
<P>Visual Leak Detector is <A href="#license">licensed</A> free of charge as a service to the Windows developer community.</P>
<H2><A name=new></A>What's New?</H2>
<P><B>14 November 2006:</B> A new beta version of has been posted. This version fixes a few bugs, most notably a deadlock bug and a couple of failed assertion bugs, that were identified in the 1.9c beta.</P>
<P>Note that the beta version does not have the same limitations of the 1.0 version. Whereas 1.0 can only detect leaks resulting from <CODE>new</CODE> or <CODE>malloc</CODE>, the beta can detect many different classes of leaks.</P>
<P>Please also note that the article below describes the inner workings of the 1.0 version. Because the beta version might change significantly before the next official release, the article will not be updated to reflect the design of the beta version until the official release is complete.</P>
<H2><A name=use></A>Using Visual Leak Detector</H2>
<P>This section briefly describes the basics of using Visual Leak Detector (VLD). For a more in-depth discussion of the configuration options, runtime APIs, and a discussion of the more advanced usage scenarios (such as using VLD with DLLs), please see the full documentation included in the downloadable Zip files.</P>
<P>To use VLD with your project, follow these simple steps:</P>
<OL>
<LI>Copy the VLD library (<I>*.lib</I>) files to your Visual C++ installation's "<I>lib</I>" subdirectory.
<LI>Copy the VLD header files (<I>vld.h</I> and <I>vldapi.h</I>) to your Visual C++ installation's "<I>include</I>" subdirectory.
<LI>In the source file containing your program's main entry point, include the <I>vld.h</I> header file. It's best, but not absolutely required, to include this header before any other header files, except for <I>stdafx.h</I>. If the source file, include <I>stdafx.h</I>, then <I>vld.h</I> should be included after it.
<LI>If you are running Windows 2000 or earlier, then you will need to copy <I>dbghelp.dll</I> to the directory where the executable being debugged resides.
<LI>Build the debug version of your project. </LI></OL>
<P>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.</P>
<P><B>Note:</B> When you build release versions of your program, VLD will not be linked into the executable. So it is safe to leave <I>vld.h</I> included in your source files when doing release builds. Doing so will not result in any performance degradation or any other undesirable overhead.</P>
<H2><A name=make></A>Making a Memory Leak Detector</H2>
<P>The goal of Visual Leak Detector was to build a better replacement for the memory leak detector built-in to Visual C++. With that in mind, I set out to use the same method used by the built-in detector, namely the CRT Debug Heap. But this new detector would provide enhancements -- primarily full stack traces, which can be <I>extremely</I> helpful for finding and fixing leaks.</P>
<H3>The Built-In Detector</H3>
<P>The built-in detector is pretty simple really. When a program is exiting, the CRT runs a bunch of cleanup code after <CODE>main</CODE> returns. If the built-in detector is enabled, then it runs a memory leak check as part of the cleanup procedure. The memory leak check simply looks at the debug heap: if there are any user blocks still allocated on the debug heap, then they must be memory leaks. The debug version of <CODE>malloc</CODE> stores the file and line number that allocated each block in the block's header at the time it is allocated. When the built-in detector identifies a memory leak, it simply peers inside the block header to get the file and line number. It then reports that information to the debugger where it is displayed.</P>
<P>Note that the built-in detector detects leaks without doing any monitoring of allocations or frees. It simply takes a snapshot of the heap just before the process terminates and determines if there are any leaks based on that snapshot. A snapshot of the heap only tells us if there <I>are</I> leaks; it does not tell us <I>how</I> they were leaked. Clearly, to determine the "how" we also need to obtain a stack trace. But to obtain a stack trace, we need to be able to monitor every allocation on-the-fly at runtime. This is what will distinguish our leak detector from the built-in one.</P>
<H3>Allocation Hooking</H3>
<P>Luckily for us, Microsoft has provided an easy way to monitor every allocation made from the debug heap: allocation hooks. An allocation hook is simply a user-supplied callback function that will be called just before each allocation is made from the debug heap. Microsoft has provided a function, <CODE>_CrtSetAllocHook</CODE>, which registers the allocation hook function with the debug heap. When the debug heap calls the allocation hook, one of the arguments passed is an ID number that uniquely identifies each allocation -- it's basically a serial number for each memory block allocated. There's not enough room in the memory block header for us to record any information directly in it, but we can use this unique ID number as a key to map each block to any data that we want to record.</P>
<H3>Walking the Stack</H3>
<P>Now that we have a way to be notified every time a block is allocated, as well as a way to uniquely identify each allocation, all that's left to do is to record the call stack each time an allocation occurs. We could conceivably attempt to unwind the stack ourselves using inline assembly. But stack frames can be organized in different ways, depending on compiler optimizations and calling conventions, so it could become complicated to do it that way. Once again, Microsoft has provided us with a tool to help us out. This time it is a function that we can call iteratively to walk the stack, frame by frame. That function is <CODE>StackWalk64</CODE>. It is part of the Debug Help Library (<I>dbghelp.dll</I>). As long as we provide it with the information that it needs to establish a starting "frame of reference", so to speak, it can examine our stack from there and reliably unwind it for us. Each time <CODE>StackWalk64</CODE> is called, it gives back a <CODE>STACKFRAME64</CODE> structure that can be reused as input for the next call to <CODE>StackWalk64</CODE>. It can be repeatedly called this way until the end of the stack is reached.</P>
<H3>Initializing the Memory Leak Detector</H3>
<P>We now have the beginnings of a better memory leak detector. We can monitor every allocation, and for each allocation monitored, we can obtain and record a stack trace. The only challenge that remains is to ensure that the allocation hook function is registered with the debug heap as soon as the program starts executing. This can be very simply solved by creating a global instance of a C++ class object. The constructor will run when the program is initialized. From the constructor, we can call <CODE>_CrtSetAllocHook</CODE> to register our allocation hook function. But wait, what if the program we are debugging already has <I>other</I> global C++ class objects that allocate memory? How can we ensure that our constructor will be called first, and that our allocation hook function will be installed before any other global objects are constructed? Unfortunately, the C++ specification does not spell out any rules for deciding in which order to construct global objects. So there are no absolute guarantees that our constructor will be called first. But we can come very close to guaranteeing it. We can leverage a compiler-specific preprocessor directive that explicitly tells the compiler to ensure that our global variable is constructed as soon as possible: <CODE>#pragma init_seg (compiler)</CODE>. This directive tells the compiler to place our global object in the "compiler" initialization segment. Objects in this segment are the first to be constructed. Next, objects in the "library" segment are constructed, and objects in the "user" segment are constructed last. The "user" segment is the default segment for global objects. Generally speaking, no normal user objects should ever be placed in the "compiler" segment, so this provides a reasonable amount of certainty that our global object will be constructed before any user objects.</P>
<H3>Detecting Memory Leaks</H3>
<P>Because global objects are destroyed in the inverse order they are constructed, our global object will be destroyed after any user objects. We can then examine the heap, just like the built-in detector does. If we find a block on the heap that has not been freed, it is a leak and we can look up its call stack using the unique ID number recorded by our allocation hook function. An STL map would work fine here for mapping the ID number to the call stacks. I didn't use an STL map because I wanted my library to be compatible with both new and old versions of Visual C++. The STL from older versions is incompatible with the newer versions, so I couldn't use STL components. But the good news is that this gave me the opportunity to create a data structure similar in concept to the STL map, but with specific optimizations for use with my memory leak detector.</P>
<P>Do you remember that the built-in leak detector peers inside the memory block to get the name of the file and the line number where the block was allocated? Well, all we have for our call stack is a bunch of program addresses. Dumping all those hex numbers to the debugger wouldn't be of much use. To make those addresses more meaningful, we need to translate them to human readable information: files and line numbers (and function names too). Once again, Microsoft comes through with the tools that will help us do our job: the symbol handler APIs. Like <CODE>StackWalk64</CODE>, they also happen to be part of the Debug Help Library. I won't dwell on them in detail here, because there are a lot of them and they're pretty simple to use. They don't require as much ingenuity to use as <CODE>StackWalk64</CODE> does. We can use two of the symbol handler APIs to get the filenames, line numbers, and function names that we want. The aptly named <CODE>SymGetLineFromAddr64</CODE> translates addresses into source filenames and line numbers. Its sister API, <CODE>SymFromAddr</CODE> translates addresses into symbol names. For program addresses, which are what we have, the corresponding symbol name will be the name of the function containing that program address.</P>
<H2><A name=source></A>Key Parts of the Source Code</H2>
<P>In case you got bored with the above section and skipped ahead, I'll summarize it here. In a nutshell, this memory leak detector works like this:</P>
<OL>
<LI>A global object is automatically constructed. It is the first object constructed. The constructor registers our allocation hook function.
<LI>Every allocation eventually calls our allocation hook function. The allocation hook function obtains and records the call stack for each allocation. The call stack information is recorded in a specialized STL-like map.
<LI>When the program terminates, the global object is the last object destroyed. It examines the heap and identifies leaks. Leaked blocks are looked up in the map and matched with their corresponding call stack. The resulting data is sent to the debugger to be displayed. </LI></OL>
<H3>Step 1: Registering the Allocation Hook</H3>
<P>Here is the <CODE>VisualLeakDetector</CODE> class constructor. Note the call to <CODE>_CrtSetAllocHook</CODE>. This is where our callback function, <CODE>allochook</CODE>, is registered with the debug heap. The call to <CODE>linkdebughelplibrary</CODE> performs an explicit dynamic link with the Debug Help Library (<I>dbghelp.dll</I>). Because VLD is itself a library, implicitly linking with the Debug Help Library through the import library <I>dbghelp.lib</I> is undesirable; it would make the VLD library dependent on <I>dbghelp.lib</I> at link-time. <I>dbghelp.lib</I> will not be present on many Windows computers and it's not redistributable, so we need to link with the DLL at runtime in order to bypass the import library. There is a lot of other stuff going on in here as well, but most of it has to do with custom configuration options that VLD supports.</P><PRE>// Constructor - Dynamically links with the Debug Help Library and installs the
// allocation hook function so that the C runtime's debug heap manager will
// call the hook function for every heap request.
//
VisualLeakDetector::VisualLeakDetector ()
{
// Initialize private data.
m_mallocmap = new BlockMap;
m_process = GetCurrentProcess();
m_selftestfile = __FILE__;
m_status = 0x0;
m_thread = GetCurrentThread();
m_tlsindex = TlsAlloc();
if (_VLD_configflags & VLD_CONFIG_SELF_TEST) {
// Self-test mode has been enabled.
// Intentionally leak a small amount of
// memory so that memory leak self-checking can be verified.
strncpy(new char [21], "Memory Leak Self-Test", 21);
m_selftestline = __LINE__;
}
if (m_tlsindex == TLS_OUT_OF_INDEXES) {
report("ERROR: Visual Leak Detector:"
" Couldn't allocate thread local storage.\n");
}
else if (linkdebughelplibrary()) {
// Register our allocation hook function with the debug heap.
m_poldhook = _CrtSetAllocHook(allochook);
report("Visual Leak Detector "
"Version "VLD_VERSION" installed ("VLD_LIBTYPE").\n");
reportconfig();
if (_VLD_configflags & VLD_CONFIG_START_DISABLED) {
// Memory leak detection will initially be disabled.
m_status |= VLD_STATUS_NEVER_ENABLED;
}
m_status |= VLD_STATUS_INSTALLED;
return;
}
report("Visual Leak Detector is NOT installed!\n");
}</PRE>
<H3>Step 2: Walking the Stack</H3>
<P>Here is the function responsible for obtaining call stacks. This is perhaps the trickiest part of the entire program. Setting up for the first call to <CODE>StackWalk64</CODE> is where the tricky bit is. To start the stack trace, <CODE>StackWalk64</CODE> needs to know exactly where on the stack to begin walking. It never assumes that we want to start tracing from the current stack frame. This requires that we provide it with the address of the current frame, as well as the current program address. I've seen other examples that attempt to get this information by calling <CODE>GetThreadContext</CODE> to retrieve the current thread's context, which would contain both of the required addresses. But, as its documentation clearly states, <CODE>GetThreadContext</CODE> can't be relied upon to get valid information for a running thread. By definition, this means that <CODE>GetThreadContext</CODE> can't get a valid context for the current thread. A better approach is to get the required addresses directly, and the only way to do that is with inline assembly.</P>
<P>Obtaining the address of the current frame is easy: it's stored in a CPU register (<CODE lang=asm>EBP</CODE>) that we can directly read it from. The program address is a little harder to obtain. Though there is a CPU register (<CODE lang=asm>EIP</CODE>) that always contains the current program address, on Intel x86 CPUs, it can't be read by software. But we can get the same address in a round-about way, by calling another function and from within that function obtaining the return address. The return address is the same as the program address that called the function. For this, I've created a separate function, <CODE>getprogramcounterx86x64</CODE>. Since we're already doing inline assembly, we could write a simple function call in assembly, instead of writing another C++ function, but to keep it easier to understand, I've used C++ wherever it's possible to do so.</P>
<P>In the following code, <CODE>pStackWalk64</CODE>, <CODE>pSymFunctionTableAccess64</CODE> and <CODE>pSymGetModuleBase64</CODE> are all pointers to the functions exported by <I>dbghelp.dll</I>.</P><PRE>// getstacktrace - Traces the stack, starting from this function, as far
// back as possible.
//
// - callstack (OUT): Pointer to an empty CallStack to be populated with
// entries from the stack trace.
//
// Return Value:
//
// None.
//
void VisualLeakDetector::getstacktrace (CallStack *callstack)
{
DWORD architecture;
CONTEXT context;
unsigned int count = 0;
STACKFRAME64 frame;
DWORD_PTR framepointer;
DWORD_PTR programcounter;
// Get the required values for initialization of the STACKFRAME64 structure
// to be passed to StackWalk64(). Required fields are AddrPC and AddrFrame.
#if defined(_M_IX86) || defined(_M_X64)
architecture = X86X64ARCHITECTURE;
programcounter = getprogramcounterx86x64();
__asm mov [framepointer], BPREG // Get the frame pointer (aka base pointer)
#else
// If you want to retarget Visual Leak Detector to another processor
// architecture then you'll need to provide architecture-specific code to
// retrieve the current frame pointer and program counter in order to initialize
// the STACKFRAME64 structure below.
#error "Visual Leak Detector is not supported on this architecture."
#endif // defined(_M_IX86) || defined(_M_X64)
// Initialize the STACKFRAME64 structure.
memset(&frame, 0x0, sizeof(frame));
frame.AddrPC.Offset = programcounter;
frame.AddrPC.Mode = AddrModeFlat;
frame.AddrFrame.Offset = framepointer;
frame.AddrFrame.Mode = AddrModeFlat;
// Walk the stack.
while (count < _VLD_maxtraceframes) {
count++;
if (!pStackWalk64(architecture, m_process, m_thread,
&frame, &context, NULL, pSymFunctionTableAccess64,
pSymGetModuleBase64, NULL)) {
// Couldn't trace back through any more frames.
break;
}
if (frame.AddrFrame.Offset == 0) {
// End of stack.
break;
}
// Push this frame's program counter onto the provided CallStack.
callstack->push_back((DWORD_PTR)frame.AddrPC.Offset);
}
}</PRE>
<P>And here is the function that retrieves the <CODE lang=asm>EIP</CODE> register. Again, this has to be done as a separate function call because there is no way for the software to directly read the <CODE lang=asm>EIP</CODE> register. But the same value can be obtained by making a function call, and then from within the called function getting the return address. The return address is the program address that made the function call, and it is pushed onto the stack when the function call is made. We get it by copying it from the stack.</P><PRE>// getprogramcounterx86x64 - Helper function that retrieves the program counter
// for getstacktrace() on Intel x86 or x64 architectures.
//
// Note: Inlining of this function must be disabled. The whole purpose of this
// function's existence depends upon it being a *called* function.
//
// Return Value:
//
// Returns the caller's program address.
//
#if defined(_M_IX86) || defined(_M_X64)
#pragma auto_inline(off)
DWORD_PTR VisualLeakDetector::getprogramcounterx86x64 ()
{
DWORD_PTR programcounter;
// Get the return address out of the current stack frame
__asm mov AXREG, [BPREG + SIZEOFPTR]
// Put the return address into the variable we'll return
__asm mov [programcounter], AXREG
return programcounter;
}
#pragma auto_inline(on)
#endif // defined(_M_IX86) || defined(_M_X64)</PRE>
<H3>Step 3: Generating a Better Memory Leak Report</H3>
<P>Finally, here is the function that converts the program addresses obtained while walking the stack into useful symbol names. Note that the address-to-symbol conversion code is only run if memory leaks are detected. This avoids having to do symbol lookups on-the-fly while the program is running, which would add considerable additional overhead. Not to mention that it just doesn't make sense to store (large) symbol names for later retrieval when you can store (small) addresses instead.</P>
<P>The CRT doesn't expose any documented method for gaining access to its internal linked-list of allocated memory blocks. This linked list is what is used by the built-in detector for taking a "snapshot" of the heap to determine if there are any memory leaks. I've come up with a very simple trick to gain access to the list. Any time a new memory block is allocated, it happens to be placed at the beginning of the linked-list. So, to get a pointer to the head of the list, I just allocate a temporary memory block. That block's address can be converted to the address of the containing <CODE>_CrtMemBlockHeader</CODE> structure and now I have a pointer to the beginning of the linked list.</P>
<P>In the following code, <CODE>pSymSetOptions</CODE>, <CODE>pSymInitialize</CODE>, <CODE>pSymGetLineFromAddr64</CODE>, and <CODE>pSymFromAddr</CODE> are all pointers to the functions exported by <I>dbghelp.dll</I>. The <CODE>report</CODE> function is just a custom wrapper around <CODE>OutputDebugString</CODE> which sends messages to the debugger for display in the debugger's output window.</P>
<P>This function is quite long. To cut down on clutter, I've removed all of the uninteresting and trivial parts. To see this function in its entirety, please download the source ZIP file.</P><PRE>// reportleaks - Generates a memory leak report when the program terminates if
// leaks were detected. The report is displayed in the debug output window.
//
// Return Value:
//
// None.
//
void VisualLeakDetector::reportleaks ()
{
...
// Initialize the symbol handler. We use it for obtaining source file/line
// number information and function names for the memory leak report.
symbolpath = buildsymbolsearchpath();
pSymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME);
if (!pSymInitialize(m_process, symbolpath, TRUE)) {
report("WARNING: Visual Leak Detector: The symbol handler"
" failed to initialize (error=%lu).\n"
" Stack traces will probably not be available"
" for leaked blocks.\n", GetLastError());
}
...
#ifdef _MT
_mlock(_HEAP_LOCK);
#endif // _MT
pheap = new char;
pheader = pHdr(pheap)->pBlockHeaderNext;
delete pheap;
while (pheader) {
...
callstack = m_mallocmap->find(pheader->lRequest);
if (callstack) {
...
// Iterate through each frame in the call stack.
for (frame = 0; frame < callstack->size(); frame++) {
// Try to get the source file and line number associated with
// this program counter address.
if (pSymGetLineFromAddr64(m_process,
(*callstack)[frame], &displacement, &sourceinfo)) {
...
}
// Try to get the name of the function containing this program
// counter address.
if (pSymFromAddr(m_process, (*callstack)[frame],
&displacement64, pfunctioninfo)) {
functionname = pfunctioninfo->Name;
}
else {
functionname = "(Function name unavailable)";
}
...
}
...
}
pheader = pheader->pBlockHeaderNext;
}
#ifdef _MT
_munlock(_HEAP_LOCK);
#endif // _MT
...
}</PRE>
<H2><A name=bandr></A>Known Bugs and Restrictions</H2>
<P>There are currently no known bugs in the latest release, but there are some known restrictions:</P>
<UL>
<LI>VLD does not detect COM leaks, out-of-process resource leaks, or any other types of memory leaks that are not associated with the CRT heap. In simpler terms, VLD only detects memory leaks that are the result of calls to <CODE>new</CODE> or <CODE>malloc</CODE>. Keep in mind that VLD was created as an alternative to the built-in memory leak detector, which also only detects leaks from <CODE>new</CODE> and <CODE>malloc</CODE>.
<LI>VLD is not compatible with version 6.5 of the Debug Help Library (<I>dbghelp.dll</I>). The recommended version of <I>dbghelp.dll</I> to use with VLD is 6.3. Version 6.3 is included in the VLD distribution.
<LI>The pre-compiled libraries included in the VLD distribution may not be compatible with Visual Studio 2005. If you need to use VLD with Visual Studio 2005, <A href="#build">building VLD from source</A> in Visual Studio 2005 should create compatible libraries. </LI></UL>
<H2><A name=credits></A>Credits</H2>
<UL>
<LI>Thanks to Alexandre Nikolov for quickly discovering the bug in 0.9e and helping to slap together a quick fix.
<LI>Credit for the idea of how to make VLD's global class <CODE>VisualLeakDetector</CODE> object get constructed before any other user global objects goes to cmk. Thanks cmk!
<LI>Thanks to Nitrogenycs (aka Matthias) for discovering the <CODE>VLD_MAX_DATA_DUMP</CODE> infinite loop bug.
<LI>Thanks to hsvcs (aka Holger) for discovering the <CODE>VLD_MAX_DATA_DUMP</CODE> compilation bug.
<LI>Thanks to Don Clugston for pointing out to me that people sometimes do build optimized debug executables, and that I need to watch out for that. </LI></UL>
<H2><A name=references></A>References</H2>
<P>Here are some links to useful related articles and resources:</P>
<UL>
<LI><A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt__crtsetallochook.asp" target=_blank><CODE>_CrtSetAllocHook</CODE></A> from the MSDN Library.
<LI><A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/stackwalk64.asp" target=_blank><CODE>StackWalk64</CODE></A> from the MSDN Library.
<LI><A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/symbol_handling.asp" target=_blank>Using the Symbol Handler</A>, from the MSDN Library.
<LI><A href="ftp://download.intel.com/design/Pentium4/manuals/25366514.pdf" target=_blank>IA-32 Intel Architecture Software Developer's Manual - Volume 1</A>. Section 3.5 explains the <CODE lang=asm>EIP</CODE> register and how software can and cannot interact with it. </LI></UL>
<H2><A name=license></A>License</H2>
<P>Visual Leak Detector is distributed under the terms of the <A href="http://www.gnu.org/copyleft/lesser.html" target=_blank>GNU Lesser General Public License</A>. See the documentation included in the downloadable ZIP files for detailed licensing information.</P>
<H2><A name=history></A>History</H2>
<P>This list gives a brief overview of the changes made from release to release. For a detailed description of changes made in each release, please see the change log, <I>CHANGES.txt</I>, in the downloadable ZIP files.</P>
<UL>
<LI><B>14 November 2006:</B> Version 1.9d beta - Fixed a deadlock bug that may occur in multithreaded programs. Also fixed a two failed assertion bugs.</LI>
<LI><B>6 November 2006:</B> Version 1.9c beta - New installer to make starting out with VLD easier. All known incompatibilities with Visual Studio 2005 have been fixed.
<LI><B>9 March 2006:</B> Version 1.9a beta - Entirely new leak detection engine detects most, if not all, in-process memory leaks not just leaks from <CODE>new</CODE> or <CODE>malloc</CODE>. Added many other new convenience features as well.
<LI><B>5 August 2005:</B> Version 1.0 - A couple of new features have been added, and a few bugs have been fixed. Major revisions have been made to this article to bring it up to date with respect to the 1.0 release.
<LI><B>2 May 2005:</B> Version 0.9i beta - This release fixed several bugs. It also includes support for Windows x64.
<LI><B>22 April 2005:</B> Version 0.9h beta - This release contains a crucial fix for an internal logic bug in version 0.9g.
<LI><B>22 April 2005:</B> Version 0.9g beta - This release contains a vastly improved internal search/sort algorithm that results in a significant overall performance boost.
<LI><B>13 April 2005:</B> Version 0.9f beta - This provides a quick fix for a bug in 0.9e that can cause crashes.
<LI><B>12 April 2005:</B> Version 0.9e beta - Solves compatibility problems between the pre-built libraries and Visual Studio .NET by removing the use of STL components (the pre-built libraries are built in Visual Studio 6.0 and the STL is not compatible between .NET and 6.0).
<LI><B>30 March 2005:</B> Version 0.9d beta - First release of VLD as a set of pre-built libraries.
<LI><B>17 March 2005:</B> Version 0.9c beta - Fixed a compilation error if <CODE>VLD_MAX_DATA_DUMP</CODE> is defined.
<LI><B>15 March 2005:</B> Version 0.9b beta - Improved ability to detect leaks in global C++ object constructors.
<LI><B>12 March 2005:</B> Version 0.9a beta - Initial public release. </LI></UL>
<!----------------------------- Article Ends ----------------------------->