-
Notifications
You must be signed in to change notification settings - Fork 402
/
vldint.h
292 lines (266 loc) · 16.6 KB
/
vldint.h
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
////////////////////////////////////////////////////////////////////////////////
//
// Visual Leak Detector - VisualLeakDetector Class Definition
// Copyright (c) 2005-2009 Dan Moulding
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
// See COPYING.txt for the full terms of the GNU Lesser General Public License.
//
////////////////////////////////////////////////////////////////////////////////
#pragma once
#ifndef VLDBUILD
#error \
"This header should only be included by Visual Leak Detector when building it from source. \
Applications should never include this header."
#endif
#include <cstdio>
#include <windows.h>
#include "callstack.h" // Provides a custom class for handling call stacks.
#include "map.h" // Provides a custom STL-like map template.
#include "ntapi.h" // Provides access to NT APIs.
#include "set.h" // Provides a custom STL-like set template.
#include "utility.h" // Provides miscellaneous utility functions.
#define MAXMODULELISTLENGTH 512 // Maximum module list length, in characters.
#define SELFTESTTEXTA "Memory Leak Self-Test"
#define SELFTESTTEXTW L"Memory Leak Self-Test"
#define VLDREGKEYPRODUCT L"Software\\Visual Leak Detector"
#define VLDVERSION L"1.9h"
// The Visual Leak Detector APIs.
extern "C" __declspec(dllexport) void VLDDisable ();
extern "C" __declspec(dllexport) void VLDEnable ();
// Function pointer types for explicit dynamic linking with functions listed in
// the import patch table.
typedef void* (__cdecl *_calloc_dbg_t) (size_t, size_t, int, const char*, int);
typedef void* (__cdecl *_malloc_dbg_t) (size_t, int, const char *, int);
typedef void* (__cdecl *_realloc_dbg_t) (void *, size_t, int, const char *, int);
typedef void* (__cdecl *calloc_t) (size_t, size_t);
typedef HRESULT (__stdcall *CoGetMalloc_t) (DWORD, LPMALLOC *);
typedef LPVOID (__stdcall *CoTaskMemAlloc_t) (ULONG);
typedef LPVOID (__stdcall *CoTaskMemRealloc_t) (LPVOID, ULONG);
typedef void* (__cdecl *malloc_t) (size_t);
typedef void* (__cdecl *new_t) (size_t);
typedef void* (__cdecl *new_dbg_crt_t) (size_t, int, const char *, int);
typedef void* (__cdecl *new_dbg_mfc_t) (size_t, const char *, int);
typedef void* (__cdecl *realloc_t) (void *, size_t);
// Data is collected for every block allocated from any heap in the process.
// The data is stored in this structure and these structures are stored in
// a BlockMap which maps each of these structures to its corresponding memory
// block.
typedef struct blockinfo_s {
CallStack *callstack;
SIZE_T serialnumber;
SIZE_T size;
} blockinfo_t;
// BlockMaps map memory blocks (via their addresses) to blockinfo_t structures.
typedef Map<LPCVOID, blockinfo_t*> BlockMap;
// Information about each heap in the process is kept in this map. Primarily
// this is used for mapping heaps to all of the blocks allocated from those
// heaps.
typedef struct heapinfo_s {
BlockMap blockmap; // Map of all blocks allocated from this heap.
UINT32 flags; // Heap status flags:
#define VLD_HEAP_CRT 0x1 // If set, this heap is a CRT heap (i.e. the CRT uses it for new/malloc).
} heapinfo_t;
// HeapMaps map heaps (via their handles) to BlockMaps.
typedef Map<HANDLE, heapinfo_t*> HeapMap;
// This structure stores information, primarily the virtual address range, about
// a given module and can be used with the Set template because it supports the
// '<' operator (sorts by virtual address range).
typedef struct moduleinfo_s {
BOOL operator < (const struct moduleinfo_s &other) const
{
if (addrhigh < other.addrlow) {
return TRUE;
}
else {
return FALSE;
}
}
SIZE_T addrhigh; // Highest address within the module's virtual address space (i.e. base + size).
SIZE_T addrlow; // Lowest address within the module's virtual address space (i.e. base address).
UINT32 flags; // Module flags:
#define VLD_MODULE_EXCLUDED 0x1 // If set, this module is excluded from leak detection.
#define VLD_MODULE_SYMBOLSLOADED 0x2 // If set, this module's debug symbols have been loaded.
LPCSTR name; // The module's name (e.g. "kernel32.dll").
LPCSTR path; // The fully qualified path from where the module was loaded.
} moduleinfo_t;
// ModuleSets store information about modules loaded in the process.
typedef Set<moduleinfo_t> ModuleSet;
// Thread local storage structure. Every thread in the process gets its own copy
// of this structure. Thread specific information, such as the current leak
// detection status (enabled or disabled) and the address that initiated the
// current allocation is stored here.
typedef struct tls_s {
SIZE_T addrfp; // Frame pointer at the first call that entered VLD's code for the current allocation.
UINT32 flags; // Thread-local status flags:
#define VLD_TLS_CRTALLOC 0x1 // If set, the current allocation is a CRT allocation.
#define VLD_TLS_DISABLED 0x2 // If set, memory leak detection is disabled for the current thread.
#define VLD_TLS_ENABLED 0x4 // If set, memory leak detection is enabled for the current thread.
DWORD threadid; // Thread ID of the thread that owns this TLS structure.
} tls_t;
// The TlsSet allows VLD to keep track of all thread local storage structures
// allocated in the process.
typedef Set<tls_t*> TlsSet;
////////////////////////////////////////////////////////////////////////////////
//
// The VisualLeakDetector Class
//
// One global instance of this class is instantiated. Upon construction it
// patches the import address table (IAT) of every other module loaded in the
// process (see the "patchimport" utility function) to allow key Windows heap
// APIs to be patched through to, or redirected to, functions provided by VLD.
// Patching the IATs in this manner allows VLD to be made aware of all
// relevant heap activity, making it possible for VLD to detect and trace
// memory leaks.
//
// The one global instance of this class is constructed within the context of
// the process' main thread during process initialization and is destroyed in
// the same context during process termination.
//
// When the VisualLeakDetector object is destroyed, it consults its internal
// datastructures, looking for any memory that has not been freed. A memory
// leak report is then generated, indicating any memory leaks that may have
// been identified.
//
// This class is derived from IMalloc so that it can provide an implementation
// of the IMalloc COM interface in order to support detection of COM-based
// memory leaks. However, this implementation of IMalloc is actually just a
// thin wrapper around the system's implementation of IMalloc.
//
class VisualLeakDetector : public IMalloc
{
public:
VisualLeakDetector();
~VisualLeakDetector();
////////////////////////////////////////////////////////////////////////////////
// Public CRT and MFC Common Handlers
//
// Many heap functions are indirectly rerouted to these handlers. One common
// function exists for each heap function with a given signature. These
// handlers are not direct IAT replacements, but are called by the individual
// IAT replacement functions.
////////////////////////////////////////////////////////////////////////////////
// Standard CRT and MFC common handlers
void* _calloc (calloc_t pcalloc, SIZE_T fp, size_t num, size_t size);
void* _malloc (malloc_t pmalloc, SIZE_T fp, size_t size);
void* _new (new_t pnew, SIZE_T fp, size_t size);
void* _realloc (realloc_t prealloc, SIZE_T fp, void *mem, size_t size);
// Debug CRT and MFC common handlers
void* __calloc_dbg (_calloc_dbg_t p_calloc_dbg, SIZE_T fp, size_t num, size_t size, int type, char const *file, int line);
void* __malloc_dbg (_malloc_dbg_t p_malloc_dbg, SIZE_T fp, size_t size, int type, char const *file, int line);
void* new_dbg_crt (new_dbg_crt_t pnew_dbg_crt, SIZE_T fp, size_t size, int type, char const *file, int line);
void* new_dbg_mfc (new_dbg_crt_t pnew_dbg, SIZE_T fp, size_t size, int type, char const *file, int line);
void* new_dbg_mfc (new_dbg_mfc_t pnew_dbg_mfc, SIZE_T fp, size_t size, char const *file, int line);
void* __realloc_dbg (_realloc_dbg_t p_realloc_dbg, SIZE_T fp, void *mem, size_t size, int type, char const *file, int line);
////////////////////////////////////////////////////////////////////////////////
// Public IMalloc methods - for support of COM-based memory leak detection.
////////////////////////////////////////////////////////////////////////////////
ULONG __stdcall AddRef ();
LPVOID __stdcall Alloc (ULONG size);
INT __stdcall DidAlloc (LPVOID mem);
VOID __stdcall Free (LPVOID mem);
ULONG __stdcall GetSize (LPVOID mem);
VOID __stdcall HeapMinimize ();
HRESULT __stdcall QueryInterface (REFIID iid, LPVOID *object);
LPVOID __stdcall Realloc (LPVOID mem, ULONG size);
ULONG __stdcall Release ();
private:
////////////////////////////////////////////////////////////////////////////////
// Private leak detection functions - see each function definition for details.
////////////////////////////////////////////////////////////////////////////////
VOID attachtoloadedmodules (ModuleSet *newmodules);
LPWSTR buildsymbolsearchpath ();
VOID configure ();
BOOL enabled ();
SIZE_T eraseduplicates (const BlockMap::Iterator &element);
tls_t* gettls ();
VOID mapblock (HANDLE heap, LPCVOID mem, SIZE_T size, SIZE_T framepointer, BOOL crtalloc);
VOID mapheap (HANDLE heap);
VOID remapblock (HANDLE heap, LPCVOID mem, LPCVOID newmem, SIZE_T size, SIZE_T framepointer, BOOL crtalloc);
VOID reportconfig ();
VOID reportleaks (HANDLE heap);
VOID unmapblock (HANDLE heap, LPCVOID mem);
VOID unmapheap (HANDLE heap);
// Static functions (callbacks)
static BOOL __stdcall addloadedmodule (PCWSTR modulepath, DWORD64 modulebase, ULONG modulesize, PVOID context);
static BOOL __stdcall detachfrommodule (PCWSTR modulepath, DWORD64 modulebase, ULONG modulesize, PVOID context);
////////////////////////////////////////////////////////////////////////////////
// IAT replacement functions - see each function definition for details.
//
// Because there are so many virtually identical CRT and MFC replacement
// functions, they are excluded from the class to reduce the amount of noise
// within this class's code. See crtmfcpatch.cpp for those functions.
////////////////////////////////////////////////////////////////////////////////
// Win32 IAT replacement functions
static FARPROC __stdcall _GetProcAddress (HMODULE module, LPCSTR procname);
static HANDLE __stdcall _HeapCreate (DWORD options, SIZE_T initsize, SIZE_T maxsize);
static BOOL __stdcall _HeapDestroy (HANDLE heap);
static NTSTATUS __stdcall _LdrLoadDll (LPWSTR searchpath, PDWORD flags, unicodestring_t *modulename,
PHANDLE modulehandle);
static LPVOID __stdcall _RtlAllocateHeap (HANDLE heap, DWORD flags, SIZE_T size);
static BOOL __stdcall _RtlFreeHeap (HANDLE heap, DWORD flags, LPVOID mem);
static LPVOID __stdcall _RtlReAllocateHeap (HANDLE heap, DWORD flags, LPVOID mem, SIZE_T size);
// COM IAT replacement functions
static HRESULT __stdcall _CoGetMalloc (DWORD context, LPMALLOC *imalloc);
static LPVOID __stdcall _CoTaskMemAlloc (ULONG size);
static LPVOID __stdcall _CoTaskMemRealloc (LPVOID mem, ULONG size);
////////////////////////////////////////////////////////////////////////////////
// Private data
////////////////////////////////////////////////////////////////////////////////
WCHAR m_forcedmodulelist [MAXMODULELISTLENGTH]; // List of modules to be forcefully included in leak detection.
HeapMap *m_heapmap; // Map of all active heaps in the process.
IMalloc *m_imalloc; // Pointer to the system implementation of IMalloc.
SIZE_T m_leaksfound; // Total number of leaks found.
ModuleSet *m_loadedmodules; // Contains information about all modules loaded in the process.
CRITICAL_SECTION m_loaderlock; // Serializes the attachment of newly loaded modules.
CRITICAL_SECTION m_maplock; // Serializes access to the heap and block maps.
SIZE_T m_maxdatadump; // Maximum number of user-data bytes to dump for each leaked block.
UINT32 m_maxtraceframes; // Maximum number of frames per stack trace for each leaked block.
CRITICAL_SECTION m_moduleslock; // Protects accesses to the "loaded modules" ModuleSet.
UINT32 m_options; // Configuration options:
#define VLD_OPT_AGGREGATE_DUPLICATES 0x1 // If set, aggregate duplicate leaks in the leak report.
#define VLD_OPT_MODULE_LIST_INCLUDE 0x2 // If set, modules in the module list are included, all others are excluded.
#define VLD_OPT_REPORT_TO_DEBUGGER 0x4 // If set, the memory leak report is sent to the debugger.
#define VLD_OPT_REPORT_TO_FILE 0x8 // If set, the memory leak report is sent to a file.
#define VLD_OPT_SAFE_STACK_WALK 0x10 // If set, the stack is walked using the "safe" method (StackWalk64).
#define VLD_OPT_SELF_TEST 0x20 // If set, peform a self-test to verify memory leak self-checking.
#define VLD_OPT_SLOW_DEBUGGER_DUMP 0x40 // If set, inserts a slight delay between sending output to the debugger.
#define VLD_OPT_START_DISABLED 0x80 // If set, memory leak detection will initially disabled.
#define VLD_OPT_TRACE_INTERNAL_FRAMES 0x100 // If set, include useless frames (e.g. internal to VLD) in call stacks.
#define VLD_OPT_UNICODE_REPORT 0x200 // If set, the leak report will be encoded UTF-16 instead of ASCII.
#define VLD_OPT_VLDOFF 0x400 // If set, VLD will be completely deactivated. It will not attach to any modules.
static patchentry_t m_patchtable []; // Table of imports patched for attaching VLD to other modules.
FILE *m_reportfile; // File where the memory leak report may be sent to.
WCHAR m_reportfilepath [MAX_PATH]; // Full path and name of file to send memory leak report to.
const char *m_selftestfile; // Filename where the memory leak self-test block is leaked.
int m_selftestline; // Line number where the memory leak self-test block is leaked.
UINT32 m_status; // Status flags:
#define VLD_STATUS_DBGHELPLINKED 0x1 // If set, the explicit dynamic link to the Debug Help Library succeeded.
#define VLD_STATUS_INSTALLED 0x2 // If set, VLD was successfully installed.
#define VLD_STATUS_NEVER_ENABLED 0x4 // If set, VLD started disabled, and has not yet been manually enabled.
#define VLD_STATUS_FORCE_REPORT_TO_FILE 0x8 // If set, the leak report is being forced to a file.
DWORD m_tlsindex; // Thread-local storage index.
CRITICAL_SECTION m_tlslock; // Protects accesses to the Set of TLS structures.
TlsSet *m_tlsset; // Set of all all thread-local storage structres for the process.
HMODULE m_vldbase; // Visual Leak Detector's own module handle (base address).
// The Visual Leak Detector APIs are our friends.
friend __declspec(dllexport) void VLDDisable ();
friend __declspec(dllexport) void VLDEnable ();
};
// Configuration option default values
#define VLD_DEFAULT_MAX_DATA_DUMP 256
#define VLD_DEFAULT_MAX_TRACE_FRAMES 64
#define VLD_DEFAULT_REPORT_FILE_NAME L".\\memory_leak_report.txt"