1 ////////////////////////////////////////////////////////////////////////////////
3 // Visual Leak Detector - VisualLeakDetector Class Implementation
4 // Copyright (c) 2005-2009 Dan Moulding
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 // See COPYING.txt for the full terms of the GNU Lesser General Public License.
22 ////////////////////////////////////////////////////////////////////////////////
24 #pragma comment(lib, "dbghelp.lib")
32 #define __out_xcount(x) // Workaround for the specstrings.h bug in the Platform SDK.
34 #define DBGHELP_TRANSLATE_TCHAR
35 #include <dbghelp.h> // Provides symbol handling services.
36 #define VLDBUILD // Declares that we are building Visual Leak Detector.
37 #include "callstack.h" // Provides a class for handling call stacks.
38 #include "crtmfcpatch.h" // Provides CRT and MFC patch functions.
39 #include "map.h" // Provides a lightweight STL-like map template.
40 #include "ntapi.h" // Provides access to NT APIs.
41 #include "set.h" // Provides a lightweight STL-like set template.
42 #include "utility.h" // Provides various utility functions.
43 #include "vldheap.h" // Provides internal new and delete operators.
44 #include "vldint.h" // Provides access to the Visual Leak Detector internals.
46 #define BLOCKMAPRESERVE 64 // This should strike a balance between memory use and a desire to minimize heap hits.
47 #define HEAPMAPRESERVE 2 // Usually there won't be more than a few heaps in the process, so this should be small.
48 #define MAXSYMBOLNAMELENGTH 256 // Maximum symbol name length that we will allow. Longer names will be truncated.
49 #define MODULESETRESERVE 16 // There are likely to be several modules loaded in the process.
51 // Imported global variables.
52 extern vldblockheader_t *vldblocklist;
53 extern HANDLE vldheap;
54 extern CRITICAL_SECTION vldheaplock;
57 HANDLE currentprocess; // Pseudo-handle for the current process.
58 HANDLE currentthread; // Pseudo-handle for the current thread.
59 CRITICAL_SECTION imagelock; // Serializes calls to the Debug Help Library PE image access APIs.
60 HANDLE processheap; // Handle to the process's heap (COM allocations come from here).
61 CRITICAL_SECTION stackwalklock; // Serializes calls to StackWalk64 from the Debug Help Library.
62 CRITICAL_SECTION symbollock; // Serializes calls to the Debug Help Library symbols handling APIs.
64 // The one and only VisualLeakDetector object instance.
65 __declspec(dllexport) VisualLeakDetector vld;
67 // Global function pointers for explicit dynamic linking with functions listed
68 // in the import patch table. Using explicit dynamic linking minimizes VLD's
69 // footprint by loading only modules that are actually used. These pointers will
70 // be linked to the real functions the first time they are used.
72 // The import patch table: lists the heap-related API imports that VLD patches
73 // through to replacement functions provided by VLD. Having this table simply
74 // makes it more convenient to add additional IAT patches.
75 patchentry_t VisualLeakDetector::m_patchtable [] = {
77 "kernel32.dll", "GetProcAddress", 0x0, _GetProcAddress, // Not heap related, but can be used to obtain pointers to heap functions.
78 "kernel32.dll", "HeapAlloc", 0x0, _RtlAllocateHeap,
79 "kernel32.dll", "HeapCreate", 0x0, _HeapCreate,
80 "kernel32.dll", "HeapDestroy", 0x0, _HeapDestroy,
81 "kernel32.dll", "HeapFree", 0x0, _RtlFreeHeap,
82 "kernel32.dll", "HeapReAlloc", 0x0, _RtlReAllocateHeap,
84 // MFC new operators (exported by ordinal).
85 // XXX why are the vector new operators missing for mfc42d.dll?
86 "mfc42d.dll", (LPCSTR)711, 0x0, VS60::mfcd_scalar_new,
87 "mfc42d.dll", (LPCSTR)712, 0x0, VS60::mfcd__scalar_new_dbg_4p,
88 "mfc42d.dll", (LPCSTR)714, 0x0, VS60::mfcd__scalar_new_dbg_3p,
89 "mfc42ud.dll", (LPCSTR)711, 0x0, VS60::mfcud_scalar_new,
90 "mfc42ud.dll", (LPCSTR)712, 0x0, VS60::mfcud__scalar_new_dbg_4p,
91 "mfc42ud.dll", (LPCSTR)714, 0x0, VS60::mfcud__scalar_new_dbg_3p,
92 "mfc70d.dll", (LPCSTR)257, 0x0, VS70::mfcd_vector_new,
93 "mfc70d.dll", (LPCSTR)258, 0x0, VS70::mfcd__vector_new_dbg_4p,
94 "mfc70d.dll", (LPCSTR)259, 0x0, VS70::mfcd__vector_new_dbg_3p,
95 "mfc70d.dll", (LPCSTR)832, 0x0, VS70::mfcd_scalar_new,
96 "mfc70d.dll", (LPCSTR)833, 0x0, VS70::mfcd__scalar_new_dbg_4p,
97 "mfc70d.dll", (LPCSTR)834, 0x0, VS70::mfcd__scalar_new_dbg_3p,
98 "mfc70ud.dll", (LPCSTR)258, 0x0, VS70::mfcud_vector_new,
99 "mfc70ud.dll", (LPCSTR)259, 0x0, VS70::mfcud__vector_new_dbg_4p,
100 "mfc70ud.dll", (LPCSTR)260, 0x0, VS70::mfcud__vector_new_dbg_3p,
101 "mfc70ud.dll", (LPCSTR)833, 0x0, VS70::mfcud_scalar_new,
102 "mfc70ud.dll", (LPCSTR)834, 0x0, VS70::mfcud__scalar_new_dbg_4p,
103 "mfc70ud.dll", (LPCSTR)835, 0x0, VS70::mfcud__scalar_new_dbg_3p,
104 "mfc71d.dll", (LPCSTR)267, 0x0, VS71::mfcd_vector_new,
105 "mfc71d.dll", (LPCSTR)268, 0x0, VS71::mfcd__vector_new_dbg_4p,
106 "mfc71d.dll", (LPCSTR)269, 0x0, VS71::mfcd__vector_new_dbg_3p,
107 "mfc71d.dll", (LPCSTR)893, 0x0, VS71::mfcd_scalar_new,
108 "mfc71d.dll", (LPCSTR)894, 0x0, VS71::mfcd__scalar_new_dbg_4p,
109 "mfc71d.dll", (LPCSTR)895, 0x0, VS71::mfcd__scalar_new_dbg_3p,
110 "mfc71ud.dll", (LPCSTR)267, 0x0, VS71::mfcud_vector_new,
111 "mfc71ud.dll", (LPCSTR)268, 0x0, VS71::mfcud__vector_new_dbg_4p,
112 "mfc71ud.dll", (LPCSTR)269, 0x0, VS71::mfcud__vector_new_dbg_3p,
113 "mfc71ud.dll", (LPCSTR)893, 0x0, VS71::mfcud_scalar_new,
114 "mfc71ud.dll", (LPCSTR)894, 0x0, VS71::mfcud__scalar_new_dbg_4p,
115 "mfc71ud.dll", (LPCSTR)895, 0x0, VS71::mfcud__scalar_new_dbg_3p,
116 "mfc80d.dll", (LPCSTR)267, 0x0, VS80::mfcd_vector_new,
117 "mfc80d.dll", (LPCSTR)268, 0x0, VS80::mfcd__vector_new_dbg_4p,
118 "mfc80d.dll", (LPCSTR)269, 0x0, VS80::mfcd__vector_new_dbg_3p,
119 "mfc80d.dll", (LPCSTR)893, 0x0, VS80::mfcd_scalar_new,
120 "mfc80d.dll", (LPCSTR)894, 0x0, VS80::mfcd__scalar_new_dbg_4p,
121 "mfc80d.dll", (LPCSTR)895, 0x0, VS80::mfcd__scalar_new_dbg_3p,
122 "mfc80ud.dll", (LPCSTR)267, 0x0, VS80::mfcud_vector_new,
123 "mfc80ud.dll", (LPCSTR)268, 0x0, VS80::mfcud__vector_new_dbg_4p,
124 "mfc80ud.dll", (LPCSTR)269, 0x0, VS80::mfcud__vector_new_dbg_3p,
125 "mfc80ud.dll", (LPCSTR)893, 0x0, VS80::mfcud_scalar_new,
126 "mfc80ud.dll", (LPCSTR)894, 0x0, VS80::mfcud__scalar_new_dbg_4p,
127 "mfc80ud.dll", (LPCSTR)895, 0x0, VS80::mfcud__scalar_new_dbg_3p,
128 "mfc90d.dll", (LPCSTR)267, 0x0, VS90::mfcd_vector_new,
129 "mfc90d.dll", (LPCSTR)268, 0x0, VS90::mfcd__vector_new_dbg_4p,
130 "mfc90d.dll", (LPCSTR)269, 0x0, VS90::mfcd__vector_new_dbg_3p,
131 "mfc90d.dll", (LPCSTR)931, 0x0, VS90::mfcd_scalar_new,
132 "mfc90d.dll", (LPCSTR)932, 0x0, VS90::mfcd__scalar_new_dbg_4p,
133 "mfc90d.dll", (LPCSTR)933, 0x0, VS90::mfcd__scalar_new_dbg_3p,
134 "mfc90ud.dll", (LPCSTR)267, 0x0, VS90::mfcud_vector_new,
135 "mfc90ud.dll", (LPCSTR)268, 0x0, VS90::mfcud__vector_new_dbg_4p,
136 "mfc90ud.dll", (LPCSTR)269, 0x0, VS90::mfcud__vector_new_dbg_3p,
137 "mfc90ud.dll", (LPCSTR)935, 0x0, VS90::mfcud_scalar_new,
138 "mfc90ud.dll", (LPCSTR)936, 0x0, VS90::mfcud__scalar_new_dbg_4p,
139 "mfc90ud.dll", (LPCSTR)937, 0x0, VS90::mfcud__scalar_new_dbg_3p,
140 "mfc100d.dll", (LPCSTR)267, 0x0, VS100::mfcd_vector_new,
141 "mfc100d.dll", (LPCSTR)268, 0x0, VS100::mfcd__vector_new_dbg_4p,
142 "mfc100d.dll", (LPCSTR)269, 0x0, VS100::mfcd__vector_new_dbg_3p,
143 "mfc100d.dll", (LPCSTR)1427, 0x0, VS100::mfcd_scalar_new,
144 "mfc100d.dll", (LPCSTR)1428, 0x0, VS100::mfcd__scalar_new_dbg_4p,
145 "mfc100d.dll", (LPCSTR)1429, 0x0, VS100::mfcd__scalar_new_dbg_3p,
146 "mfc100ud.dll", (LPCSTR)267, 0x0, VS100::mfcud_vector_new,
147 "mfc100ud.dll", (LPCSTR)268, 0x0, VS100::mfcud__vector_new_dbg_4p,
148 "mfc100ud.dll", (LPCSTR)269, 0x0, VS100::mfcud__vector_new_dbg_3p,
149 "mfc100ud.dll", (LPCSTR)1434, 0x0, VS100::mfcud_scalar_new,
150 "mfc100ud.dll", (LPCSTR)1435, 0x0, VS100::mfcud__scalar_new_dbg_4p,
151 "mfc100ud.dll", (LPCSTR)1436, 0x0, VS100::mfcud__scalar_new_dbg_3p,
153 // CRT new operators and heap APIs.
154 "msvcrtd.dll", "_calloc_dbg", 0x0, VS60::crtd__calloc_dbg,
155 "msvcrtd.dll", "_malloc_dbg", 0x0, VS60::crtd__malloc_dbg,
156 "msvcrtd.dll", "_realloc_dbg", 0x0, VS60::crtd__realloc_dbg,
157 "msvcrtd.dll", "??2@YAPAXIHPBDH@Z", 0x0, VS60::crtd__scalar_new_dbg,
158 // "msvcrtd.dll", "??_U@YAPAXIHPBDH@Z", 0x0, VS60::crtd__vector_new_dbg,
159 "msvcrtd.dll", "calloc", 0x0, VS60::crtd_calloc,
160 "msvcrtd.dll", "malloc", 0x0, VS60::crtd_malloc,
161 "msvcrtd.dll", "realloc", 0x0, VS60::crtd_realloc,
162 "msvcrtd.dll", "??2@YAPAXI@Z", 0x0, VS60::crtd_scalar_new,
163 // "msvcrtd.dll", "??_U@YAPAXI@Z", 0x0, VS60::crtd_vector_new,
164 "msvcr70d.dll", "_calloc_dbg", 0x0, VS70::crtd__calloc_dbg,
165 "msvcr70d.dll", "_malloc_dbg", 0x0, VS70::crtd__malloc_dbg,
166 "msvcr70d.dll", "_realloc_dbg", 0x0, VS70::crtd__realloc_dbg,
167 "msvcr70d.dll", "??2@YAPAXIHPBDH@Z", 0x0, VS70::crtd__scalar_new_dbg,
168 "msvcr70d.dll", "??_U@YAPAXIHPBDH@Z", 0x0, VS70::crtd__vector_new_dbg,
169 "msvcr70d.dll", "calloc", 0x0, VS70::crtd_calloc,
170 "msvcr70d.dll", "malloc", 0x0, VS70::crtd_malloc,
171 "msvcr70d.dll", "realloc", 0x0, VS70::crtd_realloc,
172 "msvcr70d.dll", "??2@YAPAXI@Z", 0x0, VS70::crtd_scalar_new,
173 "msvcr70d.dll", "??_U@YAPAXI@Z", 0x0, VS70::crtd_vector_new,
174 "msvcr71d.dll", "_calloc_dbg", 0x0, VS71::crtd__calloc_dbg,
175 "msvcr71d.dll", "_malloc_dbg", 0x0, VS71::crtd__malloc_dbg,
176 "msvcr71d.dll", "_realloc_dbg", 0x0, VS71::crtd__realloc_dbg,
177 "msvcr71d.dll", "??2@YAPAXIHPBDH@Z", 0x0, VS71::crtd__scalar_new_dbg,
178 "msvcr71d.dll", "??_U@YAPAXIHPBDH@Z", 0x0, VS71::crtd__vector_new_dbg,
179 "msvcr71d.dll", "calloc", 0x0, VS71::crtd_calloc,
180 "msvcr71d.dll", "malloc", 0x0, VS71::crtd_malloc,
181 "msvcr71d.dll", "realloc", 0x0, VS71::crtd_realloc,
182 "msvcr71d.dll", "??2@YAPAXI@Z", 0x0, VS71::crtd_scalar_new,
183 "msvcr71d.dll", "??_U@YAPAXI@Z", 0x0, VS71::crtd_vector_new,
184 "msvcr80d.dll", "_calloc_dbg", 0x0, VS80::crtd__calloc_dbg,
185 "msvcr80d.dll", "_malloc_dbg", 0x0, VS80::crtd__malloc_dbg,
186 "msvcr80d.dll", "_realloc_dbg", 0x0, VS80::crtd__realloc_dbg,
187 "msvcr80d.dll", "??2@YAPAXIHPBDH@Z", 0x0, VS80::crtd__scalar_new_dbg,
188 "msvcr80d.dll", "??_U@YAPAXIHPBDH@Z", 0x0, VS80::crtd__vector_new_dbg,
189 "msvcr80d.dll", "calloc", 0x0, VS80::crtd_calloc,
190 "msvcr80d.dll", "malloc", 0x0, VS80::crtd_malloc,
191 "msvcr80d.dll", "realloc", 0x0, VS80::crtd_realloc,
192 "msvcr80d.dll", "??2@YAPAXI@Z", 0x0, VS80::crtd_scalar_new,
193 "msvcr80d.dll", "??_U@YAPAXI@Z", 0x0, VS80::crtd_vector_new,
194 "msvcr90d.dll", "_calloc_dbg", 0x0, VS90::crtd__calloc_dbg,
195 "msvcr90d.dll", "_malloc_dbg", 0x0, VS90::crtd__malloc_dbg,
196 "msvcr90d.dll", "_realloc_dbg", 0x0, VS90::crtd__realloc_dbg,
197 "msvcr90d.dll", "??2@YAPAXIHPBDH@Z", 0x0, VS90::crtd__scalar_new_dbg,
198 "msvcr90d.dll", "??_U@YAPAXIHPBDH@Z", 0x0, VS90::crtd__vector_new_dbg,
199 "msvcr90d.dll", "calloc", 0x0, VS90::crtd_calloc,
200 "msvcr90d.dll", "malloc", 0x0, VS90::crtd_malloc,
201 "msvcr90d.dll", "realloc", 0x0, VS90::crtd_realloc,
202 "msvcr90d.dll", "??2@YAPAXI@Z", 0x0, VS90::crtd_scalar_new,
203 "msvcr90d.dll", "??_U@YAPAXI@Z", 0x0, VS90::crtd_vector_new,
204 "msvcr100d.dll", "_calloc_dbg", 0x0, VS100::crtd__calloc_dbg,
205 "msvcr100d.dll", "_malloc_dbg", 0x0, VS100::crtd__malloc_dbg,
206 "msvcr100d.dll", "_realloc_dbg", 0x0, VS100::crtd__realloc_dbg,
207 "msvcr100d.dll", scalar_new_dbg_name, 0x0, VS100::crtd__scalar_new_dbg,
208 "msvcr100d.dll", vector_new_dbg_name, 0x0, VS100::crtd__vector_new_dbg,
209 "msvcr100d.dll", "calloc", 0x0, VS100::crtd_calloc,
210 "msvcr100d.dll", "malloc", 0x0, VS100::crtd_malloc,
211 "msvcr100d.dll", "realloc", 0x0, VS100::crtd_realloc,
212 "msvcr100d.dll", scalar_new_name, 0x0, VS100::crtd_scalar_new,
213 "msvcr100d.dll", vector_new_name, 0x0, VS100::crtd_vector_new,
216 "ntdll.dll", "RtlAllocateHeap", 0x0, _RtlAllocateHeap,
217 "ntdll.dll", "RtlFreeHeap", 0x0, _RtlFreeHeap,
218 "ntdll.dll", "RtlReAllocateHeap", 0x0, _RtlReAllocateHeap,
221 "ole32.dll", "CoGetMalloc", 0x0, _CoGetMalloc,
222 "ole32.dll", "CoTaskMemAlloc", 0x0, _CoTaskMemAlloc,
223 "ole32.dll", "CoTaskMemRealloc", 0x0, _CoTaskMemRealloc
226 // Constructor - Initializes private data, loads configuration options, and
227 // attaches Visual Leak Detector to all other modules loaded into the current
230 VisualLeakDetector::VisualLeakDetector ()
232 WCHAR bom = BOM; // Unicode byte-order mark.
234 ModuleSet *newmodules;
238 // Initialize configuration options and related private data.
239 _wcsnset_s(m_forcedmodulelist, MAXMODULELISTLENGTH, '\0', _TRUNCATE);
240 m_maxdatadump = 0xffffffff;
241 m_maxtraceframes = 0xffffffff;
244 wcsncpy_s(m_reportfilepath, MAX_PATH, VLD_DEFAULT_REPORT_FILE_NAME, _TRUNCATE);
247 // Load configuration options.
249 if (m_options & VLD_OPT_VLDOFF) {
250 report(L"Visual Leak Detector is turned off.\n");
254 kernel32 = GetModuleHandle(L"kernel32.dll");
255 ntdll = GetModuleHandle(L"ntdll.dll");
257 // Initialize global variables.
258 currentprocess = GetCurrentProcess();
259 currentthread = GetCurrentThread();
260 InitializeCriticalSection(&imagelock);
261 LdrLoadDll = (LdrLoadDll_t)GetProcAddress(ntdll, "LdrLoadDll");
262 processheap = GetProcessHeap();
263 RtlAllocateHeap = (RtlAllocateHeap_t)GetProcAddress(ntdll, "RtlAllocateHeap");
264 RtlFreeHeap = (RtlFreeHeap_t)GetProcAddress(ntdll, "RtlFreeHeap");
265 RtlReAllocateHeap = (RtlReAllocateHeap_t)GetProcAddress(ntdll, "RtlReAllocateHeap");
266 InitializeCriticalSection(&stackwalklock);
267 InitializeCriticalSection(&symbollock);
268 vldheap = HeapCreate(0x0, 0, 0);
269 InitializeCriticalSection(&vldheaplock);
271 // Initialize remaining private data.
272 m_heapmap = new HeapMap;
273 m_heapmap->reserve(HEAPMAPRESERVE);
276 m_loadedmodules = NULL;
277 InitializeCriticalSection(&m_loaderlock);
278 InitializeCriticalSection(&m_maplock);
279 InitializeCriticalSection(&m_moduleslock);
280 m_selftestfile = __FILE__;
282 m_tlsindex = TlsAlloc();
283 InitializeCriticalSection(&m_tlslock);
284 m_tlsset = new TlsSet;
286 if (m_options & VLD_OPT_SELF_TEST) {
287 // Self-test mode has been enabled. Intentionally leak a small amount of
288 // memory so that memory leak self-checking can be verified.
289 if (m_options & VLD_OPT_UNICODE_REPORT) {
290 wcsncpy_s(new WCHAR [wcslen(SELFTESTTEXTW) + 1], wcslen(SELFTESTTEXTW) + 1, SELFTESTTEXTW, _TRUNCATE);
291 m_selftestline = __LINE__ - 1;
294 strncpy_s(new CHAR [strlen(SELFTESTTEXTA) + 1], strlen(SELFTESTTEXTA) + 1, SELFTESTTEXTA, _TRUNCATE);
295 m_selftestline = __LINE__ - 1;
298 if (m_options & VLD_OPT_START_DISABLED) {
299 // Memory leak detection will initially be disabled.
300 m_status |= VLD_STATUS_NEVER_ENABLED;
302 if (m_options & VLD_OPT_REPORT_TO_FILE) {
303 // Reporting to file enabled.
304 if (m_options & VLD_OPT_UNICODE_REPORT) {
305 // Unicode data encoding has been enabled. Write the byte-order
306 // mark before anything else gets written to the file. Open the
307 // file for binary writing.
308 if (_wfopen_s(&m_reportfile, m_reportfilepath, L"wb") == EINVAL) {
309 // Couldn't open the file.
313 fwrite(&bom, sizeof(WCHAR), 1, m_reportfile);
314 setreportencoding(unicode);
318 // Open the file in text mode for ASCII output.
319 if (_wfopen_s(&m_reportfile, m_reportfilepath, L"w") == EINVAL) {
320 // Couldn't open the file.
324 setreportencoding(ascii);
327 if (m_reportfile == NULL) {
328 report(L"WARNING: Visual Leak Detector: Couldn't open report file for writing: %s\n"
329 L" The report will be sent to the debugger instead.\n", m_reportfilepath);
332 // Set the "report" function to write to the file.
333 setreportfile(m_reportfile, m_options & VLD_OPT_REPORT_TO_DEBUGGER);
336 if (m_options & VLD_OPT_SLOW_DEBUGGER_DUMP) {
337 // Insert a slight delay between messages sent to the debugger for
338 // output. (For working around a bug in VC6 where data sent to the
339 // debugger gets lost if it's sent too fast).
343 // This is highly unlikely to happen, but just in case, check to be sure
344 // we got a valid TLS index.
345 if (m_tlsindex == TLS_OUT_OF_INDEXES) {
346 report(L"ERROR: Visual Leak Detector could not be installed because thread local"
347 L" storage could not be allocated.");
351 // Initialize the symbol handler. We use it for obtaining source file/line
352 // number information and function names for the memory leak report.
353 symbolpath = buildsymbolsearchpath();
354 SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME);
355 if (!SymInitializeW(currentprocess, symbolpath, FALSE)) {
356 report(L"WARNING: Visual Leak Detector: The symbol handler failed to initialize (error=%lu).\n"
357 L" File and function names will probably not be available in call stacks.\n", GetLastError());
359 delete [] symbolpath;
361 // Patch into kernel32.dll's calls to LdrLoadDll so that VLD can
362 // dynamically attach to new modules loaded during runtime.
363 patchimport(kernel32, ntdll, "ntdll.dll", "LdrLoadDll", _LdrLoadDll);
365 // Attach Visual Leak Detector to every module loaded in the process.
366 newmodules = new ModuleSet;
367 newmodules->reserve(MODULESETRESERVE);
368 EnumerateLoadedModulesW64(currentprocess, addloadedmodule, newmodules);
369 attachtoloadedmodules(newmodules);
370 m_loadedmodules = newmodules;
371 m_status |= VLD_STATUS_INSTALLED;
373 report(L"Visual Leak Detector Version " VLDVERSION L" installed.\n");
374 if (m_status & VLD_STATUS_FORCE_REPORT_TO_FILE) {
375 // The report is being forced to a file. Let the human know why.
376 report(L"NOTE: Visual Leak Detector: Unicode-encoded reporting has been enabled, but the\n"
377 L" debugger is the only selected report destination. The debugger cannot display\n"
378 L" Unicode characters, so the report will also be sent to a file. If no file has\n"
379 L" been specified, the default file name is \"" VLD_DEFAULT_REPORT_FILE_NAME L"\".\n");
385 // Destructor - Detaches Visual Leak Detector from all modules loaded in the
386 // process, frees internally allocated resources, and generates the memory
389 VisualLeakDetector::~VisualLeakDetector ()
391 BlockMap::Iterator blockit;
394 vldblockheader_t *header;
396 HeapMap::Iterator heapit;
397 SIZE_T internalleaks = 0;
398 const char *leakfile = NULL;
399 WCHAR leakfilew [MAX_PATH];
401 ModuleSet::Iterator moduleit;
403 BOOL threadsactive= FALSE;
404 TlsSet::Iterator tlsit;
405 DWORD dwCurProcessID;
407 if (m_options & VLD_OPT_VLDOFF) {
408 // VLD has been turned off.
412 if (m_status & VLD_STATUS_INSTALLED) {
413 // Detach Visual Leak Detector from all previously attached modules.
414 EnumerateLoadedModulesW64(currentprocess, detachfrommodule, NULL);
416 dwCurProcessID = GetCurrentProcessId();
418 // See if any threads that have ever entered VLD's code are still active.
419 EnterCriticalSection(&m_tlslock);
420 for (tlsit = m_tlsset->begin(); tlsit != m_tlsset->end(); ++tlsit) {
421 if ((*tlsit)->threadid == GetCurrentThreadId()) {
422 // Don't wait for the current thread to exit.
426 thread = OpenThread(SYNCHRONIZE | THREAD_QUERY_INFORMATION, FALSE, (*tlsit)->threadid);
427 if (thread == NULL) {
428 // Couldn't query this thread. We'll assume that it exited.
429 continue; // XXX should we check GetLastError()?
431 if (GetProcessIdOfThread(thread) != dwCurProcessID) {
432 //The thread ID has been recycled.
436 while (WaitForSingleObject(thread, 10000) == WAIT_TIMEOUT) { // 10 seconds
437 // There is still at least one other thread running. The CRT
438 // will stomp it dead when it cleans up, which is not a
439 // graceful way for a thread to go down. Warn about this,
440 // and wait until the thread has exited so that we know it
441 // can't still be off running somewhere in VLD's code.
443 // Since we've been waiting a while, let the human know we are
444 // still here and alive.
445 threadsactive = TRUE;
446 report(L"Visual Leak Detector: Waiting for threads to terminate...\n");
450 LeaveCriticalSection(&m_tlslock);
452 if (m_status & VLD_STATUS_NEVER_ENABLED) {
453 // Visual Leak Detector started with leak detection disabled and
454 // it was never enabled at runtime. A lot of good that does.
455 report(L"WARNING: Visual Leak Detector: Memory leak detection was never enabled.\n");
458 // Generate a memory leak report for each heap in the process.
459 for (heapit = m_heapmap->begin(); heapit != m_heapmap->end(); ++heapit) {
460 heap = (*heapit).first;
465 if (m_leaksfound == 0) {
466 report(L"No memory leaks detected.\n");
469 report(L"Visual Leak Detector detected %lu memory leak", m_leaksfound);
470 report((m_leaksfound > 1) ? L"s.\n" : L".\n");
474 // Free resources used by the symbol handler.
475 if (!SymCleanup(currentprocess)) {
476 report(L"WARNING: Visual Leak Detector: The symbol handler failed to deallocate resources (error=%lu).\n",
480 // Free internally allocated resources used by the heapmap and blockmap.
481 for (heapit = m_heapmap->begin(); heapit != m_heapmap->end(); ++heapit) {
482 blockmap = &(*heapit).second->blockmap;
483 for (blockit = blockmap->begin(); blockit != blockmap->end(); ++blockit) {
484 delete (*blockit).second->callstack;
485 delete (*blockit).second;
491 // Free internally allocated resources used by the loaded module set.
492 for (moduleit = m_loadedmodules->begin(); moduleit != m_loadedmodules->end(); ++moduleit) {
493 delete (*moduleit).name;
494 delete (*moduleit).path;
496 delete m_loadedmodules;
498 // Free internally allocated resources used for thread local storage.
499 for (tlsit = m_tlsset->begin(); tlsit != m_tlsset->end(); ++tlsit) {
504 // Do a memory leak self-check.
505 header = vldblocklist;
507 // Doh! VLD still has an internally allocated block!
508 // This won't ever actually happen, right guys?... guys?
510 leakfile = header->file;
511 leakline = header->line;
512 mbstowcs_s(&count, leakfilew, MAX_PATH, leakfile, _TRUNCATE);
513 report(L"ERROR: Visual Leak Detector: Detected a memory leak internal to Visual Leak Detector!!\n");
514 report(L"---------- Block %ld at " ADDRESSFORMAT L": %u bytes ----------\n", header->serialnumber,
515 VLDBLOCKDATA(header), header->size);
516 report(L" Call Stack:\n");
517 report(L" %s (%d): Full call stack not available.\n", leakfilew, leakline);
518 if (m_maxdatadump != 0) {
520 if (m_options & VLD_OPT_UNICODE_REPORT) {
521 dumpmemoryw(VLDBLOCKDATA(header), (m_maxdatadump < header->size) ? m_maxdatadump : header->size);
524 dumpmemorya(VLDBLOCKDATA(header), (m_maxdatadump < header->size) ? m_maxdatadump : header->size);
528 header = header->next;
530 if (m_options & VLD_OPT_SELF_TEST) {
531 if ((internalleaks == 1) && (strcmp(leakfile, m_selftestfile) == 0) && (leakline == m_selftestline)) {
532 report(L"Visual Leak Detector passed the memory leak self-test.\n");
535 report(L"ERROR: Visual Leak Detector: Failed the memory leak self-test.\n");
539 if (threadsactive == TRUE) {
540 report(L"WARNING: Visual Leak Detector: Some threads appear to have not terminated normally.\n"
541 L" This could cause inaccurate leak detection results, including false positives.\n");
543 report(L"Visual Leak Detector is now exiting.\n");
546 // VLD failed to load properly.
550 HeapDestroy(vldheap);
552 DeleteCriticalSection(&imagelock);
553 DeleteCriticalSection(&m_loaderlock);
554 DeleteCriticalSection(&m_maplock);
555 DeleteCriticalSection(&m_moduleslock);
556 DeleteCriticalSection(&stackwalklock);
557 DeleteCriticalSection(&symbollock);
558 DeleteCriticalSection(&vldheaplock);
560 if (m_tlsindex != TLS_OUT_OF_INDEXES) {
564 if (m_reportfile != NULL) {
565 fclose(m_reportfile);
570 ////////////////////////////////////////////////////////////////////////////////
572 // Private Leak Detection Functions
574 ////////////////////////////////////////////////////////////////////////////////
576 // attachtoloadedmodules - Attaches VLD to all modules contained in the provided
577 // ModuleSet. Not all modules are in the ModuleSet will actually be included
578 // in leak detection. Only modules that import the global VisualLeakDetector
579 // class object, or those that are otherwise explicitly included in leak
580 // detection, will be checked for memory leaks.
582 // When VLD attaches to a module, it means that any of the imports listed in
583 // the import patch table which are imported by the module, will be redirected
584 // to VLD's designated replacements.
586 // - newmodules (IN): Pointer to a ModuleSet containing information about any
587 // loaded modules that need to be attached.
593 VOID VisualLeakDetector::attachtoloadedmodules (ModuleSet *newmodules)
598 IMAGEHLP_MODULE64 moduleimageinfo;
600 #define MAXMODULENAME (_MAX_FNAME + _MAX_EXT)
601 WCHAR modulenamew [MAXMODULENAME];
604 ModuleSet::Iterator newit;
605 ModuleSet::Iterator oldit;
606 ModuleSet *oldmodules;
608 UINT tablesize = sizeof(m_patchtable) / sizeof(patchentry_t);
609 ModuleSet::Muterator updateit;
611 // Iterate through the supplied set, until all modules have been attached.
612 for (newit = newmodules->begin(); newit != newmodules->end(); ++newit) {
613 modulebase = (DWORD64)(*newit).addrlow;
615 modulename = (*newit).name;
616 modulepath = (*newit).path;
617 modulesize = (DWORD)((*newit).addrhigh - (*newit).addrlow) + 1;
620 EnterCriticalSection(&m_moduleslock);
621 oldmodules = m_loadedmodules;
622 if (oldmodules != NULL) {
623 // This is not the first time we have been called to attach to the
624 // currently loaded modules.
625 oldit = oldmodules->find(*newit);
626 if (oldit != oldmodules->end()) {
627 // We've seen this "new" module loaded in the process before.
628 moduleflags = (*oldit).flags;
629 LeaveCriticalSection(&m_moduleslock);
630 if (moduleispatched((HMODULE)modulebase, m_patchtable, tablesize)) {
631 // This module is already attached. Just update the module's
632 // flags, nothing more.
634 (*updateit).flags = moduleflags;
638 // This module may have been attached before and has been
639 // detached. We'll need to try reattaching to it in case it
640 // was unloaded and then subsequently reloaded.
645 LeaveCriticalSection(&m_moduleslock);
649 LeaveCriticalSection(&m_moduleslock);
652 EnterCriticalSection(&symbollock);
653 if ((refresh == TRUE) && (moduleflags & VLD_MODULE_SYMBOLSLOADED)) {
654 // Discard the previously loaded symbols, so we can refresh them.
655 if (SymUnloadModule64(currentprocess, modulebase) == FALSE) {
656 report(L"WARNING: Visual Leak Detector: Failed to unload the symbols for %s. Function names and line"
657 L" numbers shown in the memory leak report for %s may be inaccurate.", modulename, modulename);
661 // Try to load the module's symbols. This ensures that we have loaded
662 // the symbols for every module that has ever been loaded into the
663 // process, guaranteeing the symbols' availability when generating the
665 moduleimageinfo.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
666 if ((SymGetModuleInfoW64(currentprocess, (DWORD64)modulebase, &moduleimageinfo) == TRUE) ||
667 ((SymLoadModule64(currentprocess, NULL, modulepath, NULL, modulebase, modulesize) == modulebase) &&
668 (SymGetModuleInfoW64(currentprocess, modulebase, &moduleimageinfo) == TRUE))) {
669 moduleflags |= VLD_MODULE_SYMBOLSLOADED;
671 LeaveCriticalSection(&symbollock);
673 if (_stricmp("vld.dll", modulename) == 0) {
674 // What happens when a module goes through it's own portal? Bad things.
675 // Like infinite recursion. And ugly bald men wearing dresses. VLD
676 // should not, therefore, attach to itself.
680 mbstowcs_s(&count, modulenamew, MAXMODULENAME, modulename, _TRUNCATE);
681 if ((findimport((HMODULE)modulebase, m_vldbase, "vld.dll", "?vld@@3VVisualLeakDetector@@A") == FALSE) &&
682 (wcsstr(vld.m_forcedmodulelist, modulenamew) == NULL)) {
683 // This module does not import VLD. This means that none of the module's
684 // sources #included vld.h. Exclude this module from leak detection.
685 moduleflags |= VLD_MODULE_EXCLUDED;
687 else if (!(moduleflags & VLD_MODULE_SYMBOLSLOADED) || (moduleimageinfo.SymType == SymExport)) {
688 // This module is going to be included in leak detection, but complete
689 // symbols for this module couldn't be loaded. This means that any stack
690 // traces through this module may lack information, like line numbers
691 // and function names.
692 report(L"WARNING: Visual Leak Detector: A module, %s, included in memory leak detection\n"
693 L" does not have any debugging symbols available, or they could not be located.\n"
694 L" Function names and/or line numbers for this module may not be available.\n", modulename);
697 // Update the module's flags in the "new modules" set.
699 (*updateit).flags = moduleflags;
701 // Attach to the module.
702 patchmodule((HMODULE)modulebase, m_patchtable, tablesize);
706 // buildsymbolsearchpath - Builds the symbol search path for the symbol handler.
707 // This helps the symbol handler find the symbols for the application being
712 // Returns a string containing the search path. The caller is responsible for
713 // freeing the string.
715 LPWSTR VisualLeakDetector::buildsymbolsearchpath ()
717 WCHAR directory [_MAX_DIR];
718 WCHAR drive [_MAX_DRIVE];
724 LPWSTR path = new WCHAR [MAX_PATH];
726 WCHAR system [MAX_PATH];
727 WCHAR windows [MAX_PATH];
729 // Oddly, the symbol handler ignores the link to the PDB embedded in the
730 // executable image. So, we'll manually add the location of the executable
731 // to the search path since that is often where the PDB will be located.
733 module = GetModuleHandle(NULL);
734 GetModuleFileName(module, path, MAX_PATH);
735 _wsplitpath_s(path, drive, _MAX_DRIVE, directory, _MAX_DIR, NULL, 0, NULL, 0);
736 wcsncpy_s(path, MAX_PATH, drive, _TRUNCATE);
737 strapp(&path, directory);
739 // When the symbol handler is given a custom symbol search path, it will no
740 // longer search the default directories (working directory, system root,
741 // etc). But we'd like it to still search those directories, so we'll add
742 // them to our custom search path.
744 // Append the working directory.
745 strapp(&path, L";.\\");
747 // Append the Windows directory.
748 if (GetWindowsDirectory(windows, MAX_PATH) != 0) {
750 strapp(&path, windows);
753 // Append the system directory.
754 if (GetSystemDirectory(system, MAX_PATH) != 0) {
756 strapp(&path, system);
759 // Append %_NT_SYMBOL_PATH%.
760 envlen = GetEnvironmentVariable(L"_NT_SYMBOL_PATH", NULL, 0);
762 env = new WCHAR [envlen];
763 if (GetEnvironmentVariable(L"_NT_SYMBOL_PATH", env, envlen) != 0) {
770 // Append %_NT_ALT_SYMBOL_PATH%.
771 envlen = GetEnvironmentVariable(L"_NT_ALT_SYMBOL_PATH", NULL, 0);
773 env = new WCHAR [envlen];
774 if (GetEnvironmentVariable(L"_NT_ALT_SYMBOL_PATH", env, envlen) != 0) {
781 // Remove any quotes from the path. The symbol handler doesn't like them.
783 length = wcslen(path);
784 while (pos < length) {
785 if (path[pos] == L'\"') {
786 for (index = pos; index < length; index++) {
787 path[index] = path[index + 1];
796 // configure - Configures VLD using values read from the vld.ini file.
802 VOID VisualLeakDetector::configure ()
805 WCHAR buffer [BSIZE];
806 WCHAR filename [MAX_PATH];
807 WCHAR inipath [MAX_PATH];
808 BOOL keyopen = FALSE;
815 if (_wstat(L".\\vld.ini", &s) == 0) {
816 // Found a copy of vld.ini in the working directory. Use it.
817 wcsncpy_s(inipath, MAX_PATH, L".\\vld.ini", _TRUNCATE);
820 // Get the location of the vld.ini file from the registry.
821 regstatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, VLDREGKEYPRODUCT, 0, KEY_QUERY_VALUE, &productkey);
822 if (regstatus == ERROR_SUCCESS) {
824 regstatus = RegQueryValueEx(productkey, L"IniFile", NULL, &valuetype, (LPBYTE)&inipath, &length);
827 RegCloseKey(productkey);
829 if ((regstatus != ERROR_SUCCESS) || (_wstat(inipath, &s) != 0)) {
830 // The location of vld.ini could not be read from the registry. As a
831 // last resort, look in the Windows directory.
832 wcsncpy_s(inipath, MAX_PATH, L"vld.ini", _TRUNCATE);
836 // Read the boolean options.
837 GetPrivateProfileString(L"Options", L"VLD", L"on", buffer, BSIZE, inipath);
838 if (strtobool(buffer) == FALSE) {
839 m_options |= VLD_OPT_VLDOFF;
843 GetPrivateProfileString(L"Options", L"AggregateDuplicates", L"", buffer, BSIZE, inipath);
844 if (strtobool(buffer) == TRUE) {
845 m_options |= VLD_OPT_AGGREGATE_DUPLICATES;
848 GetPrivateProfileString(L"Options", L"SelfTest", L"", buffer, BSIZE, inipath);
849 if (strtobool(buffer) == TRUE) {
850 m_options |= VLD_OPT_SELF_TEST;
853 GetPrivateProfileString(L"Options", L"SlowDebuggerDump", L"", buffer, BSIZE, inipath);
854 if (strtobool(buffer) == TRUE) {
855 m_options |= VLD_OPT_SLOW_DEBUGGER_DUMP;
858 GetPrivateProfileString(L"Options", L"StartDisabled", L"", buffer, BSIZE, inipath);
859 if (strtobool(buffer) == TRUE) {
860 m_options |= VLD_OPT_START_DISABLED;
863 GetPrivateProfileString(L"Options", L"TraceInternalFrames", L"", buffer, BSIZE, inipath);
864 if (strtobool(buffer) == TRUE) {
865 m_options |= VLD_OPT_TRACE_INTERNAL_FRAMES;
868 // Read the integer configuration options.
869 m_maxdatadump = GetPrivateProfileInt(L"Options", L"MaxDataDump", VLD_DEFAULT_MAX_DATA_DUMP, inipath);
870 m_maxtraceframes = GetPrivateProfileInt(L"Options", L"MaxTraceFrames", VLD_DEFAULT_MAX_TRACE_FRAMES, inipath);
871 if (m_maxtraceframes < 1) {
872 m_maxtraceframes = VLD_DEFAULT_MAX_TRACE_FRAMES;
875 // Read the force-include module list.
876 GetPrivateProfileString(L"Options", L"ForceIncludeModules", L"", m_forcedmodulelist, MAXMODULELISTLENGTH, inipath);
877 _wcslwr_s(m_forcedmodulelist, MAXMODULELISTLENGTH);
879 // Read the report destination (debugger, file, or both).
880 GetPrivateProfileString(L"Options", L"ReportFile", L"", filename, MAX_PATH, inipath);
881 if (wcslen(filename) == 0) {
882 wcsncpy_s(filename, MAX_PATH, VLD_DEFAULT_REPORT_FILE_NAME, _TRUNCATE);
884 _wfullpath(m_reportfilepath, filename, MAX_PATH);
885 GetPrivateProfileString(L"Options", L"ReportTo", L"", buffer, BSIZE, inipath);
886 if (_wcsicmp(buffer, L"both") == 0) {
887 m_options |= (VLD_OPT_REPORT_TO_DEBUGGER | VLD_OPT_REPORT_TO_FILE);
889 else if (_wcsicmp(buffer, L"file") == 0) {
890 m_options |= VLD_OPT_REPORT_TO_FILE;
893 m_options |= VLD_OPT_REPORT_TO_DEBUGGER;
896 // Read the report file encoding (ascii or unicode).
897 GetPrivateProfileString(L"Options", L"ReportEncoding", L"", buffer, BSIZE, inipath);
898 if (_wcsicmp(buffer, L"unicode") == 0) {
899 m_options |= VLD_OPT_UNICODE_REPORT;
901 if ((m_options & VLD_OPT_UNICODE_REPORT) && !(m_options & VLD_OPT_REPORT_TO_FILE)) {
902 // If Unicode report encoding is enabled, then the report needs to be
903 // sent to a file because the debugger will not display Unicode
904 // characters, it will display question marks in their place instead.
905 m_options |= VLD_OPT_REPORT_TO_FILE;
906 m_status |= VLD_STATUS_FORCE_REPORT_TO_FILE;
909 // Read the stack walking method.
910 GetPrivateProfileString(L"Options", L"StackWalkMethod", L"", buffer, BSIZE, inipath);
911 if (_wcsicmp(buffer, L"safe") == 0) {
912 m_options |= VLD_OPT_SAFE_STACK_WALK;
916 // enabled - Determines if memory leak detection is enabled for the current
921 // Returns true if Visual Leak Detector is enabled for the current thread.
922 // Otherwise, returns false.
924 BOOL VisualLeakDetector::enabled ()
926 tls_t *tls = vld.gettls();
928 if (!(m_status & VLD_STATUS_INSTALLED)) {
929 // Memory leak detection is not yet enabled because VLD is still
934 if (!(tls->flags & VLD_TLS_DISABLED) && !(tls->flags & VLD_TLS_ENABLED)) {
935 // The enabled/disabled state for the current thread has not been
936 // initialized yet. Use the default state.
937 if (m_options & VLD_OPT_START_DISABLED) {
938 tls->flags |= VLD_TLS_DISABLED;
941 tls->flags |= VLD_TLS_ENABLED;
945 return ((tls->flags & VLD_TLS_ENABLED) != 0);
948 // eraseduplicates - Erases, from the block maps, blocks that appear to be
949 // duplicate leaks of an already identified leak.
951 // - element (IN): BlockMap Iterator referencing the block of which to search
956 // Returns the number of duplicate blocks erased from the block map.
958 SIZE_T VisualLeakDetector::eraseduplicates (const BlockMap::Iterator &element)
960 BlockMap::Iterator blockit;
962 blockinfo_t *elementinfo;
964 HeapMap::Iterator heapit;
966 BlockMap::Iterator previt;
968 elementinfo = (*element).second;
970 // Iteratate through all block maps, looking for blocks with the same size
971 // and callstack as the specified element.
972 for (heapit = m_heapmap->begin(); heapit != m_heapmap->end(); ++heapit) {
973 blockmap = &(*heapit).second->blockmap;
974 for (blockit = blockmap->begin(); blockit != blockmap->end(); ++blockit) {
975 if (blockit == element) {
976 // Don't delete the element of which we are searching for
980 info = (*blockit).second;
981 if ((info->size == elementinfo->size) && (*(info->callstack) == *(elementinfo->callstack))) {
982 // Found a duplicate. Erase it.
983 delete info->callstack;
985 previt = blockit - 1;
986 blockmap->erase(blockit);
996 // gettls - Obtains the thread local storage structure for the calling thread.
1000 // Returns a pointer to the thread local storage structure. (This function
1001 // always succeeds).
1003 tls_t* VisualLeakDetector::gettls ()
1007 // Get the pointer to this thread's thread local storage structure.
1008 tls = (tls_t*)TlsGetValue(m_tlsindex);
1009 assert(GetLastError() == ERROR_SUCCESS);
1012 // This thread's thread local storage structure has not been allocated.
1014 TlsSetValue(m_tlsindex, tls);
1017 tls->threadid = GetCurrentThreadId();
1019 // Add this thread's TLS to the TlsSet.
1020 EnterCriticalSection(&m_tlslock);
1021 m_tlsset->insert(tls);
1022 LeaveCriticalSection(&m_tlslock);
1028 // mapblock - Tracks memory allocations. Information about allocated blocks is
1029 // collected and then the block is mapped to this information.
1031 // - heap (IN): Handle to the heap from which the block has been allocated.
1033 // - mem (IN): Pointer to the memory block being allocated.
1035 // - size (IN): Size, in bytes, of the memory block being allocated.
1037 // - framepointer (IN): Framepointer at the time this allocation first entered
1038 // VLD's code. This is used from determining the starting point for the
1041 // - crtalloc (IN): Should be set to TRUE if this allocation is a CRT memory
1042 // block. Otherwise should be FALSE.
1048 VOID VisualLeakDetector::mapblock (HANDLE heap, LPCVOID mem, SIZE_T size, SIZE_T framepointer, BOOL crtalloc)
1050 blockinfo_t *blockinfo;
1051 BlockMap::Iterator blockit;
1053 HeapMap::Iterator heapit;
1054 static SIZE_T serialnumber = 0;
1056 // Record the block's information.
1057 blockinfo = new blockinfo_t;
1058 if (m_options & VLD_OPT_SAFE_STACK_WALK) {
1059 blockinfo->callstack = new SafeCallStack;
1062 blockinfo->callstack = new FastCallStack;
1064 if (m_options & VLD_OPT_TRACE_INTERNAL_FRAMES) {
1065 // Passing NULL for the frame pointer argument will force the stack
1066 // trace to begin at the current frame.
1067 blockinfo->callstack->getstacktrace(m_maxtraceframes, NULL);
1070 // Start the stack trace at the call that first entered VLD's code.
1071 blockinfo->callstack->getstacktrace(m_maxtraceframes, (SIZE_T*)framepointer);
1073 blockinfo->serialnumber = serialnumber++;
1074 blockinfo->size = size;
1076 // Insert the block's information into the block map.
1077 EnterCriticalSection(&m_maplock);
1078 heapit = m_heapmap->find(heap);
1079 if (heapit == m_heapmap->end()) {
1080 // We haven't mapped this heap to a block map yet. Do it now.
1082 heapit = m_heapmap->find(heap);
1083 assert(heapit != m_heapmap->end());
1085 if (crtalloc == TRUE) {
1086 // The heap that this block was allocated from is a CRT heap.
1087 (*heapit).second->flags |= VLD_HEAP_CRT;
1089 blockmap = &(*heapit).second->blockmap;
1090 blockit = blockmap->insert(mem, blockinfo);
1091 if (blockit == blockmap->end()) {
1092 // A block with this address has already been allocated. The
1093 // previously allocated block must have been freed (probably by some
1094 // mechanism unknown to VLD), or the heap wouldn't have allocated it
1095 // again. Replace the previously allocated info with the new info.
1096 blockit = blockmap->find(mem);
1097 delete (*blockit).second->callstack;
1098 delete (*blockit).second;
1099 blockmap->erase(blockit);
1100 blockmap->insert(mem, blockinfo);
1102 LeaveCriticalSection(&m_maplock);
1105 // mapheap - Tracks heap creation. Creates a block map for tracking individual
1106 // allocations from the newly created heap and then maps the heap to this
1109 // - heap (IN): Handle to the newly created heap.
1115 VOID VisualLeakDetector::mapheap (HANDLE heap)
1117 heapinfo_t *heapinfo;
1118 HeapMap::Iterator heapit;
1120 // Create a new block map for this heap and insert it into the heap map.
1121 heapinfo = new heapinfo_t;
1122 heapinfo->blockmap.reserve(BLOCKMAPRESERVE);
1123 heapinfo->flags = 0x0;
1124 EnterCriticalSection(&m_maplock);
1125 heapit = m_heapmap->insert(heap, heapinfo);
1126 if (heapit == m_heapmap->end()) {
1127 // Somehow this heap has been created twice without being destroyed,
1128 // or at least it was destroyed without VLD's knowledge. Unmap the heap
1129 // from the existing heapinfo, and remap it to the new one.
1130 report(L"WARNING: Visual Leak Detector detected a duplicate heap (" ADDRESSFORMAT L").\n", heap);
1131 heapit = m_heapmap->find(heap);
1132 unmapheap((*heapit).first);
1133 m_heapmap->insert(heap, heapinfo);
1135 LeaveCriticalSection(&m_maplock);
1138 // remapblock - Tracks reallocations. Unmaps a block from its previously
1139 // collected information and remaps it to updated information.
1141 // Note: If the block itself remains at the same address, then the block's
1142 // information can simply be updated rather than having to actually erase and
1143 // reinsert the block.
1145 // - heap (IN): Handle to the heap from which the memory is being reallocated.
1147 // - mem (IN): Pointer to the memory block being reallocated.
1149 // - newmem (IN): Pointer to the memory block being returned to the caller
1150 // that requested the reallocation. This pointer may or may not be the same
1151 // as the original memory block (as pointed to by "mem").
1153 // - size (IN): Size, in bytes, of the new memory block.
1155 // - framepointer (IN): The frame pointer at which this reallocation entered
1156 // VLD's code. Used for determining the starting point of the stack trace.
1158 // - crtalloc (IN): Should be set to TRUE if this reallocation is for a CRT
1159 // memory block. Otherwise should be set to FALSE.
1165 VOID VisualLeakDetector::remapblock (HANDLE heap, LPCVOID mem, LPCVOID newmem, SIZE_T size, SIZE_T framepointer,
1168 BlockMap::Iterator blockit;
1170 HeapMap::Iterator heapit;
1173 if (newmem != mem) {
1174 // The block was not reallocated in-place. Instead the old block was
1175 // freed and a new block allocated to satisfy the new size.
1176 unmapblock(heap, mem);
1177 mapblock(heap, newmem, size, framepointer, crtalloc);
1181 // The block was reallocated in-place. Find the existing blockinfo_t
1182 // entry in the block map and update it with the new callstack and size.
1183 EnterCriticalSection(&m_maplock);
1184 heapit = m_heapmap->find(heap);
1185 if (heapit == m_heapmap->end()) {
1186 // We haven't mapped this heap to a block map yet. Obviously the
1187 // block has also not been mapped to a blockinfo_t entry yet either,
1188 // so treat this reallocation as a brand-new allocation (this will
1189 // also map the heap to a new block map).
1190 mapblock(heap, newmem, size, framepointer, crtalloc);
1191 LeaveCriticalSection(&m_maplock);
1195 // Find the block's blockinfo_t structure so that we can update it.
1196 blockmap = &(*heapit).second->blockmap;
1197 blockit = blockmap->find(mem);
1198 if (blockit == blockmap->end()) {
1199 // The block hasn't been mapped to a blockinfo_t entry yet.
1200 // Treat this reallocation as a new allocation.
1201 mapblock(heap, newmem, size, framepointer, crtalloc);
1202 LeaveCriticalSection(&m_maplock);
1206 // Found the blockinfo_t entry for this block. Update it with
1207 // a new callstack and new size.
1208 info = (*blockit).second;
1209 info->callstack->clear();
1211 // The heap that this block was allocated from is a CRT heap.
1212 (*heapit).second->flags |= VLD_HEAP_CRT;
1214 LeaveCriticalSection(&m_maplock);
1216 // Update the block's callstack and size.
1217 if (m_options & VLD_OPT_TRACE_INTERNAL_FRAMES) {
1218 // Passing NULL for the frame pointer argument will force
1219 // the stack trace to begin at the current frame.
1220 info->callstack->getstacktrace(m_maxtraceframes, NULL);
1223 // Start the stack trace at the call that first entered
1225 info->callstack->getstacktrace(m_maxtraceframes, (SIZE_T*)framepointer);
1230 // reportconfig - Generates a brief report summarizing Visual Leak Detector's
1231 // configuration, as loaded from the vld.ini file.
1237 VOID VisualLeakDetector::reportconfig ()
1239 if (m_options & VLD_OPT_AGGREGATE_DUPLICATES) {
1240 report(L" Aggregating duplicate leaks.\n");
1242 if (wcslen(m_forcedmodulelist) != 0) {
1243 report(L" Forcing inclusion of these modules in leak detection: %s\n", m_forcedmodulelist);
1245 if (m_maxdatadump != VLD_DEFAULT_MAX_DATA_DUMP) {
1246 if (m_maxdatadump == 0) {
1247 report(L" Suppressing data dumps.\n");
1250 report(L" Limiting data dumps to %lu bytes.\n", m_maxdatadump);
1253 if (m_maxtraceframes != VLD_DEFAULT_MAX_TRACE_FRAMES) {
1254 report(L" Limiting stack traces to %u frames.\n", m_maxtraceframes);
1256 if (m_options & VLD_OPT_UNICODE_REPORT) {
1257 report(L" Generating a Unicode (UTF-16) encoded report.\n");
1259 if (m_options & VLD_OPT_REPORT_TO_FILE) {
1260 if (m_options & VLD_OPT_REPORT_TO_DEBUGGER) {
1261 report(L" Outputting the report to the debugger and to %s\n", m_reportfilepath);
1264 report(L" Outputting the report to %s\n", m_reportfilepath);
1267 if (m_options & VLD_OPT_SLOW_DEBUGGER_DUMP) {
1268 report(L" Outputting the report to the debugger at a slower rate.\n");
1270 if (m_options & VLD_OPT_SAFE_STACK_WALK) {
1271 report(L" Using the \"safe\" (but slow) stack walking method.\n");
1273 if (m_options & VLD_OPT_SELF_TEST) {
1274 report(L" Perfoming a memory leak self-test.\n");
1276 if (m_options & VLD_OPT_START_DISABLED) {
1277 report(L" Starting with memory leak detection disabled.\n");
1279 if (m_options & VLD_OPT_TRACE_INTERNAL_FRAMES) {
1280 report(L" Including heap and VLD internal frames in stack traces.\n");
1284 // reportleaks - Generates a memory leak report for the specified heap.
1286 // - heap (IN): Handle to the heap for which to generate a memory leak
1293 VOID VisualLeakDetector::reportleaks (HANDLE heap)
1297 BlockMap::Iterator blockit;
1299 crtdbgblockheader_t *crtheader;
1301 heapinfo_t *heapinfo;
1302 HeapMap::Iterator heapit;
1306 // Find the heap's information (blockmap, etc).
1307 EnterCriticalSection(&m_maplock);
1308 heapit = m_heapmap->find(heap);
1309 if (heapit == m_heapmap->end()) {
1310 // Nothing is allocated from this heap. No leaks.
1311 LeaveCriticalSection(&m_maplock);
1315 heapinfo = (*heapit).second;
1316 blockmap = &heapinfo->blockmap;
1317 for (blockit = blockmap->begin(); blockit != blockmap->end(); ++blockit) {
1318 // Found a block which is still in the BlockMap. We've identified a
1319 // potential memory leak.
1320 block = (*blockit).first;
1321 info = (*blockit).second;
1324 if (heapinfo->flags & VLD_HEAP_CRT) {
1325 // This block is allocated to a CRT heap, so the block has a CRT
1326 // memory block header prepended to it.
1327 crtheader = (crtdbgblockheader_t*)block;
1328 if (CRT_USE_TYPE(crtheader->use) == CRT_USE_INTERNAL) {
1329 // This block is marked as being used internally by the CRT.
1330 // The CRT will free the block after VLD is destroyed.
1333 // The CRT header is more or less transparent to the user, so
1334 // the information about the contained block will probably be
1335 // more useful to the user. Accordingly, that's the information
1336 // we'll include in the report.
1337 address = CRTDBGBLOCKDATA(block);
1338 size = crtheader->size;
1340 // It looks like a real memory leak.
1341 if (m_leaksfound == 0) {
1342 report(L"WARNING: Visual Leak Detector detected memory leaks!\n");
1345 report(L"---------- Block %ld at " ADDRESSFORMAT L": %u bytes ----------\n", info->serialnumber, address, size);
1346 if (m_options & VLD_OPT_AGGREGATE_DUPLICATES) {
1347 // Aggregate all other leaks which are duplicates of this one
1348 // under this same heading, to cut down on clutter.
1349 duplicates = eraseduplicates(blockit);
1351 report(L"A total of %lu leaks match this size and call stack. Showing only the first one.\n",
1353 m_leaksfound += duplicates;
1356 // Dump the call stack.
1357 report(L" Call Stack:\n");
1358 info->callstack->dump(m_options & VLD_OPT_TRACE_INTERNAL_FRAMES);
1359 // Dump the data in the user data section of the memory block.
1360 if (m_maxdatadump != 0) {
1361 report(L" Data:\n");
1362 if (m_options & VLD_OPT_UNICODE_REPORT) {
1363 dumpmemoryw(address, (m_maxdatadump < size) ? m_maxdatadump : size);
1366 dumpmemorya(address, (m_maxdatadump < size) ? m_maxdatadump : size);
1372 LeaveCriticalSection(&m_maplock);
1375 // unmapblock - Tracks memory blocks that are freed. Unmaps the specified block
1376 // from the block's information, relinquishing internally allocated resources.
1378 // - heap (IN): Handle to the heap to which this block is being freed.
1380 // - mem (IN): Pointer to the memory block being freed.
1386 VOID VisualLeakDetector::unmapblock (HANDLE heap, LPCVOID mem)
1388 BlockMap::Iterator blockit;
1390 HeapMap::Iterator heapit;
1393 // Find this heap's block map.
1394 EnterCriticalSection(&m_maplock);
1395 heapit = m_heapmap->find(heap);
1396 if (heapit == m_heapmap->end()) {
1397 // We don't have a block map for this heap. We must not have monitored
1398 // this allocation (probably happened before VLD was initialized).
1399 LeaveCriticalSection(&m_maplock);
1403 // Find this block in the block map.
1404 blockmap = &(*heapit).second->blockmap;
1405 blockit = blockmap->find(mem);
1406 if (blockit == blockmap->end()) {
1407 // This block is not in the block map. We must not have monitored this
1408 // allocation (probably happened before VLD was initialized).
1409 LeaveCriticalSection(&m_maplock);
1413 // Free the blockinfo_t structure and erase it from the block map.
1414 info = (*blockit).second;
1415 delete info->callstack;
1417 blockmap->erase(blockit);
1418 LeaveCriticalSection(&m_maplock);
1421 // unmapheap - Tracks heap destruction. Unmaps the specified heap from its block
1422 // map. The block map is cleared and deleted, relinquishing internally
1423 // allocated resources.
1425 // - heap (IN): Handle to the heap which is being destroyed.
1431 VOID VisualLeakDetector::unmapheap (HANDLE heap)
1433 BlockMap::Iterator blockit;
1435 heapinfo_t *heapinfo;
1436 HeapMap::Iterator heapit;
1438 // Find this heap's block map.
1439 EnterCriticalSection(&m_maplock);
1440 heapit = m_heapmap->find(heap);
1441 if (heapit == m_heapmap->end()) {
1442 // This heap hasn't been mapped. We must not have monitored this heap's
1443 // creation (probably happened before VLD was initialized).
1444 LeaveCriticalSection(&m_maplock);
1448 // Free all of the blockinfo_t structures stored in the block map.
1449 heapinfo = (*heapit).second;
1450 blockmap = &heapinfo->blockmap;
1451 for (blockit = blockmap->begin(); blockit != blockmap->end(); ++blockit) {
1452 delete (*blockit).second->callstack;
1453 delete (*blockit).second;
1457 // Remove this heap's block map from the heap map.
1458 m_heapmap->erase(heapit);
1459 LeaveCriticalSection(&m_maplock);
1463 ////////////////////////////////////////////////////////////////////////////////
1465 // Static Leak Detection Functions (Callbacks)
1467 ////////////////////////////////////////////////////////////////////////////////
1469 // addloadedmodule - Callback function for EnumerateLoadedModules64. This
1470 // function records information about every module loaded in the process,
1471 // each time adding the module's information to the provided ModuleSet (the
1472 // "context" parameter).
1474 // When EnumerateLoadedModules64 has finished calling this function for each
1475 // loaded module, then the resulting ModuleSet can be used at any time to get
1476 // information about any modules loaded into the process.
1478 // - modulepath (IN): The fully qualified path from where the module was
1481 // - modulebase (IN): The base address at which the module has been loaded.
1483 // - modulesize (IN): The size, in bytes, of the loaded module.
1485 // - context (IN): Pointer to the ModuleSet to which information about each
1486 // module is to be added.
1490 // Always returns TRUE, which tells EnumerateLoadedModules64 to continue
1493 BOOL VisualLeakDetector::addloadedmodule (PCWSTR modulepath, DWORD64 modulebase, ULONG modulesize, PVOID context)
1496 patchentry_t *entry;
1497 CHAR extension [_MAX_EXT];
1498 CHAR filename [_MAX_FNAME];
1500 moduleinfo_t moduleinfo;
1503 ModuleSet* newmodules = (ModuleSet*)context;
1505 UINT tablesize = sizeof(m_patchtable) / sizeof(patchentry_t);
1507 // Convert the module path to ASCII.
1508 size = wcslen(modulepath) + 1;
1509 modulepatha = new CHAR [size];
1510 wcstombs_s(&count, modulepatha, size, modulepath, _TRUNCATE);
1512 // Extract just the filename and extension from the module path.
1513 _splitpath_s(modulepatha, NULL, 0, NULL, 0, filename, _MAX_FNAME, extension, _MAX_EXT);
1514 size = strlen(filename) + strlen(extension) + 1;
1515 modulenamea = new CHAR [size];
1516 strncpy_s(modulenamea, size, filename, _TRUNCATE);
1517 strncat_s(modulenamea, size, extension, _TRUNCATE);
1518 _strlwr_s(modulenamea, size);
1520 if (_stricmp(modulenamea, "vld.dll") == 0) {
1521 // Record Visual Leak Detector's own base address.
1522 vld.m_vldbase = (HMODULE)modulebase;
1525 // See if this is a module listed in the patch table. If it is, update
1526 // the corresponding patch table entries' module base address.
1527 for (index = 0; index < tablesize; index++) {
1528 entry = &m_patchtable[index];
1529 if (_stricmp(entry->exportmodulename, modulenamea) == 0) {
1530 entry->modulebase = (SIZE_T)modulebase;
1535 // Record the module's information and store it in the set.
1536 moduleinfo.addrlow = (SIZE_T)modulebase;
1537 moduleinfo.addrhigh = (SIZE_T)(modulebase + modulesize) - 1;
1538 moduleinfo.flags = 0x0;
1539 moduleinfo.name = modulenamea;
1540 moduleinfo.path = modulepatha;
1541 newmodules->insert(moduleinfo);
1546 // detachfrommodule - Callback function for EnumerateLoadedModules64 that
1547 // detaches Visual Leak Detector from the specified module. If the specified
1548 // module has not previously been attached to, then calling this function will
1549 // not actually result in any changes.
1551 // - modulepath (IN): String containing the name, which may include a path, of
1552 // the module to detach from (ignored).
1554 // - modulebase (IN): Base address of the module.
1556 // - modulesize (IN): Total size of the module (ignored).
1558 // - context (IN): User-supplied context (ignored).
1562 // Always returns TRUE.
1564 BOOL VisualLeakDetector::detachfrommodule (PCWSTR /*modulepath*/, DWORD64 modulebase, ULONG /*modulesize*/,
1567 UINT tablesize = sizeof(m_patchtable) / sizeof(patchentry_t);
1569 restoremodule((HMODULE)modulebase, m_patchtable, tablesize);
1575 ////////////////////////////////////////////////////////////////////////////////
1577 // Standard CRT and MFC IAT Replacement Functions
1579 // The addresses of these functions are not actually directly patched into the
1580 // import address tables, but these functions do get indirectly called by the
1581 // patch functions that are placed in the import address tables.
1583 ////////////////////////////////////////////////////////////////////////////////
1585 // _calloc - This function is just a wrapper around the real calloc that sets
1586 // appropriate flags to be consulted when the memory is actually allocated by
1589 // - pcalloc (IN): Pointer to the particular calloc implementation to call.
1591 // - fp (IN): Frame pointer from the call that initiated this allocation.
1593 // - num (IN): The number of blocks, of size 'size', to be allocated.
1595 // - size (IN): The size, in bytes, of the memory block to be allocated.
1599 // Returns the value returned from the specified calloc.
1601 void* VisualLeakDetector::_calloc (calloc_t pcalloc,
1607 tls_t *tls = vld.gettls();
1609 // malloc is a CRT function and allocates from the CRT heap.
1610 tls->flags |= VLD_TLS_CRTALLOC;
1612 if (tls->addrfp == 0x0) {
1613 // This is the first call to enter VLD for the current allocation.
1614 // Record the current frame pointer.
1618 // Do the allocation. The block will be mapped by _RtlAllocateHeap.
1619 block = pcalloc(num, size);
1621 // Reset thread local flags and variables for the next allocation.
1623 tls->flags &= ~VLD_TLS_CRTALLOC;
1628 // _malloc - This function is just a wrapper around the real malloc that sets
1629 // appropriate flags to be consulted when the memory is actually allocated by
1632 // - pmalloc (IN): Pointer to the particular malloc implementation to call.
1634 // - fp (IN): Frame pointer from the call that initiated this allocation.
1636 // - size (IN): The size, in bytes, of the memory block to be allocated.
1640 // Returns the value returned from the specified malloc.
1642 void *VisualLeakDetector::_malloc (malloc_t pmalloc, SIZE_T fp, size_t size)
1645 tls_t *tls = vld.gettls();
1647 // malloc is a CRT function and allocates from the CRT heap.
1648 tls->flags |= VLD_TLS_CRTALLOC;
1650 if (tls->addrfp == 0x0) {
1651 // This is the first call to enter VLD for the current allocation.
1652 // Record the current frame pointer.
1656 // Do the allocation. The block will be mapped by _RtlAllocateHeap.
1657 block = pmalloc(size);
1659 // Reset thread local flags and variables for the next allocation.
1661 tls->flags &= ~VLD_TLS_CRTALLOC;
1666 // _new - This function is just a wrapper around the real CRT and MFC new
1667 // operators that sets appropriate flags to be consulted when the memory is
1668 // actually allocated by RtlAllocateHeap.
1670 // - pnew (IN): Pointer to the particular new implementation to call.
1672 // - fp (IN): Frame pointer from the call that initiated this allocation.
1674 // - size (IN): The size, in bytes, of the memory block to be allocated.
1678 // Returns the value returned by the specified CRT new operator.
1680 void* VisualLeakDetector::_new (new_t pnew, SIZE_T fp, size_t size)
1683 tls_t *tls = vld.gettls();
1685 // The new operator is a CRT function and allocates from the CRT heap.
1686 tls->flags |= VLD_TLS_CRTALLOC;
1688 if (tls->addrfp == 0x0) {
1689 // This is the first call to enter VLD for the current allocation.
1690 // Record the current frame pointer.
1694 // Do the allocation. The block will be mapped by _RtlAllocateHeap.
1697 // Reset thread local flags and variables for the next allocation.
1699 tls->flags &= ~VLD_TLS_CRTALLOC;
1704 // _realloc - This function is just a wrapper around the real realloc that sets
1705 // appropriate flags to be consulted when the memory is actually allocated by
1708 // - prealloc (IN): Pointer to the particular realloc implementation to call.
1710 // - fp (IN): Frame pointer from the call that initiated this allocation.
1712 // - mem (IN): Pointer to the memory block to reallocate.
1714 // - size (IN): Size of the memory block to reallocate.
1718 // Returns the value returned from the specified realloc.
1720 void* VisualLeakDetector::_realloc (realloc_t prealloc,
1726 tls_t *tls = vld.gettls();
1728 // realloc is a CRT function and allocates from the CRT heap.
1729 tls->flags |= VLD_TLS_CRTALLOC;
1731 if (tls->addrfp == 0x0) {
1732 // This is the first call to enter VLD for the current allocation.
1733 // Record the current frame pointer.
1737 // Do the allocation. The block will be mapped by _RtlReAllocateHeap.
1738 block = prealloc(mem, size);
1740 // Reset thread local flags and variables for the next allocation.
1742 tls->flags &= ~VLD_TLS_CRTALLOC;
1747 ////////////////////////////////////////////////////////////////////////////////
1749 // Debug CRT and MFC IAT Replacement Functions
1751 // The addresses of these functions are not actually directly patched into the
1752 // import address tables, but these functions do get indirectly called by the
1753 // patch functions that are placed in the import address tables.
1755 ////////////////////////////////////////////////////////////////////////////////
1757 // __calloc_dbg - This function is just a wrapper around the real _calloc_dbg
1758 // that sets appropriate flags to be consulted when the memory is actually
1759 // allocated by RtlAllocateHeap.
1761 // - p_calloc_dbg: Pointer to the particular _calloc_dbg implementation to
1764 // - fp (IN): Frame pointer from the call that initiated this allocation.
1766 // - size (IN): The size, in bytes, of the memory block to be allocated.
1768 // - type (IN): The CRT "use type" of the block to be allocated.
1770 // - file (IN): The name of the file from which this function is being called.
1772 // - line (IN): The line number, in the above file, at which this function is
1777 // Returns the value returned by the specified _calloc_dbg.
1779 void* VisualLeakDetector::__calloc_dbg (_calloc_dbg_t p_calloc_dbg,
1788 tls_t *tls = vld.gettls();
1790 // _malloc_dbg is a CRT function and allocates from the CRT heap.
1791 tls->flags |= VLD_TLS_CRTALLOC;
1793 if (tls->addrfp == 0x0) {
1794 // This is the first call to enter VLD for the current allocation.
1795 // Record the current frame pointer.
1799 // Do the allocation. The block will be mapped by _RtlAllocateHeap.
1800 block = p_calloc_dbg(num, size, type, file, line);
1802 // Reset thread local flags and variables for the next allocation.
1804 tls->flags &= ~VLD_TLS_CRTALLOC;
1809 // __malloc_dbg - This function is just a wrapper around the real _malloc_dbg
1810 // that sets appropriate flags to be consulted when the memory is actually
1811 // allocated by RtlAllocateHeap.
1813 // - p_malloc_dbg (IN): Pointer to the particular _malloc_dbg implementation to
1816 // - fp (IN): Frame pointer from the call that initiated this allocation.
1818 // - size (IN): The size, in bytes, of the memory block to be allocated.
1820 // - type (IN): The CRT "use type" of the block to be allocated.
1822 // - file (IN): The name of the file from which this function is being called.
1824 // - line (IN): The line number, in the above file, at which this function is
1829 // Returns the value returned by the specified _malloc_dbg.
1831 void* VisualLeakDetector::__malloc_dbg (_malloc_dbg_t p_malloc_dbg,
1839 tls_t *tls = vld.gettls();
1841 // _malloc_dbg is a CRT function and allocates from the CRT heap.
1842 tls->flags |= VLD_TLS_CRTALLOC;
1844 if (tls->addrfp == 0x0) {
1845 // This is the first call to enter VLD for the current allocation.
1846 // Record the current frame pointer.
1850 // Do the allocation. The block will be mapped by _RtlAllocateHeap.
1851 block = p_malloc_dbg(size, type, file, line);
1853 // Reset thread local flags and variables for the next allocation.
1855 tls->flags &= ~VLD_TLS_CRTALLOC;
1860 // new_dbg_crt - This function is just a wrapper around the real CRT debug new
1861 // operators that sets appropriate flags to be consulted when the memory is
1862 // actually allocated by RtlAllocateHeap.
1864 // - pnew_dbg_crt (IN): Pointer to the particular CRT new operator
1865 // implementation to call.
1867 // - fp (IN): Frame pointer from the call that initiated this allocation.
1869 // - size (IN): The size, in bytes, of the memory block to be allocated.
1871 // - type (IN): The CRT "use type" of the block to be allocated.
1873 // - file (IN): The name of the file from which this function is being called.
1875 // - line (IN): The line number, in the above file, at which this function is
1880 // Returns the value returned by the specified CRT debug new operator.
1882 void* VisualLeakDetector::new_dbg_crt (new_dbg_crt_t pnew_dbg_crt,
1890 tls_t *tls = vld.gettls();
1892 // The debug new operator is a CRT function and allocates from the CRT heap.
1893 tls->flags |= VLD_TLS_CRTALLOC;
1895 if (tls->addrfp == 0x0) {
1896 // This is the first call to enter VLD for the current allocation.
1897 // Record the current frame pointer.
1901 // Do the allocation. The block will be mapped by _RtlAllocateHeap.
1902 block = pnew_dbg_crt(size, type, file, line);
1904 // Reset thread local flags and variables for the next allocation.
1906 tls->flags &= ~VLD_TLS_CRTALLOC;
1911 // new_dbg_mfc - This function is just a wrapper around the real MFC debug new
1912 // operators that sets appropriate flags to be consulted when the memory is
1913 // actually allocated by RtlAllocateHeap.
1915 // - pnew_dbg (IN): Pointer to the particular CRT new operator
1916 // implementation to call.
1918 // - fp (IN): Frame pointer from the call that initiated this allocation.
1920 // - size (IN): The size, in bytes, of the memory block to be allocated.
1922 // - type (IN): The CRT "use type" of the block to be allocated.
1924 // - file (IN): The name of the file from which this function is being called.
1926 // - line (IN): The line number, in the above file, at which this function is
1931 // Returns the value returned by the specified CRT debug new operator.
1933 void* VisualLeakDetector::new_dbg_mfc (new_dbg_crt_t pnew_dbg,
1941 tls_t *tls = vld.gettls();
1943 if (tls->addrfp == 0x0) {
1944 // This is the first call to enter VLD for the current allocation.
1945 // Record the current frame pointer.
1949 // Do the allocation. The block will be mapped by _RtlAllocateHeap.
1950 block = pnew_dbg(size, type, file, line);
1952 // Reset thread local flags and variables for the next allocation.
1954 tls->flags &= ~VLD_TLS_CRTALLOC;
1959 // new_dbg_mfc - This function is just a wrapper around the real MFC debug new
1960 // operators that sets appropriate flags to be consulted when the memory is
1961 // actually allocated by RtlAllocateHeap.
1963 // - pnew_dbg_mfc (IN): Pointer to the particular MFC new operator
1964 // implementation to call.
1966 // - fp (IN): Frame pointer of the call that initiated this allocation.
1968 // - size (IN): The size, in bytes, of the memory block to be allocated.
1970 // - file (IN): The name of the file from which this function is being called.
1972 // - line (IN): The line number, in the above file, at which this function is
1977 // Returns the value returned by the specified MFC debug new operator.
1979 void* VisualLeakDetector::new_dbg_mfc (new_dbg_mfc_t pnew_dbg_mfc,
1986 tls_t *tls = vld.gettls();
1988 if (tls->addrfp == 0x0) {
1989 // This is the first call to enter VLD for the current allocation.
1990 // Record the current frame pointer.
1994 // Do the allocation. The block will be mapped by _RtlAllocateHeap.
1995 block = pnew_dbg_mfc(size, file, line);
1997 // Reset thread local flags and variables for the next allocation.
1999 tls->flags &= ~VLD_TLS_CRTALLOC;
2004 // __realloc_debug - This function is just a wrapper around the real
2005 // _realloc_dbg that sets appropriate flags to be consulted when the memory is
2006 // actually allocated by RtlAllocateHeap.
2008 // - p_realloc_dbg (IN): Pointer to the particular __realloc_dbg implementation
2011 // - fp (IN): Frame pointer from the call that initiated this allocation.
2013 // - mem (IN): Pointer to the memory block to be reallocated.
2015 // - size (IN): The size of the memory block to reallocate.
2017 // - type (IN): The CRT "use type" of the block to be reallocated.
2019 // - file (IN): The name of the file from which this function is being called.
2021 // - line (IN): The line number, in the above file, at which this function is
2026 // Returns the value returned by the specified _realloc_dbg.
2028 void* VisualLeakDetector::__realloc_dbg (_realloc_dbg_t p_realloc_dbg,
2037 tls_t *tls = vld.gettls();
2039 // _realloc_dbg is a CRT function and allocates from the CRT heap.
2040 tls->flags |= VLD_TLS_CRTALLOC;
2042 if (tls->addrfp == 0x0) {
2043 // This is the first call to enter VLD for the current allocation.
2044 // Record the current frame pointer.
2048 // Do the allocation. The block will be mapped by _RtlReAllocateHeap.
2049 block = p_realloc_dbg(mem, size, type, file, line);
2051 // Reset thread local flags and variables for the next allocation.
2053 tls->flags &= ~VLD_TLS_CRTALLOC;
2058 ////////////////////////////////////////////////////////////////////////////////
2060 // Win32 IAT Replacement Functions
2062 ////////////////////////////////////////////////////////////////////////////////
2064 // _GetProcAddress - Calls to GetProcAddress are patched through to this
2065 // function. If the requested function is a function that has been patched
2066 // through to one of VLD's handlers, then the address of VLD's handler
2067 // function is returned instead of the real address. Otherwise, this
2068 // function is just a wrapper around the real GetProcAddress.
2070 // - module (IN): Handle (base address) of the module from which to retrieve
2071 // the address of an exported function.
2073 // - procname (IN): ANSI string containing the name of the exported function
2074 // whose address is to be retrieved.
2078 // Returns a pointer to the requested function, or VLD's replacement for
2079 // the function, if there is a replacement function.
2081 FARPROC VisualLeakDetector::_GetProcAddress (HMODULE module, LPCSTR procname)
2083 patchentry_t *entry;
2085 UINT tablesize = sizeof(vld.m_patchtable) / sizeof(patchentry_t);
2087 // See if there is an entry in the patch table that matches the requested
2089 for (index = 0; index < tablesize; index++) {
2090 entry = &vld.m_patchtable[index];
2091 if ((entry->modulebase == 0x0) || ((HMODULE)entry->modulebase != module)) {
2092 // This patch table entry is for a different module.
2096 // This patch table entry is for the specified module. If the requested
2097 // import's name matches the entry's import name (or ordinal), then
2098 // return the address of the replacement instead of the address of the
2100 if ((SIZE_T)entry->importname < (SIZE_T)vld.m_vldbase) {
2101 // This entry's import name is not a valid pointer to data in
2102 // vld.dll. It must be an ordinal value.
2103 if ((UINT)entry->importname == (UINT)procname) {
2104 return (FARPROC)entry->replacement;
2108 if (strcmp(entry->importname, procname) == 0) {
2109 return (FARPROC)entry->replacement;
2114 // The requested function is not a patched function. Just return the real
2115 // address of the requested function.
2116 return GetProcAddress(module, procname);
2119 // _HeapCreate - Calls to HeapCreate are patched through to this function. This
2120 // function is just a wrapper around the real HeapCreate that calls VLD's heap
2121 // creation tracking function after the heap has been created.
2123 // - options (IN): Heap options.
2125 // - initsize (IN): Initial size of the heap.
2127 // - maxsize (IN): Maximum size of the heap.
2131 // Returns the value returned by HeapCreate.
2133 HANDLE VisualLeakDetector::_HeapCreate (DWORD options, SIZE_T initsize, SIZE_T maxsize)
2135 DWORD64 displacement;
2137 SYMBOL_INFO *functioninfo;
2139 HeapMap::Iterator heapit;
2141 BYTE symbolbuffer [sizeof(SYMBOL_INFO) + (MAXSYMBOLNAMELENGTH * sizeof(WCHAR)) - 1] = { 0 };
2144 // Get the return address within the calling function.
2146 ra = *((SIZE_T*)fp + 1);
2149 heap = HeapCreate(options, initsize, maxsize);
2151 // Map the created heap handle to a new block map.
2154 // Try to get the name of the function containing the return address.
2155 functioninfo = (SYMBOL_INFO*)&symbolbuffer;
2156 functioninfo->SizeOfStruct = sizeof(SYMBOL_INFO);
2157 functioninfo->MaxNameLen = MAXSYMBOLNAMELENGTH;
2158 EnterCriticalSection(&symbollock);
2159 symfound = SymFromAddrW(currentprocess, ra, &displacement, functioninfo);
2160 LeaveCriticalSection(&symbollock);
2161 if (symfound == TRUE) {
2162 if (wcscmp(L"_heap_init", functioninfo->Name) == 0) {
2163 // HeapCreate was called by _heap_init. This is a static CRT heap.
2164 EnterCriticalSection(&vld.m_maplock);
2165 heapit = vld.m_heapmap->find(heap);
2166 assert(heapit != vld.m_heapmap->end());
2167 (*heapit).second->flags |= VLD_HEAP_CRT;
2168 LeaveCriticalSection(&vld.m_maplock);
2175 // _HeapDestroy - Calls to HeapDestroy are patched through to this function.
2176 // This function is just a wrapper around the real HeapDestroy that calls
2177 // VLD's heap destruction tracking function after the heap has been destroyed.
2179 // - heap (IN): Handle to the heap to be destroyed.
2183 // Returns the valued returned by HeapDestroy.
2185 BOOL VisualLeakDetector::_HeapDestroy (HANDLE heap)
2187 // After this heap is destroyed, the heap's address space will be unmapped
2188 // from the process's address space. So, we'd better generate a leak report
2189 // for this heap now, while we can still read from the memory blocks
2191 vld.reportleaks(heap);
2193 vld.unmapheap(heap);
2195 return HeapDestroy(heap);
2198 // _LdrLoadDll - Calls to LdrLoadDll are patched through to this function. This
2199 // function invokes the real LdrLoadDll and then re-attaches VLD to all
2200 // modules loaded in the process after loading of the new DLL is complete.
2201 // All modules must be re-enumerated because the explicit load of the
2202 // specified module may result in the implicit load of one or more additional
2203 // modules which are dependencies of the specified module.
2205 // - searchpath (IN): The path to use for searching for the specified module to
2208 // - flags (IN): Pointer to action flags.
2210 // - modulename (IN): Pointer to a unicodestring_t structure specifying the
2211 // name of the module to be loaded.
2213 // - modulehandle (OUT): Address of a HANDLE to receive the newly loaded
2218 // Returns the value returned by LdrLoadDll.
2220 NTSTATUS VisualLeakDetector::_LdrLoadDll (LPWSTR searchpath, PDWORD flags, unicodestring_t *modulename,
2221 PHANDLE modulehandle)
2223 ModuleSet::Iterator moduleit;
2224 ModuleSet *newmodules;
2225 ModuleSet *oldmodules;
2228 EnterCriticalSection(&vld.m_loaderlock);
2231 status = LdrLoadDll(searchpath, flags, modulename, modulehandle);
2233 if (STATUS_SUCCESS == status) {
2234 // Create a new set of all loaded modules, including any newly loaded
2236 newmodules = new ModuleSet;
2237 newmodules->reserve(MODULESETRESERVE);
2238 EnumerateLoadedModulesW64(currentprocess, addloadedmodule, newmodules);
2240 // Attach to all modules included in the set.
2241 vld.attachtoloadedmodules(newmodules);
2243 // Start using the new set of loaded modules.
2244 EnterCriticalSection(&vld.m_moduleslock);
2245 oldmodules = vld.m_loadedmodules;
2246 vld.m_loadedmodules = newmodules;
2247 LeaveCriticalSection(&vld.m_moduleslock);
2249 // Free resources used by the old module list.
2250 for (moduleit = oldmodules->begin(); moduleit != oldmodules->end(); ++moduleit) {
2251 delete (*moduleit).name;
2252 delete (*moduleit).path;
2257 LeaveCriticalSection(&vld.m_loaderlock);
2262 // _RtlAllocateHeap - Calls to RtlAllocateHeap are patched through to this
2263 // function. This function invokes the real RtlAllocateHeap and then calls
2264 // VLD's allocation tracking function. Pretty much all memory allocations
2265 // will eventually result in a call to RtlAllocateHeap, so this is where we
2266 // finally map the allocated block.
2268 // - heap (IN): Handle to the heap from which to allocate memory.
2270 // - flags (IN): Heap allocation control flags.
2272 // - size (IN): Size, in bytes, of the block to allocate.
2276 // Returns the return value from RtlAllocateHeap.
2278 LPVOID VisualLeakDetector::_RtlAllocateHeap (HANDLE heap, DWORD flags, SIZE_T size)
2281 BOOL excluded = FALSE;
2284 moduleinfo_t moduleinfo;
2285 ModuleSet::Iterator moduleit;
2286 SIZE_T returnaddress;
2287 tls_t *tls = vld.gettls();
2289 // Allocate the block.
2290 block = RtlAllocateHeap(heap, flags, size);
2291 if ((block != NULL) && vld.enabled()) {
2292 if (tls->addrfp == 0x0) {
2293 // This is the first call to enter VLD for the current allocation.
2294 // Record the current frame pointer.
2300 crtalloc = (tls->flags & VLD_TLS_CRTALLOC) ? TRUE : FALSE;
2302 // Reset thread local flags and variables, in case any libraries called
2303 // into while mapping the block allocate some memory.
2305 tls->flags &=~VLD_TLS_CRTALLOC;
2307 // Find the information for the module that initiated this allocation.
2308 returnaddress = *((SIZE_T*)fp + 1);
2309 moduleinfo.addrhigh = returnaddress;
2310 moduleinfo.addrlow = returnaddress;
2311 EnterCriticalSection(&vld.m_moduleslock);
2312 moduleit = vld.m_loadedmodules->find(moduleinfo);
2313 if (moduleit != vld.m_loadedmodules->end()) {
2314 excluded = (*moduleit).flags & VLD_MODULE_EXCLUDED ? TRUE : FALSE;
2316 LeaveCriticalSection(&vld.m_moduleslock);
2318 // The module that initiated this allocation is included in leak
2319 // detection. Map this block to the specified heap.
2320 vld.mapblock(heap, block, size, fp, crtalloc);
2324 // Reset thread local flags and variables for the next allocation.
2326 tls->flags &= ~VLD_TLS_CRTALLOC;
2331 // _RtlFreeHeap - Calls to RtlFreeHeap are patched through to this function.
2332 // This function calls VLD's free tracking function and then invokes the real
2333 // RtlFreeHeap. Pretty much all memory frees will eventually result in a call
2334 // to RtlFreeHeap, so this is where we finally unmap the freed block.
2336 // - heap (IN): Handle to the heap to which the block being freed belongs.
2338 // - flags (IN): Heap control flags.
2340 // - mem (IN): Pointer to the memory block being freed.
2344 // Returns the value returned by RtlFreeHeap.
2346 BOOL VisualLeakDetector::_RtlFreeHeap (HANDLE heap, DWORD flags, LPVOID mem)
2350 // Unmap the block from the specified heap.
2351 vld.unmapblock(heap, mem);
2353 status = RtlFreeHeap(heap, flags, mem);
2358 // _RtlReAllocateHeap - Calls to RtlReAllocateHeap are patched through to this
2359 // function. This function invokes the real RtlReAllocateHeap and then calls
2360 // VLD's reallocation tracking function. All arguments passed to this function
2361 // are passed on to the real RtlReAllocateHeap without modification. Pretty
2362 // much all memory re-allocations will eventually result in a call to
2363 // RtlReAllocateHeap, so this is where we finally remap the reallocated block.
2365 // - heap (IN): Handle to the heap to reallocate memory from.
2367 // - flags (IN): Heap control flags.
2369 // - mem (IN): Pointer to the currently allocated block which is to be
2372 // - size (IN): Size, in bytes, of the block to reallocate.
2376 // Returns the value returned by RtlReAllocateHeap.
2378 LPVOID VisualLeakDetector::_RtlReAllocateHeap (HANDLE heap, DWORD flags, LPVOID mem, SIZE_T size)
2381 BOOL excluded = FALSE;
2383 moduleinfo_t moduleinfo;
2384 ModuleSet::Iterator moduleit;
2386 SIZE_T returnaddress;
2387 tls_t *tls = vld.gettls();
2389 // Reallocate the block.
2390 newmem = RtlReAllocateHeap(heap, flags, mem, size);
2392 if (newmem != NULL) {
2393 if (tls->addrfp == 0x0) {
2394 // This is the first call to enter VLD for the current allocation.
2395 // Record the current frame pointer.
2401 crtalloc = (tls->flags & VLD_TLS_CRTALLOC) ? TRUE : FALSE;
2403 // Reset thread local flags and variables, in case any libraries called
2404 // into while remapping the block allocate some memory.
2406 tls->flags &= ~VLD_TLS_CRTALLOC;
2408 // Find the information for the module that initiated this reallocation.
2409 returnaddress = *((SIZE_T*)fp + 1);
2410 moduleinfo.addrhigh = returnaddress;
2411 moduleinfo.addrlow = returnaddress;
2412 EnterCriticalSection(&vld.m_moduleslock);
2413 moduleit = vld.m_loadedmodules->find(moduleinfo);
2414 if (moduleit != vld.m_loadedmodules->end()) {
2415 excluded = (*moduleit).flags & VLD_MODULE_EXCLUDED ? TRUE : FALSE;
2417 LeaveCriticalSection(&vld.m_moduleslock);
2419 // The module that initiated this allocation is included in leak
2420 // detection. Remap the block.
2421 vld.remapblock(heap, mem, newmem, size, fp, crtalloc);
2425 // Reset thread local flags and variables for the next allocation.
2427 tls->flags &= ~VLD_TLS_CRTALLOC;
2432 ////////////////////////////////////////////////////////////////////////////////
2434 // COM IAT Replacement Functions
2436 ////////////////////////////////////////////////////////////////////////////////
2438 // _CoGetMalloc - Calls to CoGetMalloc are patched through to this function.
2439 // This function returns a pointer to Visual Leak Detector's implementation
2440 // of the IMalloc interface, instead of returning a pointer to the system
2441 // implementation. This allows VLD's implementation of the IMalloc interface
2442 // (which is basically a thin wrapper around the system implementation) to be
2443 // invoked in place of the system implementation.
2445 // - context (IN): Reserved; value must be 1.
2447 // - imalloc (IN): Address of a pointer to receive the address of VLD's
2448 // implementation of the IMalloc interface.
2452 // Always returns S_OK.
2454 HRESULT VisualLeakDetector::_CoGetMalloc (DWORD context, LPMALLOC *imalloc)
2456 static CoGetMalloc_t pCoGetMalloc = NULL;
2460 *imalloc = (LPMALLOC)&vld;
2462 if (pCoGetMalloc == NULL) {
2463 // This is the first call to this function. Link to the real
2464 // CoGetMalloc and get a pointer to the system implementation of the
2465 // IMalloc interface.
2466 ole32 = GetModuleHandle(L"ole32.dll");
2467 pCoGetMalloc = (CoGetMalloc_t)GetProcAddress(ole32, "CoGetMalloc");
2468 pCoGetMalloc(context, &vld.m_imalloc);
2474 // _CoTaskMemAlloc - Calls to CoTaskMemAlloc are patched through to this
2475 // function. This function is just a wrapper around the real CoTaskMemAlloc
2476 // that sets appropriate flags to be consulted when the memory is actually
2477 // allocated by RtlAllocateHeap.
2479 // - size (IN): Size of the memory block to allocate.
2483 // Returns the value returned from CoTaskMemAlloc.
2485 LPVOID VisualLeakDetector::_CoTaskMemAlloc (ULONG size)
2487 static CoTaskMemAlloc_t pCoTaskMemAlloc = NULL;
2492 tls_t *tls = vld.gettls();
2494 if (tls->addrfp == 0x0) {
2495 // This is the first call to enter VLD for the current allocation.
2496 // Record the current frame pointer.
2501 if (pCoTaskMemAlloc == NULL) {
2502 // This is the first call to this function. Link to the real
2504 ole32 = GetModuleHandle(L"ole32.dll");
2505 pCoTaskMemAlloc = (CoTaskMemAlloc_t)GetProcAddress(ole32, "CoTaskMemAlloc");
2508 // Do the allocation. The block will be mapped by _RtlAllocateHeap.
2509 block = pCoTaskMemAlloc(size);
2511 // Reset thread local flags and variables for the next allocation.
2513 tls->flags &= ~VLD_TLS_CRTALLOC;
2518 // _CoTaskMemRealloc - Calls to CoTaskMemRealloc are patched through to this
2519 // function. This function is just a wrapper around the real CoTaskMemRealloc
2520 // that sets appropriate flags to be consulted when the memory is actually
2521 // allocated by RtlAllocateHeap.
2523 // - mem (IN): Pointer to the memory block to reallocate.
2525 // - size (IN): Size, in bytes, of the block to reallocate.
2529 // Returns the value returned from CoTaskMemRealloc.
2531 LPVOID VisualLeakDetector::_CoTaskMemRealloc (LPVOID mem, ULONG size)
2533 static CoTaskMemRealloc_t pCoTaskMemRealloc = NULL;
2538 tls_t *tls = vld.gettls();
2540 if (tls->addrfp == 0x0) {
2541 // This is the first call to enter VLD for the current allocation.
2542 // Record the current frame pointer.
2547 if (pCoTaskMemRealloc == NULL) {
2548 // This is the first call to this function. Link to the real
2549 // CoTaskMemRealloc.
2550 ole32 = GetModuleHandle(L"ole32.dll");
2551 pCoTaskMemRealloc = (CoTaskMemRealloc_t)GetProcAddress(ole32, "CoTaskMemRealloc");
2554 // Do the allocation. The block will be mapped by _RtlReAllocateHeap.
2555 block = pCoTaskMemRealloc(mem, size);
2557 // Reset thread local flags and variables for the next allocation.
2559 tls->flags &= ~VLD_TLS_CRTALLOC;
2564 ////////////////////////////////////////////////////////////////////////////////
2566 // Public COM IMalloc Implementation Functions
2568 ////////////////////////////////////////////////////////////////////////////////
2570 // AddRef - Calls to IMalloc::AddRef end up here. This function is just a
2571 // wrapper around the real IMalloc::AddRef implementation.
2575 // Returns the value returned by the system implementation of
2578 ULONG VisualLeakDetector::AddRef ()
2580 assert(m_imalloc != NULL);
2581 return m_imalloc->AddRef();
2584 // Alloc - Calls to IMalloc::Alloc end up here. This function is just a wrapper
2585 // around the real IMalloc::Alloc implementation that sets appropriate flags
2586 // to be consulted when the memory is actually allocated by RtlAllocateHeap.
2588 // - size (IN): The size of the memory block to allocate.
2592 // Returns the value returned by the system's IMalloc::Alloc implementation.
2594 LPVOID VisualLeakDetector::Alloc (ULONG size)
2598 tls_t *tls = vld.gettls();
2600 if (tls->addrfp == 0x0) {
2601 // This is the first call to enter VLD for the current allocation.
2602 // Record the current frame pointer.
2607 // Do the allocation. The block will be mapped by _RtlAllocateHeap.
2608 assert(m_imalloc != NULL);
2609 block = m_imalloc->Alloc(size);
2611 // Reset thread local flags and variables for the next allocation.
2613 tls->flags &= ~VLD_TLS_CRTALLOC;
2618 // DidAlloc - Calls to IMalloc::DidAlloc will end up here. This function is just
2619 // a wrapper around the system implementation of IMalloc::DidAlloc.
2621 // - mem (IN): Pointer to a memory block to inquire about.
2625 // Returns the value returned by the system implementation of
2626 // IMalloc::DidAlloc.
2628 INT VisualLeakDetector::DidAlloc (LPVOID mem)
2630 assert(m_imalloc != NULL);
2631 return m_imalloc->DidAlloc(mem);
2634 // Free - Calls to IMalloc::Free will end up here. This function is just a
2635 // wrapper around the real IMalloc::Free implementation.
2637 // - mem (IN): Pointer to the memory block to be freed.
2643 VOID VisualLeakDetector::Free (LPVOID mem)
2645 assert(m_imalloc != NULL);
2646 m_imalloc->Free(mem);
2649 // GetSize - Calls to IMalloc::GetSize will end up here. This function is just a
2650 // wrapper around the real IMalloc::GetSize implementation.
2652 // - mem (IN): Pointer to the memory block to inquire about.
2656 // Returns the value returned by the system implementation of
2657 // IMalloc::GetSize.
2659 ULONG VisualLeakDetector::GetSize (LPVOID mem)
2661 assert(m_imalloc != NULL);
2662 return m_imalloc->GetSize(mem);
2665 // HeapMinimize - Calls to IMalloc::HeapMinimize will end up here. This function
2666 // is just a wrapper around the real IMalloc::HeapMinimize implementation.
2672 VOID VisualLeakDetector::HeapMinimize ()
2674 assert(m_imalloc != NULL);
2675 m_imalloc->HeapMinimize();
2678 // QueryInterface - Calls to IMalloc::QueryInterface will end up here. This
2679 // function is just a wrapper around the real IMalloc::QueryInterface
2682 // - iid (IN): COM interface ID to query about.
2684 // - object (IN): Address of a pointer to receive the requested interface
2689 // Returns the value returned by the system implementation of
2690 // IMalloc::QueryInterface.
2692 HRESULT VisualLeakDetector::QueryInterface (REFIID iid, LPVOID *object)
2694 assert(m_imalloc != NULL);
2695 return m_imalloc->QueryInterface(iid, object);
2698 // Realloc - Calls to IMalloc::Realloc will end up here. This function is just a
2699 // wrapper around the real IMalloc::Realloc implementation that sets
2700 // appropriate flags to be consulted when the memory is actually allocated by
2703 // - mem (IN): Pointer to the memory block to reallocate.
2705 // - size (IN): Size, in bytes, of the memory block to reallocate.
2709 // Returns the value returned by the system implementation of
2710 // IMalloc::Realloc.
2712 LPVOID VisualLeakDetector::Realloc (LPVOID mem, ULONG size)
2716 tls_t *tls = vld.gettls();
2718 if (tls->addrfp == 0x0) {
2719 // This is the first call to enter VLD for the current allocation.
2720 // Record the current frame pointer.
2725 // Do the allocation. The block will be mapped by _RtlReAllocateHeap.
2726 assert(m_imalloc != NULL);
2727 block = m_imalloc->Realloc(mem, size);
2729 // Reset thread local flags and variables for the next allocation.
2731 tls->flags &= ~VLD_TLS_CRTALLOC;
2736 // Release - Calls to IMalloc::Release will end up here. This function is just
2737 // a wrapper around the real IMalloc::Release implementation.
2741 // Returns the value returned by the system implementation of
2742 // IMalloc::Release.
2744 ULONG VisualLeakDetector::Release ()
2746 assert(m_imalloc != NULL);
2747 return m_imalloc->Release();