////////////////////////////////////////////////////////////////////////////////
//
//  Visual Leak Detector - VisualLeakDetector Class Implementation
//  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 comment(lib, "dbghelp.lib")

#include <cassert>
#include <cerrno>
#include <cstdio>
#include <sys/stat.h>
#include <windows.h>
#ifndef __out_xcount
#define __out_xcount(x) // Workaround for the specstrings.h bug in the Platform SDK.
#endif
#define DBGHELP_TRANSLATE_TCHAR
#include <dbghelp.h>     // Provides symbol handling services.
#define VLDBUILD         // Declares that we are building Visual Leak Detector.
#include "callstack.h"   // Provides a class for handling call stacks.
#include "crtmfcpatch.h" // Provides CRT and MFC patch functions.
#include "map.h"         // Provides a lightweight STL-like map template.
#include "ntapi.h"       // Provides access to NT APIs.
#include "set.h"         // Provides a lightweight STL-like set template.
#include "utility.h"     // Provides various utility functions.
#include "vldheap.h"     // Provides internal new and delete operators.
#include "vldint.h"      // Provides access to the Visual Leak Detector internals.

#define BLOCKMAPRESERVE     64  // This should strike a balance between memory use and a desire to minimize heap hits.
#define HEAPMAPRESERVE      2   // Usually there won't be more than a few heaps in the process, so this should be small.
#define MAXSYMBOLNAMELENGTH 256 // Maximum symbol name length that we will allow. Longer names will be truncated.
#define MODULESETRESERVE    16  // There are likely to be several modules loaded in the process.

// Imported global variables.
extern vldblockheader_t *vldblocklist;
extern HANDLE            vldheap;
extern CRITICAL_SECTION  vldheaplock;

// Global variables.
HANDLE           currentprocess; // Pseudo-handle for the current process.
HANDLE           currentthread;  // Pseudo-handle for the current thread.
CRITICAL_SECTION imagelock;      // Serializes calls to the Debug Help Library PE image access APIs.
HANDLE           processheap;    // Handle to the process's heap (COM allocations come from here).
CRITICAL_SECTION stackwalklock;  // Serializes calls to StackWalk64 from the Debug Help Library.
CRITICAL_SECTION symbollock;     // Serializes calls to the Debug Help Library symbols handling APIs.

// The one and only VisualLeakDetector object instance.
__declspec(dllexport) VisualLeakDetector vld;

// Global function pointers for explicit dynamic linking with functions listed
// in the import patch table. Using explicit dynamic linking minimizes VLD's
// footprint by loading only modules that are actually used. These pointers will
// be linked to the real functions the first time they are used.

// The import patch table: lists the heap-related API imports that VLD patches
// through to replacement functions provided by VLD. Having this table simply
// makes it more convenient to add additional IAT patches.
patchentry_t VisualLeakDetector::m_patchtable [] = {
    // Win32 heap APIs.
    "kernel32.dll", "GetProcAddress",     0x0, _GetProcAddress, // Not heap related, but can be used to obtain pointers to heap functions.
    "kernel32.dll", "HeapAlloc",          0x0, _RtlAllocateHeap,
    "kernel32.dll", "HeapCreate",         0x0, _HeapCreate,
    "kernel32.dll", "HeapDestroy",        0x0, _HeapDestroy,
    "kernel32.dll", "HeapFree",           0x0, _RtlFreeHeap,
    "kernel32.dll", "HeapReAlloc",        0x0, _RtlReAllocateHeap,

    // MFC new operators (exported by ordinal).
    // XXX why are the vector new operators missing for mfc42d.dll?
    "mfc42d.dll",   (LPCSTR)711,          0x0, VS60::mfcd_scalar_new,
    "mfc42d.dll",   (LPCSTR)712,          0x0, VS60::mfcd__scalar_new_dbg_4p,
    "mfc42d.dll",   (LPCSTR)714,          0x0, VS60::mfcd__scalar_new_dbg_3p,
    "mfc42ud.dll",  (LPCSTR)711,          0x0, VS60::mfcud_scalar_new,
    "mfc42ud.dll",  (LPCSTR)712,          0x0, VS60::mfcud__scalar_new_dbg_4p,
    "mfc42ud.dll",  (LPCSTR)714,          0x0, VS60::mfcud__scalar_new_dbg_3p,
    "mfc70d.dll",   (LPCSTR)257,          0x0, VS70::mfcd_vector_new,
    "mfc70d.dll",   (LPCSTR)258,          0x0, VS70::mfcd__vector_new_dbg_4p,
    "mfc70d.dll",   (LPCSTR)259,          0x0, VS70::mfcd__vector_new_dbg_3p,
    "mfc70d.dll",   (LPCSTR)832,          0x0, VS70::mfcd_scalar_new,
    "mfc70d.dll",   (LPCSTR)833,          0x0, VS70::mfcd__scalar_new_dbg_4p,
    "mfc70d.dll",   (LPCSTR)834,          0x0, VS70::mfcd__scalar_new_dbg_3p,
    "mfc70ud.dll",  (LPCSTR)258,          0x0, VS70::mfcud_vector_new,
    "mfc70ud.dll",  (LPCSTR)259,          0x0, VS70::mfcud__vector_new_dbg_4p,
    "mfc70ud.dll",  (LPCSTR)260,          0x0, VS70::mfcud__vector_new_dbg_3p,
    "mfc70ud.dll",  (LPCSTR)833,          0x0, VS70::mfcud_scalar_new,
    "mfc70ud.dll",  (LPCSTR)834,          0x0, VS70::mfcud__scalar_new_dbg_4p,
    "mfc70ud.dll",  (LPCSTR)835,          0x0, VS70::mfcud__scalar_new_dbg_3p,
    "mfc71d.dll",   (LPCSTR)267,          0x0, VS71::mfcd_vector_new,
    "mfc71d.dll",   (LPCSTR)268,          0x0, VS71::mfcd__vector_new_dbg_4p,
    "mfc71d.dll",   (LPCSTR)269,          0x0, VS71::mfcd__vector_new_dbg_3p,
    "mfc71d.dll",   (LPCSTR)893,          0x0, VS71::mfcd_scalar_new,
    "mfc71d.dll",   (LPCSTR)894,          0x0, VS71::mfcd__scalar_new_dbg_4p,
    "mfc71d.dll",   (LPCSTR)895,          0x0, VS71::mfcd__scalar_new_dbg_3p,
    "mfc71ud.dll",  (LPCSTR)267,          0x0, VS71::mfcud_vector_new,
    "mfc71ud.dll",  (LPCSTR)268,          0x0, VS71::mfcud__vector_new_dbg_4p,
    "mfc71ud.dll",  (LPCSTR)269,          0x0, VS71::mfcud__vector_new_dbg_3p,
    "mfc71ud.dll",  (LPCSTR)893,          0x0, VS71::mfcud_scalar_new,
    "mfc71ud.dll",  (LPCSTR)894,          0x0, VS71::mfcud__scalar_new_dbg_4p,
    "mfc71ud.dll",  (LPCSTR)895,          0x0, VS71::mfcud__scalar_new_dbg_3p,
    "mfc80d.dll",   (LPCSTR)267,          0x0, VS80::mfcd_vector_new,
    "mfc80d.dll",   (LPCSTR)268,          0x0, VS80::mfcd__vector_new_dbg_4p,
    "mfc80d.dll",   (LPCSTR)269,          0x0, VS80::mfcd__vector_new_dbg_3p,
    "mfc80d.dll",   (LPCSTR)893,          0x0, VS80::mfcd_scalar_new,
    "mfc80d.dll",   (LPCSTR)894,          0x0, VS80::mfcd__scalar_new_dbg_4p,
    "mfc80d.dll",   (LPCSTR)895,          0x0, VS80::mfcd__scalar_new_dbg_3p,
    "mfc80ud.dll",  (LPCSTR)267,          0x0, VS80::mfcud_vector_new,
    "mfc80ud.dll",  (LPCSTR)268,          0x0, VS80::mfcud__vector_new_dbg_4p,
    "mfc80ud.dll",  (LPCSTR)269,          0x0, VS80::mfcud__vector_new_dbg_3p,
    "mfc80ud.dll",  (LPCSTR)893,          0x0, VS80::mfcud_scalar_new,
    "mfc80ud.dll",  (LPCSTR)894,          0x0, VS80::mfcud__scalar_new_dbg_4p,
    "mfc80ud.dll",  (LPCSTR)895,          0x0, VS80::mfcud__scalar_new_dbg_3p,
    "mfc90d.dll",   (LPCSTR)267,          0x0, VS90::mfcd_vector_new,
    "mfc90d.dll",   (LPCSTR)268,          0x0, VS90::mfcd__vector_new_dbg_4p,
    "mfc90d.dll",   (LPCSTR)269,          0x0, VS90::mfcd__vector_new_dbg_3p,
    "mfc90d.dll",   (LPCSTR)931,          0x0, VS90::mfcd_scalar_new,
    "mfc90d.dll",   (LPCSTR)932,          0x0, VS90::mfcd__scalar_new_dbg_4p,
    "mfc90d.dll",   (LPCSTR)933,          0x0, VS90::mfcd__scalar_new_dbg_3p,
    "mfc90ud.dll",  (LPCSTR)267,          0x0, VS90::mfcud_vector_new,
    "mfc90ud.dll",  (LPCSTR)268,          0x0, VS90::mfcud__vector_new_dbg_4p,
    "mfc90ud.dll",  (LPCSTR)269,          0x0, VS90::mfcud__vector_new_dbg_3p,
    "mfc90ud.dll",  (LPCSTR)935,          0x0, VS90::mfcud_scalar_new,
    "mfc90ud.dll",  (LPCSTR)936,          0x0, VS90::mfcud__scalar_new_dbg_4p,
    "mfc90ud.dll",  (LPCSTR)937,          0x0, VS90::mfcud__scalar_new_dbg_3p,
    "mfc100d.dll",   (LPCSTR)267,          0x0, VS100::mfcd_vector_new,
    "mfc100d.dll",   (LPCSTR)268,          0x0, VS100::mfcd__vector_new_dbg_4p,
    "mfc100d.dll",   (LPCSTR)269,          0x0, VS100::mfcd__vector_new_dbg_3p,
    "mfc100d.dll",   (LPCSTR)1427,         0x0, VS100::mfcd_scalar_new,
    "mfc100d.dll",   (LPCSTR)1428,         0x0, VS100::mfcd__scalar_new_dbg_4p,
    "mfc100d.dll",   (LPCSTR)1429,         0x0, VS100::mfcd__scalar_new_dbg_3p,
    "mfc100ud.dll",  (LPCSTR)267,          0x0, VS100::mfcud_vector_new,
    "mfc100ud.dll",  (LPCSTR)268,          0x0, VS100::mfcud__vector_new_dbg_4p,
    "mfc100ud.dll",  (LPCSTR)269,          0x0, VS100::mfcud__vector_new_dbg_3p,
    "mfc100ud.dll",  (LPCSTR)1434,         0x0, VS100::mfcud_scalar_new,
    "mfc100ud.dll",  (LPCSTR)1435,         0x0, VS100::mfcud__scalar_new_dbg_4p,
    "mfc100ud.dll",  (LPCSTR)1436,         0x0, VS100::mfcud__scalar_new_dbg_3p,

    // CRT new operators and heap APIs.
    "msvcrtd.dll",  "_calloc_dbg",        0x0, VS60::crtd__calloc_dbg,
    "msvcrtd.dll",  "_malloc_dbg",        0x0, VS60::crtd__malloc_dbg,
    "msvcrtd.dll",  "_realloc_dbg",       0x0, VS60::crtd__realloc_dbg,
    "msvcrtd.dll",  "??2@YAPAXIHPBDH@Z",  0x0, VS60::crtd__scalar_new_dbg,
//  "msvcrtd.dll",  "??_U@YAPAXIHPBDH@Z", 0x0, VS60::crtd__vector_new_dbg,
    "msvcrtd.dll",  "calloc",             0x0, VS60::crtd_calloc,
    "msvcrtd.dll",  "malloc",             0x0, VS60::crtd_malloc,
    "msvcrtd.dll",  "realloc",            0x0, VS60::crtd_realloc,
    "msvcrtd.dll",  "??2@YAPAXI@Z",       0x0, VS60::crtd_scalar_new,
//  "msvcrtd.dll",  "??_U@YAPAXI@Z",      0x0, VS60::crtd_vector_new,
    "msvcr70d.dll", "_calloc_dbg",        0x0, VS70::crtd__calloc_dbg,
    "msvcr70d.dll", "_malloc_dbg",        0x0, VS70::crtd__malloc_dbg,
    "msvcr70d.dll", "_realloc_dbg",       0x0, VS70::crtd__realloc_dbg,
    "msvcr70d.dll", "??2@YAPAXIHPBDH@Z",  0x0, VS70::crtd__scalar_new_dbg,
    "msvcr70d.dll", "??_U@YAPAXIHPBDH@Z", 0x0, VS70::crtd__vector_new_dbg,
    "msvcr70d.dll", "calloc",             0x0, VS70::crtd_calloc,
    "msvcr70d.dll", "malloc",             0x0, VS70::crtd_malloc,
    "msvcr70d.dll", "realloc",            0x0, VS70::crtd_realloc,
    "msvcr70d.dll", "??2@YAPAXI@Z",       0x0, VS70::crtd_scalar_new,
    "msvcr70d.dll", "??_U@YAPAXI@Z",      0x0, VS70::crtd_vector_new,
    "msvcr71d.dll", "_calloc_dbg",        0x0, VS71::crtd__calloc_dbg,
    "msvcr71d.dll", "_malloc_dbg",        0x0, VS71::crtd__malloc_dbg,
    "msvcr71d.dll", "_realloc_dbg",       0x0, VS71::crtd__realloc_dbg,
    "msvcr71d.dll", "??2@YAPAXIHPBDH@Z",  0x0, VS71::crtd__scalar_new_dbg,
    "msvcr71d.dll", "??_U@YAPAXIHPBDH@Z", 0x0, VS71::crtd__vector_new_dbg,
    "msvcr71d.dll", "calloc",             0x0, VS71::crtd_calloc,
    "msvcr71d.dll", "malloc",             0x0, VS71::crtd_malloc,
    "msvcr71d.dll", "realloc",            0x0, VS71::crtd_realloc,
    "msvcr71d.dll", "??2@YAPAXI@Z",       0x0, VS71::crtd_scalar_new,
    "msvcr71d.dll", "??_U@YAPAXI@Z",      0x0, VS71::crtd_vector_new,
    "msvcr80d.dll", "_calloc_dbg",        0x0, VS80::crtd__calloc_dbg,
    "msvcr80d.dll", "_malloc_dbg",        0x0, VS80::crtd__malloc_dbg,
    "msvcr80d.dll", "_realloc_dbg",       0x0, VS80::crtd__realloc_dbg,
    "msvcr80d.dll", "??2@YAPAXIHPBDH@Z",  0x0, VS80::crtd__scalar_new_dbg,
    "msvcr80d.dll", "??_U@YAPAXIHPBDH@Z", 0x0, VS80::crtd__vector_new_dbg,
    "msvcr80d.dll", "calloc",             0x0, VS80::crtd_calloc,
    "msvcr80d.dll", "malloc",             0x0, VS80::crtd_malloc,
    "msvcr80d.dll", "realloc",            0x0, VS80::crtd_realloc,
    "msvcr80d.dll", "??2@YAPAXI@Z",       0x0, VS80::crtd_scalar_new,
    "msvcr80d.dll", "??_U@YAPAXI@Z",      0x0, VS80::crtd_vector_new,
    "msvcr90d.dll", "_calloc_dbg",        0x0, VS90::crtd__calloc_dbg,
    "msvcr90d.dll", "_malloc_dbg",        0x0, VS90::crtd__malloc_dbg,
    "msvcr90d.dll", "_realloc_dbg",       0x0, VS90::crtd__realloc_dbg,
    "msvcr90d.dll", "??2@YAPAXIHPBDH@Z",  0x0, VS90::crtd__scalar_new_dbg,
    "msvcr90d.dll", "??_U@YAPAXIHPBDH@Z", 0x0, VS90::crtd__vector_new_dbg,
    "msvcr90d.dll", "calloc",             0x0, VS90::crtd_calloc,
    "msvcr90d.dll", "malloc",             0x0, VS90::crtd_malloc,
    "msvcr90d.dll", "realloc",            0x0, VS90::crtd_realloc,
    "msvcr90d.dll", "??2@YAPAXI@Z",       0x0, VS90::crtd_scalar_new,
    "msvcr90d.dll", "??_U@YAPAXI@Z",      0x0, VS90::crtd_vector_new,
    "msvcr100d.dll", "_calloc_dbg",        0x0, VS100::crtd__calloc_dbg,
    "msvcr100d.dll", "_malloc_dbg",        0x0, VS100::crtd__malloc_dbg,
    "msvcr100d.dll", "_realloc_dbg",       0x0, VS100::crtd__realloc_dbg,
    "msvcr100d.dll", scalar_new_dbg_name,  0x0, VS100::crtd__scalar_new_dbg,
    "msvcr100d.dll", vector_new_dbg_name,  0x0, VS100::crtd__vector_new_dbg,
    "msvcr100d.dll", "calloc",             0x0, VS100::crtd_calloc,
    "msvcr100d.dll", "malloc",             0x0, VS100::crtd_malloc,
    "msvcr100d.dll", "realloc",            0x0, VS100::crtd_realloc,
    "msvcr100d.dll", scalar_new_name,      0x0, VS100::crtd_scalar_new,
    "msvcr100d.dll", vector_new_name,      0x0, VS100::crtd_vector_new,

    // NT APIs.
    "ntdll.dll",    "RtlAllocateHeap",    0x0, _RtlAllocateHeap,
    "ntdll.dll",    "RtlFreeHeap",        0x0, _RtlFreeHeap,
    "ntdll.dll",    "RtlReAllocateHeap",  0x0, _RtlReAllocateHeap,

    // COM heap APIs.
    "ole32.dll",    "CoGetMalloc",        0x0, _CoGetMalloc,
    "ole32.dll",    "CoTaskMemAlloc",     0x0, _CoTaskMemAlloc,
    "ole32.dll",    "CoTaskMemRealloc",   0x0, _CoTaskMemRealloc
};

// Constructor - Initializes private data, loads configuration options, and
//   attaches Visual Leak Detector to all other modules loaded into the current
//   process.
//
VisualLeakDetector::VisualLeakDetector ()
{
    WCHAR      bom = BOM; // Unicode byte-order mark.
    HMODULE    kernel32;
    ModuleSet *newmodules;
    HMODULE    ntdll;
    LPWSTR     symbolpath;

    // Initialize configuration options and related private data.
    _wcsnset_s(m_forcedmodulelist, MAXMODULELISTLENGTH, '\0', _TRUNCATE);
    m_maxdatadump    = 0xffffffff;
    m_maxtraceframes = 0xffffffff;
    m_options        = 0x0;
    m_reportfile     = NULL;
    wcsncpy_s(m_reportfilepath, MAX_PATH, VLD_DEFAULT_REPORT_FILE_NAME, _TRUNCATE);
    m_status         = 0x0;

    // Load configuration options.
    configure();
    if (m_options & VLD_OPT_VLDOFF) {
        report(L"Visual Leak Detector is turned off.\n");
        return;
    }

    kernel32 = GetModuleHandle(L"kernel32.dll");
    ntdll = GetModuleHandle(L"ntdll.dll");

    // Initialize global variables.
    currentprocess    = GetCurrentProcess();
    currentthread     = GetCurrentThread();
    InitializeCriticalSection(&imagelock);
    LdrLoadDll        = (LdrLoadDll_t)GetProcAddress(ntdll, "LdrLoadDll");
    processheap       = GetProcessHeap();
    RtlAllocateHeap   = (RtlAllocateHeap_t)GetProcAddress(ntdll, "RtlAllocateHeap");
    RtlFreeHeap       = (RtlFreeHeap_t)GetProcAddress(ntdll, "RtlFreeHeap");
    RtlReAllocateHeap = (RtlReAllocateHeap_t)GetProcAddress(ntdll, "RtlReAllocateHeap");
    InitializeCriticalSection(&stackwalklock);
    InitializeCriticalSection(&symbollock);
    vldheap           = HeapCreate(0x0, 0, 0);
    InitializeCriticalSection(&vldheaplock);

    // Initialize remaining private data.
    m_heapmap         = new HeapMap;
    m_heapmap->reserve(HEAPMAPRESERVE);
    m_imalloc         = NULL;
    m_leaksfound      = 0;
    m_loadedmodules   = NULL;
    InitializeCriticalSection(&m_loaderlock);
    InitializeCriticalSection(&m_maplock);
    InitializeCriticalSection(&m_moduleslock);
    m_selftestfile    = __FILE__;
    m_selftestline    = 0;
    m_tlsindex        = TlsAlloc();
    InitializeCriticalSection(&m_tlslock);
    m_tlsset          = new TlsSet;

    if (m_options & VLD_OPT_SELF_TEST) {
        // Self-test mode has been enabled. Intentionally leak a small amount of
        // memory so that memory leak self-checking can be verified.
        if (m_options & VLD_OPT_UNICODE_REPORT) {
            wcsncpy_s(new WCHAR [wcslen(SELFTESTTEXTW) + 1], wcslen(SELFTESTTEXTW) + 1, SELFTESTTEXTW, _TRUNCATE);
            m_selftestline = __LINE__ - 1;
        }
        else {
            strncpy_s(new CHAR [strlen(SELFTESTTEXTA) + 1], strlen(SELFTESTTEXTA) + 1, SELFTESTTEXTA, _TRUNCATE);
            m_selftestline = __LINE__ - 1;
        }
    }
    if (m_options & VLD_OPT_START_DISABLED) {
        // Memory leak detection will initially be disabled.
        m_status |= VLD_STATUS_NEVER_ENABLED;
    }
    if (m_options & VLD_OPT_REPORT_TO_FILE) {
        // Reporting to file enabled.
        if (m_options & VLD_OPT_UNICODE_REPORT) {
            // Unicode data encoding has been enabled. Write the byte-order
            // mark before anything else gets written to the file. Open the
            // file for binary writing.
            if (_wfopen_s(&m_reportfile, m_reportfilepath, L"wb") == EINVAL) {
                // Couldn't open the file.
                m_reportfile = NULL;
            }
            else {
                fwrite(&bom, sizeof(WCHAR), 1, m_reportfile);
                setreportencoding(unicode);
            }
        }
        else {
            // Open the file in text mode for ASCII output.
            if (_wfopen_s(&m_reportfile, m_reportfilepath, L"w") == EINVAL) {
                // Couldn't open the file.
                m_reportfile = NULL;
            }
            else {
                setreportencoding(ascii);
            }
        }
        if (m_reportfile == NULL) {
            report(L"WARNING: Visual Leak Detector: Couldn't open report file for writing: %s\n"
                   L"  The report will be sent to the debugger instead.\n", m_reportfilepath);
        }
        else {
            // Set the "report" function to write to the file.
            setreportfile(m_reportfile, m_options & VLD_OPT_REPORT_TO_DEBUGGER);
        }
    }
    if (m_options & VLD_OPT_SLOW_DEBUGGER_DUMP) {
        // Insert a slight delay between messages sent to the debugger for
        // output. (For working around a bug in VC6 where data sent to the
        // debugger gets lost if it's sent too fast).
        insertreportdelay();
    }

    // This is highly unlikely to happen, but just in case, check to be sure
    // we got a valid TLS index.
    if (m_tlsindex == TLS_OUT_OF_INDEXES) {
        report(L"ERROR: Visual Leak Detector could not be installed because thread local"
               L"  storage could not be allocated.");
        return;
    }

    // Initialize the symbol handler. We use it for obtaining source file/line
    // number information and function names for the memory leak report.
    symbolpath = buildsymbolsearchpath();
    SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME);
    if (!SymInitializeW(currentprocess, symbolpath, FALSE)) {
        report(L"WARNING: Visual Leak Detector: The symbol handler failed to initialize (error=%lu).\n"
               L"    File and function names will probably not be available in call stacks.\n", GetLastError());
    }
    delete [] symbolpath;

    // Patch into kernel32.dll's calls to LdrLoadDll so that VLD can
    // dynamically attach to new modules loaded during runtime.
    patchimport(kernel32, ntdll, "ntdll.dll", "LdrLoadDll", _LdrLoadDll);

    // Attach Visual Leak Detector to every module loaded in the process.
    newmodules = new ModuleSet;
    newmodules->reserve(MODULESETRESERVE);
    EnumerateLoadedModulesW64(currentprocess, addloadedmodule, newmodules);
    attachtoloadedmodules(newmodules);
    m_loadedmodules = newmodules;
    m_status |= VLD_STATUS_INSTALLED;

    report(L"Visual Leak Detector Version " VLDVERSION L" installed.\n");
    if (m_status & VLD_STATUS_FORCE_REPORT_TO_FILE) {
        // The report is being forced to a file. Let the human know why.
        report(L"NOTE: Visual Leak Detector: Unicode-encoded reporting has been enabled, but the\n"
               L"  debugger is the only selected report destination. The debugger cannot display\n"
               L"  Unicode characters, so the report will also be sent to a file. If no file has\n"
               L"  been specified, the default file name is \"" VLD_DEFAULT_REPORT_FILE_NAME L"\".\n");

    }
    reportconfig();
}

// Destructor - Detaches Visual Leak Detector from all modules loaded in the
//   process, frees internally allocated resources, and generates the memory
//   leak report.
//
VisualLeakDetector::~VisualLeakDetector ()
{
    BlockMap::Iterator   blockit;
    BlockMap            *blockmap;
    size_t               count;
    vldblockheader_t    *header;
    HANDLE               heap;
    HeapMap::Iterator    heapit;
    SIZE_T               internalleaks = 0;
    const char          *leakfile = NULL;
    WCHAR                leakfilew [MAX_PATH];
    int                  leakline = 0;
    ModuleSet::Iterator  moduleit;
    HANDLE               thread;
    BOOL                 threadsactive= FALSE;
    TlsSet::Iterator     tlsit;
    DWORD                dwCurProcessID;

    if (m_options & VLD_OPT_VLDOFF) {
        // VLD has been turned off.
        return;
    }

    if (m_status & VLD_STATUS_INSTALLED) {
        // Detach Visual Leak Detector from all previously attached modules.
        EnumerateLoadedModulesW64(currentprocess, detachfrommodule, NULL);

        dwCurProcessID = GetCurrentProcessId();

        // See if any threads that have ever entered VLD's code are still active.
        EnterCriticalSection(&m_tlslock);
        for (tlsit = m_tlsset->begin(); tlsit != m_tlsset->end(); ++tlsit) {
            if ((*tlsit)->threadid == GetCurrentThreadId()) {
                // Don't wait for the current thread to exit.
                continue;
            }

            thread = OpenThread(SYNCHRONIZE | THREAD_QUERY_INFORMATION, FALSE, (*tlsit)->threadid);
            if (thread == NULL) {
                // Couldn't query this thread. We'll assume that it exited.
                continue; // XXX should we check GetLastError()?
            }
            if (GetProcessIdOfThread(thread) != dwCurProcessID) {
                //The thread ID has been recycled.
                CloseHandle(thread);
                continue;
            }
            while (WaitForSingleObject(thread, 10000) == WAIT_TIMEOUT) { // 10 seconds
                // There is still at least one other thread running. The CRT
                // will stomp it dead when it cleans up, which is not a
                // graceful way for a thread to go down. Warn about this,
                // and wait until the thread has exited so that we know it
                // can't still be off running somewhere in VLD's code.
                // 
                // Since we've been waiting a while, let the human know we are
                // still here and alive.
                threadsactive = TRUE;
                report(L"Visual Leak Detector: Waiting for threads to terminate...\n");
            }
            CloseHandle(thread);
        }
        LeaveCriticalSection(&m_tlslock);

        if (m_status & VLD_STATUS_NEVER_ENABLED) {
            // Visual Leak Detector started with leak detection disabled and
            // it was never enabled at runtime. A lot of good that does.
            report(L"WARNING: Visual Leak Detector: Memory leak detection was never enabled.\n");
        }
        else {
            // Generate a memory leak report for each heap in the process.
            for (heapit = m_heapmap->begin(); heapit != m_heapmap->end(); ++heapit) {
                heap = (*heapit).first;
                reportleaks(heap);
            }

            // Show a summary.
            if (m_leaksfound == 0) {
                report(L"No memory leaks detected.\n");
            }
            else {
                report(L"Visual Leak Detector detected %lu memory leak", m_leaksfound);
                report((m_leaksfound > 1) ? L"s.\n" : L".\n");
            }
        }

        // Free resources used by the symbol handler.
        if (!SymCleanup(currentprocess)) {
            report(L"WARNING: Visual Leak Detector: The symbol handler failed to deallocate resources (error=%lu).\n",
                   GetLastError());
        }

        // Free internally allocated resources used by the heapmap and blockmap.
        for (heapit = m_heapmap->begin(); heapit != m_heapmap->end(); ++heapit) {
            blockmap = &(*heapit).second->blockmap;
            for (blockit = blockmap->begin(); blockit != blockmap->end(); ++blockit) {
                delete (*blockit).second->callstack;
                delete (*blockit).second;
            }
            delete blockmap;
        }
        delete m_heapmap;

        // Free internally allocated resources used by the loaded module set.
        for (moduleit = m_loadedmodules->begin(); moduleit != m_loadedmodules->end(); ++moduleit) {
            delete (*moduleit).name;
            delete (*moduleit).path;
        }
        delete m_loadedmodules;

        // Free internally allocated resources used for thread local storage.
        for (tlsit = m_tlsset->begin(); tlsit != m_tlsset->end(); ++tlsit) {
            delete *tlsit;
        }
        delete m_tlsset;

        // Do a memory leak self-check.
        header = vldblocklist;
        while (header) {
            // Doh! VLD still has an internally allocated block!
            // This won't ever actually happen, right guys?... guys?
            internalleaks++;
            leakfile = header->file;
            leakline = header->line;
            mbstowcs_s(&count, leakfilew, MAX_PATH, leakfile, _TRUNCATE);
            report(L"ERROR: Visual Leak Detector: Detected a memory leak internal to Visual Leak Detector!!\n");
            report(L"---------- Block %ld at " ADDRESSFORMAT L": %u bytes ----------\n", header->serialnumber,
                   VLDBLOCKDATA(header), header->size);
            report(L"  Call Stack:\n");
            report(L"    %s (%d): Full call stack not available.\n", leakfilew, leakline);
            if (m_maxdatadump != 0) {
                report(L"  Data:\n");
                if (m_options & VLD_OPT_UNICODE_REPORT) {
                    dumpmemoryw(VLDBLOCKDATA(header), (m_maxdatadump < header->size) ? m_maxdatadump : header->size);
                }
                else {
                    dumpmemorya(VLDBLOCKDATA(header), (m_maxdatadump < header->size) ? m_maxdatadump : header->size);
                }
            }
            report(L"\n");
            header = header->next;
        }
        if (m_options & VLD_OPT_SELF_TEST) {
            if ((internalleaks == 1) && (strcmp(leakfile, m_selftestfile) == 0) && (leakline == m_selftestline)) {
                report(L"Visual Leak Detector passed the memory leak self-test.\n");
            }
            else {
                report(L"ERROR: Visual Leak Detector: Failed the memory leak self-test.\n");
            }
        }

        if (threadsactive == TRUE) {
            report(L"WARNING: Visual Leak Detector: Some threads appear to have not terminated normally.\n"
                L"  This could cause inaccurate leak detection results, including false positives.\n");
        }
        report(L"Visual Leak Detector is now exiting.\n");
    }
    else {
        // VLD failed to load properly.
        delete m_heapmap;
        delete m_tlsset;
    }
    HeapDestroy(vldheap);

    DeleteCriticalSection(&imagelock);
    DeleteCriticalSection(&m_loaderlock);
    DeleteCriticalSection(&m_maplock);
    DeleteCriticalSection(&m_moduleslock);
    DeleteCriticalSection(&stackwalklock);
    DeleteCriticalSection(&symbollock);
    DeleteCriticalSection(&vldheaplock);

    if (m_tlsindex != TLS_OUT_OF_INDEXES) {
        TlsFree(m_tlsindex);
    }

    if (m_reportfile != NULL) {
        fclose(m_reportfile);
    }
}


////////////////////////////////////////////////////////////////////////////////
//
// Private Leak Detection Functions
//
////////////////////////////////////////////////////////////////////////////////

// attachtoloadedmodules - Attaches VLD to all modules contained in the provided
//   ModuleSet. Not all modules are in the ModuleSet will actually be included
//   in leak detection. Only modules that import the global VisualLeakDetector
//   class object, or those that are otherwise explicitly included in leak
//   detection, will be checked for memory leaks.
//
//   When VLD attaches to a module, it means that any of the imports listed in
//   the import patch table which are imported by the module, will be redirected
//   to VLD's designated replacements.
//
//  - newmodules (IN): Pointer to a ModuleSet containing information about any
//      loaded modules that need to be attached.
//
//  Return Value:
//
//    None.
//
VOID VisualLeakDetector::attachtoloadedmodules (ModuleSet *newmodules)
{
    size_t                count;
    DWORD64               modulebase;
    UINT32                moduleflags;
    IMAGEHLP_MODULE64     moduleimageinfo;
    LPCSTR                modulename;
#define MAXMODULENAME (_MAX_FNAME + _MAX_EXT)
    WCHAR                 modulenamew [MAXMODULENAME];
    LPCSTR                modulepath;
    DWORD                 modulesize;
    ModuleSet::Iterator   newit;
    ModuleSet::Iterator   oldit;
    ModuleSet            *oldmodules;
    BOOL                  refresh;
    UINT                  tablesize = sizeof(m_patchtable) / sizeof(patchentry_t);
    ModuleSet::Muterator  updateit;

    // Iterate through the supplied set, until all modules have been attached.
    for (newit = newmodules->begin(); newit != newmodules->end(); ++newit) {
        modulebase  = (DWORD64)(*newit).addrlow;
        moduleflags = 0x0;
        modulename  = (*newit).name;
        modulepath  = (*newit).path;
        modulesize  = (DWORD)((*newit).addrhigh - (*newit).addrlow) + 1;

        refresh = FALSE;
        EnterCriticalSection(&m_moduleslock);
        oldmodules = m_loadedmodules;
        if (oldmodules != NULL) {
            // This is not the first time we have been called to attach to the
            // currently loaded modules.
            oldit = oldmodules->find(*newit);
            if (oldit != oldmodules->end()) {
                // We've seen this "new" module loaded in the process before.
                moduleflags = (*oldit).flags;
                LeaveCriticalSection(&m_moduleslock);
                if (moduleispatched((HMODULE)modulebase, m_patchtable, tablesize)) {
                    // This module is already attached. Just update the module's
                    // flags, nothing more.
                    updateit = newit;
                    (*updateit).flags = moduleflags;
                    continue;
                }
                else {
                    // This module may have been attached before and has been
                    // detached. We'll need to try reattaching to it in case it
                    // was unloaded and then subsequently reloaded.
                    refresh = TRUE;
                }
            }
            else {
                LeaveCriticalSection(&m_moduleslock);
            }
        }
        else {
            LeaveCriticalSection(&m_moduleslock);
        }

        EnterCriticalSection(&symbollock);
        if ((refresh == TRUE) && (moduleflags & VLD_MODULE_SYMBOLSLOADED)) {
            // Discard the previously loaded symbols, so we can refresh them.
            if (SymUnloadModule64(currentprocess, modulebase) == FALSE) {
                report(L"WARNING: Visual Leak Detector: Failed to unload the symbols for %s. Function names and line"
                       L" numbers shown in the memory leak report for %s may be inaccurate.", modulename, modulename);
            }
        }

        // Try to load the module's symbols. This ensures that we have loaded
        // the symbols for every module that has ever been loaded into the
        // process, guaranteeing the symbols' availability when generating the
        // leak report.
        moduleimageinfo.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
        if ((SymGetModuleInfoW64(currentprocess, (DWORD64)modulebase, &moduleimageinfo) == TRUE) ||
            ((SymLoadModule64(currentprocess, NULL, modulepath, NULL, modulebase, modulesize) == modulebase) &&
            (SymGetModuleInfoW64(currentprocess, modulebase, &moduleimageinfo) == TRUE))) {
            moduleflags |= VLD_MODULE_SYMBOLSLOADED;
        }
        LeaveCriticalSection(&symbollock);

        if (_stricmp("vld.dll", modulename) == 0) {
            // What happens when a module goes through it's own portal? Bad things.
            // Like infinite recursion. And ugly bald men wearing dresses. VLD
            // should not, therefore, attach to itself.
            continue;
        }

        mbstowcs_s(&count, modulenamew, MAXMODULENAME, modulename, _TRUNCATE);
        if ((findimport((HMODULE)modulebase, m_vldbase, "vld.dll", "?vld@@3VVisualLeakDetector@@A") == FALSE) &&
            (wcsstr(vld.m_forcedmodulelist, modulenamew) == NULL)) {
            // This module does not import VLD. This means that none of the module's
            // sources #included vld.h. Exclude this module from leak detection.
            moduleflags |= VLD_MODULE_EXCLUDED;
        }
        else if (!(moduleflags & VLD_MODULE_SYMBOLSLOADED) || (moduleimageinfo.SymType == SymExport)) {
            // This module is going to be included in leak detection, but complete
            // symbols for this module couldn't be loaded. This means that any stack
            // traces through this module may lack information, like line numbers
            // and function names.
            report(L"WARNING: Visual Leak Detector: A module, %s, included in memory leak detection\n"
                   L"  does not have any debugging symbols available, or they could not be located.\n"
                   L"  Function names and/or line numbers for this module may not be available.\n", modulename);
        }

        // Update the module's flags in the "new modules" set.
        updateit = newit;
        (*updateit).flags = moduleflags;

        // Attach to the module.
        patchmodule((HMODULE)modulebase, m_patchtable, tablesize);
    }
}

// buildsymbolsearchpath - Builds the symbol search path for the symbol handler.
//   This helps the symbol handler find the symbols for the application being
//   debugged.
//
//  Return Value:
//
//    Returns a string containing the search path. The caller is responsible for
//    freeing the string.
//
LPWSTR VisualLeakDetector::buildsymbolsearchpath ()
{
    WCHAR   directory [_MAX_DIR];
    WCHAR   drive [_MAX_DRIVE];
    LPWSTR  env;
    DWORD   envlen;
    SIZE_T  index;
    SIZE_T  length;
    HMODULE module;
    LPWSTR  path = new WCHAR [MAX_PATH];
    SIZE_T  pos = 0;
    WCHAR   system [MAX_PATH];
    WCHAR   windows [MAX_PATH];

    // Oddly, the symbol handler ignores the link to the PDB embedded in the
    // executable image. So, we'll manually add the location of the executable
    // to the search path since that is often where the PDB will be located.
    path[0] = L'\0';
    module = GetModuleHandle(NULL);
    GetModuleFileName(module, path, MAX_PATH);
    _wsplitpath_s(path, drive, _MAX_DRIVE, directory, _MAX_DIR, NULL, 0, NULL, 0);
    wcsncpy_s(path, MAX_PATH, drive, _TRUNCATE);
    strapp(&path, directory);

    // When the symbol handler is given a custom symbol search path, it will no
    // longer search the default directories (working directory, system root,
    // etc). But we'd like it to still search those directories, so we'll add
    // them to our custom search path.
    //
    // Append the working directory.
    strapp(&path, L";.\\");

    // Append the Windows directory.
    if (GetWindowsDirectory(windows, MAX_PATH) != 0) {
        strapp(&path, L";");
        strapp(&path, windows);
    }

    // Append the system directory.
    if (GetSystemDirectory(system, MAX_PATH) != 0) {
        strapp(&path, L";");
        strapp(&path, system);
    }

    // Append %_NT_SYMBOL_PATH%.
    envlen = GetEnvironmentVariable(L"_NT_SYMBOL_PATH", NULL, 0);
    if (envlen != 0) {
        env = new WCHAR [envlen];
        if (GetEnvironmentVariable(L"_NT_SYMBOL_PATH", env, envlen) != 0) {
            strapp(&path, L";");
            strapp(&path, env);
        }
        delete [] env;
    }

    //  Append %_NT_ALT_SYMBOL_PATH%.
    envlen = GetEnvironmentVariable(L"_NT_ALT_SYMBOL_PATH", NULL, 0);
    if (envlen != 0) {
        env = new WCHAR [envlen];
        if (GetEnvironmentVariable(L"_NT_ALT_SYMBOL_PATH", env, envlen) != 0) {
            strapp(&path, L";");
            strapp(&path, env);
        }
        delete [] env;
    }

    // Remove any quotes from the path. The symbol handler doesn't like them.
    pos = 0;
    length = wcslen(path);
    while (pos < length) {
        if (path[pos] == L'\"') {
            for (index = pos; index < length; index++) {
                path[index] = path[index + 1];
            }
        }
        pos++;
    }

    return path;
}

// configure - Configures VLD using values read from the vld.ini file.
//
//  Return Value:
//
//    None.
//
VOID VisualLeakDetector::configure ()
{
#define BSIZE 64
    WCHAR        buffer [BSIZE];
    WCHAR        filename [MAX_PATH];
    WCHAR        inipath [MAX_PATH];
    BOOL         keyopen = FALSE;
    DWORD        length;
    HKEY         productkey;
    LONG         regstatus;
    struct _stat s;
    DWORD        valuetype;

    if (_wstat(L".\\vld.ini", &s) == 0) {
        // Found a copy of vld.ini in the working directory. Use it.
        wcsncpy_s(inipath, MAX_PATH, L".\\vld.ini", _TRUNCATE);
    }
    else {
        // Get the location of the vld.ini file from the registry.
        regstatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, VLDREGKEYPRODUCT, 0, KEY_QUERY_VALUE, &productkey);
        if (regstatus == ERROR_SUCCESS) {
            keyopen = TRUE;
            regstatus = RegQueryValueEx(productkey, L"IniFile", NULL, &valuetype, (LPBYTE)&inipath, &length);
        }
        if (keyopen) {
            RegCloseKey(productkey);
        }
        if ((regstatus != ERROR_SUCCESS) || (_wstat(inipath, &s) != 0)) {
            // The location of vld.ini could not be read from the registry. As a
            // last resort, look in the Windows directory.
            wcsncpy_s(inipath, MAX_PATH, L"vld.ini", _TRUNCATE);
        }
    }

    // Read the boolean options.
    GetPrivateProfileString(L"Options", L"VLD", L"on", buffer, BSIZE, inipath);
    if (strtobool(buffer) == FALSE) {
        m_options |= VLD_OPT_VLDOFF;
        return;
    }

    GetPrivateProfileString(L"Options", L"AggregateDuplicates", L"", buffer, BSIZE, inipath);
    if (strtobool(buffer) == TRUE) {
        m_options |= VLD_OPT_AGGREGATE_DUPLICATES;
    }

    GetPrivateProfileString(L"Options", L"SelfTest", L"", buffer, BSIZE, inipath);
    if (strtobool(buffer) == TRUE) {
        m_options |= VLD_OPT_SELF_TEST;
    }

    GetPrivateProfileString(L"Options", L"SlowDebuggerDump", L"", buffer, BSIZE, inipath);
    if (strtobool(buffer) == TRUE) {
        m_options |= VLD_OPT_SLOW_DEBUGGER_DUMP;
    }

    GetPrivateProfileString(L"Options", L"StartDisabled", L"", buffer, BSIZE, inipath);
    if (strtobool(buffer) == TRUE) {
        m_options |= VLD_OPT_START_DISABLED;
    }

    GetPrivateProfileString(L"Options", L"TraceInternalFrames", L"", buffer, BSIZE, inipath);
    if (strtobool(buffer) == TRUE) {
        m_options |= VLD_OPT_TRACE_INTERNAL_FRAMES;
    }

    // Read the integer configuration options.
    m_maxdatadump = GetPrivateProfileInt(L"Options", L"MaxDataDump", VLD_DEFAULT_MAX_DATA_DUMP, inipath);
    m_maxtraceframes = GetPrivateProfileInt(L"Options", L"MaxTraceFrames", VLD_DEFAULT_MAX_TRACE_FRAMES, inipath);
    if (m_maxtraceframes < 1) {
        m_maxtraceframes = VLD_DEFAULT_MAX_TRACE_FRAMES;
    }

    // Read the force-include module list.
    GetPrivateProfileString(L"Options", L"ForceIncludeModules", L"", m_forcedmodulelist, MAXMODULELISTLENGTH, inipath);
    _wcslwr_s(m_forcedmodulelist, MAXMODULELISTLENGTH);

    // Read the report destination (debugger, file, or both).
    GetPrivateProfileString(L"Options", L"ReportFile", L"", filename, MAX_PATH, inipath);
    if (wcslen(filename) == 0) {
        wcsncpy_s(filename, MAX_PATH, VLD_DEFAULT_REPORT_FILE_NAME, _TRUNCATE);
    }
    _wfullpath(m_reportfilepath, filename, MAX_PATH);
    GetPrivateProfileString(L"Options", L"ReportTo", L"", buffer, BSIZE, inipath);
    if (_wcsicmp(buffer, L"both") == 0) {
        m_options |= (VLD_OPT_REPORT_TO_DEBUGGER | VLD_OPT_REPORT_TO_FILE);
    }
    else if (_wcsicmp(buffer, L"file") == 0) {
        m_options |= VLD_OPT_REPORT_TO_FILE;
    }
    else {
        m_options |= VLD_OPT_REPORT_TO_DEBUGGER;
    }

    // Read the report file encoding (ascii or unicode).
    GetPrivateProfileString(L"Options", L"ReportEncoding", L"", buffer, BSIZE, inipath);
    if (_wcsicmp(buffer, L"unicode") == 0) {
        m_options |= VLD_OPT_UNICODE_REPORT;
    }
    if ((m_options & VLD_OPT_UNICODE_REPORT) && !(m_options & VLD_OPT_REPORT_TO_FILE)) {
        // If Unicode report encoding is enabled, then the report needs to be
        // sent to a file because the debugger will not display Unicode
        // characters, it will display question marks in their place instead.
        m_options |= VLD_OPT_REPORT_TO_FILE;
        m_status |= VLD_STATUS_FORCE_REPORT_TO_FILE;
    }

    // Read the stack walking method.
    GetPrivateProfileString(L"Options", L"StackWalkMethod", L"", buffer, BSIZE, inipath);
    if (_wcsicmp(buffer, L"safe") == 0) {
        m_options |= VLD_OPT_SAFE_STACK_WALK;
    }
}

// enabled - Determines if memory leak detection is enabled for the current
//   thread.
//
//  Return Value:
//
//    Returns true if Visual Leak Detector is enabled for the current thread.
//    Otherwise, returns false.
//
BOOL VisualLeakDetector::enabled ()
{
    tls_t *tls = vld.gettls();

    if (!(m_status & VLD_STATUS_INSTALLED)) {
        // Memory leak detection is not yet enabled because VLD is still
        // initializing.
        return FALSE;
    }

    if (!(tls->flags & VLD_TLS_DISABLED) && !(tls->flags & VLD_TLS_ENABLED)) {
        // The enabled/disabled state for the current thread has not been 
        // initialized yet. Use the default state.
        if (m_options & VLD_OPT_START_DISABLED) {
            tls->flags |= VLD_TLS_DISABLED;
        }
        else {
            tls->flags |= VLD_TLS_ENABLED;
        }
    }

    return ((tls->flags & VLD_TLS_ENABLED) != 0);
}

// eraseduplicates - Erases, from the block maps, blocks that appear to be
//   duplicate leaks of an already identified leak.
//
//  - element (IN): BlockMap Iterator referencing the block of which to search
//      for duplicates.
//
//  Return Value:
//
//    Returns the number of duplicate blocks erased from the block map.
//
SIZE_T VisualLeakDetector::eraseduplicates (const BlockMap::Iterator &element)
{
    BlockMap::Iterator  blockit;
    BlockMap           *blockmap;
    blockinfo_t        *elementinfo;
    SIZE_T              erased = 0;
    HeapMap::Iterator   heapit;
    blockinfo_t        *info;
    BlockMap::Iterator  previt;

    elementinfo = (*element).second;

    // Iteratate through all block maps, looking for blocks with the same size
    // and callstack as the specified element.
    for (heapit = m_heapmap->begin(); heapit != m_heapmap->end(); ++heapit) {
        blockmap = &(*heapit).second->blockmap;
        for (blockit = blockmap->begin(); blockit != blockmap->end(); ++blockit) {
            if (blockit == element) {
                // Don't delete the element of which we are searching for
                // duplicates.
                continue;
            }
            info = (*blockit).second;
            if ((info->size == elementinfo->size) && (*(info->callstack) == *(elementinfo->callstack))) {
                // Found a duplicate. Erase it.
                delete info->callstack;
                delete info;
                previt = blockit - 1;
                blockmap->erase(blockit);
                blockit = previt;
                erased++;
            }
        }
    }

    return erased;
}

// gettls - Obtains the thread local storage structure for the calling thread.
//
//  Return Value:
//
//    Returns a pointer to the thread local storage structure. (This function
//    always succeeds).
//
tls_t* VisualLeakDetector::gettls ()
{
    tls_t *tls;
    
    // Get the pointer to this thread's thread local storage structure.
    tls = (tls_t*)TlsGetValue(m_tlsindex);
    assert(GetLastError() == ERROR_SUCCESS);

    if (tls == NULL) {
        // This thread's thread local storage structure has not been allocated.
        tls = new tls_t;
        TlsSetValue(m_tlsindex, tls);
        tls->addrfp = 0x0;
        tls->flags = 0x0;
        tls->threadid = GetCurrentThreadId();

        // Add this thread's TLS to the TlsSet.
        EnterCriticalSection(&m_tlslock);
        m_tlsset->insert(tls);
        LeaveCriticalSection(&m_tlslock);
    }

    return tls;
}

// mapblock - Tracks memory allocations. Information about allocated blocks is
//   collected and then the block is mapped to this information.
//
//  - heap (IN): Handle to the heap from which the block has been allocated.
//
//  - mem (IN): Pointer to the memory block being allocated.
//
//  - size (IN): Size, in bytes, of the memory block being allocated.
//
//  - framepointer (IN): Framepointer at the time this allocation first entered
//      VLD's code. This is used from determining the starting point for the
//      stack trace.
//
//  - crtalloc (IN): Should be set to TRUE if this allocation is a CRT memory
//      block. Otherwise should be FALSE.
//
//  Return Value:
//
//    None.
//
VOID VisualLeakDetector::mapblock (HANDLE heap, LPCVOID mem, SIZE_T size, SIZE_T framepointer, BOOL crtalloc)
{
    blockinfo_t        *blockinfo;
    BlockMap::Iterator  blockit;
    BlockMap           *blockmap;
    HeapMap::Iterator   heapit;
    static SIZE_T       serialnumber = 0;

    // Record the block's information.
    blockinfo = new blockinfo_t;
    if (m_options & VLD_OPT_SAFE_STACK_WALK) {
        blockinfo->callstack = new SafeCallStack;
    }
    else {
        blockinfo->callstack = new FastCallStack;
    }
    if (m_options & VLD_OPT_TRACE_INTERNAL_FRAMES) {
        // Passing NULL for the frame pointer argument will force the stack
        // trace to begin at the current frame.
        blockinfo->callstack->getstacktrace(m_maxtraceframes, NULL);
    }
    else {
        // Start the stack trace at the call that first entered VLD's code.
        blockinfo->callstack->getstacktrace(m_maxtraceframes, (SIZE_T*)framepointer);
    }
    blockinfo->serialnumber = serialnumber++;
    blockinfo->size = size;

    // Insert the block's information into the block map.
    EnterCriticalSection(&m_maplock);
    heapit = m_heapmap->find(heap);
    if (heapit == m_heapmap->end()) {
        // We haven't mapped this heap to a block map yet. Do it now.
        mapheap(heap);
        heapit = m_heapmap->find(heap);
        assert(heapit != m_heapmap->end());
    }
    if (crtalloc == TRUE) {
        // The heap that this block was allocated from is a CRT heap.
        (*heapit).second->flags |= VLD_HEAP_CRT;
    }
    blockmap = &(*heapit).second->blockmap;
    blockit = blockmap->insert(mem, blockinfo);
    if (blockit == blockmap->end()) {
        // A block with this address has already been allocated. The
        // previously allocated block must have been freed (probably by some
        // mechanism unknown to VLD), or the heap wouldn't have allocated it
        // again. Replace the previously allocated info with the new info.
        blockit = blockmap->find(mem);
        delete (*blockit).second->callstack;
        delete (*blockit).second;
        blockmap->erase(blockit);
        blockmap->insert(mem, blockinfo);
    }
    LeaveCriticalSection(&m_maplock);
}

// mapheap - Tracks heap creation. Creates a block map for tracking individual
//   allocations from the newly created heap and then maps the heap to this
//   block map.
//
//  - heap (IN): Handle to the newly created heap.
//
//  Return Value:
//
//    None.
//
VOID VisualLeakDetector::mapheap (HANDLE heap)
{
    heapinfo_t        *heapinfo;
    HeapMap::Iterator  heapit;

    // Create a new block map for this heap and insert it into the heap map.
    heapinfo = new heapinfo_t;
    heapinfo->blockmap.reserve(BLOCKMAPRESERVE);
    heapinfo->flags = 0x0;
    EnterCriticalSection(&m_maplock);
    heapit = m_heapmap->insert(heap, heapinfo);
    if (heapit == m_heapmap->end()) {
        // Somehow this heap has been created twice without being destroyed,
        // or at least it was destroyed without VLD's knowledge. Unmap the heap
        // from the existing heapinfo, and remap it to the new one.
        report(L"WARNING: Visual Leak Detector detected a duplicate heap (" ADDRESSFORMAT L").\n", heap);
        heapit = m_heapmap->find(heap);
        unmapheap((*heapit).first);
        m_heapmap->insert(heap, heapinfo);
    }
    LeaveCriticalSection(&m_maplock);
}

// remapblock - Tracks reallocations. Unmaps a block from its previously
//   collected information and remaps it to updated information.
//
//  Note: If the block itself remains at the same address, then the block's
//   information can simply be updated rather than having to actually erase and
//   reinsert the block.
//
//  - heap (IN): Handle to the heap from which the memory is being reallocated.
//
//  - mem (IN): Pointer to the memory block being reallocated.
//
//  - newmem (IN): Pointer to the memory block being returned to the caller
//      that requested the reallocation. This pointer may or may not be the same
//      as the original memory block (as pointed to by "mem").
//
//  - size (IN): Size, in bytes, of the new memory block.
//
//  - framepointer (IN): The frame pointer at which this reallocation entered
//      VLD's code. Used for determining the starting point of the stack trace.
//
//  - crtalloc (IN): Should be set to TRUE if this reallocation is for a CRT
//      memory block. Otherwise should be set to FALSE.
//
//  Return Value:
//
//    None.
//
VOID VisualLeakDetector::remapblock (HANDLE heap, LPCVOID mem, LPCVOID newmem, SIZE_T size, SIZE_T framepointer,
                                     BOOL crtalloc)
{
    BlockMap::Iterator   blockit;
    BlockMap            *blockmap;
    HeapMap::Iterator    heapit;
    blockinfo_t         *info;

    if (newmem != mem) {
        // The block was not reallocated in-place. Instead the old block was
        // freed and a new block allocated to satisfy the new size.
        unmapblock(heap, mem);
        mapblock(heap, newmem, size, framepointer, crtalloc);
        return;
    }

    // The block was reallocated in-place. Find the existing blockinfo_t
    // entry in the block map and update it with the new callstack and size.
    EnterCriticalSection(&m_maplock);
    heapit = m_heapmap->find(heap);
    if (heapit == m_heapmap->end()) {
        // We haven't mapped this heap to a block map yet. Obviously the
        // block has also not been mapped to a blockinfo_t entry yet either,
        // so treat this reallocation as a brand-new allocation (this will
        // also map the heap to a new block map).
        mapblock(heap, newmem, size, framepointer, crtalloc);
        LeaveCriticalSection(&m_maplock);
        return;
    }

    // Find the block's blockinfo_t structure so that we can update it.
    blockmap = &(*heapit).second->blockmap;
    blockit = blockmap->find(mem);
    if (blockit == blockmap->end()) {
        // The block hasn't been mapped to a blockinfo_t entry yet.
        // Treat this reallocation as a new allocation.
        mapblock(heap, newmem, size, framepointer, crtalloc);
        LeaveCriticalSection(&m_maplock);
        return;
    }

    // Found the blockinfo_t entry for this block. Update it with
    // a new callstack and new size.
    info = (*blockit).second;
    info->callstack->clear();
    if (crtalloc) {
        // The heap that this block was allocated from is a CRT heap.
        (*heapit).second->flags |= VLD_HEAP_CRT;
    }
    LeaveCriticalSection(&m_maplock);

    // Update the block's callstack and size.
    if (m_options & VLD_OPT_TRACE_INTERNAL_FRAMES) {
        // Passing NULL for the frame pointer argument will force
        // the stack trace to begin at the current frame.
        info->callstack->getstacktrace(m_maxtraceframes, NULL);
    }
    else {
        // Start the stack trace at the call that first entered
        // VLD's code.
        info->callstack->getstacktrace(m_maxtraceframes, (SIZE_T*)framepointer);
    }
    info->size = size;
}

// reportconfig - Generates a brief report summarizing Visual Leak Detector's
//   configuration, as loaded from the vld.ini file.
//
//  Return Value:
//
//    None.
//
VOID VisualLeakDetector::reportconfig ()
{
    if (m_options & VLD_OPT_AGGREGATE_DUPLICATES) {
        report(L"    Aggregating duplicate leaks.\n");
    }
    if (wcslen(m_forcedmodulelist) != 0) {
        report(L"    Forcing inclusion of these modules in leak detection: %s\n", m_forcedmodulelist);
    }
    if (m_maxdatadump != VLD_DEFAULT_MAX_DATA_DUMP) {
        if (m_maxdatadump == 0) {
            report(L"    Suppressing data dumps.\n");
        }
        else {
            report(L"    Limiting data dumps to %lu bytes.\n", m_maxdatadump);
        }
    }
    if (m_maxtraceframes != VLD_DEFAULT_MAX_TRACE_FRAMES) {
        report(L"    Limiting stack traces to %u frames.\n", m_maxtraceframes);
    }
    if (m_options & VLD_OPT_UNICODE_REPORT) {
        report(L"    Generating a Unicode (UTF-16) encoded report.\n");
    }
    if (m_options & VLD_OPT_REPORT_TO_FILE) {
        if (m_options & VLD_OPT_REPORT_TO_DEBUGGER) {
            report(L"    Outputting the report to the debugger and to %s\n", m_reportfilepath);
        }
        else {
            report(L"    Outputting the report to %s\n", m_reportfilepath);
        }
    }
    if (m_options & VLD_OPT_SLOW_DEBUGGER_DUMP) {
        report(L"    Outputting the report to the debugger at a slower rate.\n");
    }
    if (m_options & VLD_OPT_SAFE_STACK_WALK) {
        report(L"    Using the \"safe\" (but slow) stack walking method.\n");
    }
    if (m_options & VLD_OPT_SELF_TEST) {
        report(L"    Perfoming a memory leak self-test.\n");
    }
    if (m_options & VLD_OPT_START_DISABLED) {
        report(L"    Starting with memory leak detection disabled.\n");
    }
    if (m_options & VLD_OPT_TRACE_INTERNAL_FRAMES) {
        report(L"    Including heap and VLD internal frames in stack traces.\n");
    }
}

// reportleaks - Generates a memory leak report for the specified heap.
//
//  - heap (IN): Handle to the heap for which to generate a memory leak
//      report.
//
//  Return Value:
//
//    None.
//
VOID VisualLeakDetector::reportleaks (HANDLE heap)
{
    LPCVOID              address;
    LPCVOID              block;
    BlockMap::Iterator   blockit;
    BlockMap            *blockmap;
    crtdbgblockheader_t *crtheader;
    SIZE_T               duplicates;
    heapinfo_t          *heapinfo;
    HeapMap::Iterator    heapit;
    blockinfo_t         *info;
    SIZE_T               size;

    // Find the heap's information (blockmap, etc).
    EnterCriticalSection(&m_maplock);
    heapit = m_heapmap->find(heap);
    if (heapit == m_heapmap->end()) {
        // Nothing is allocated from this heap. No leaks.
        LeaveCriticalSection(&m_maplock);
        return;
    }

    heapinfo = (*heapit).second;
    blockmap = &heapinfo->blockmap;
    for (blockit = blockmap->begin(); blockit != blockmap->end(); ++blockit) {
        // Found a block which is still in the BlockMap. We've identified a
        // potential memory leak.
        block = (*blockit).first;
        info = (*blockit).second;
        address = block;
        size = info->size;
        if (heapinfo->flags & VLD_HEAP_CRT) {
            // This block is allocated to a CRT heap, so the block has a CRT
            // memory block header prepended to it.
            crtheader = (crtdbgblockheader_t*)block;
            if (CRT_USE_TYPE(crtheader->use) == CRT_USE_INTERNAL) {
                // This block is marked as being used internally by the CRT.
                // The CRT will free the block after VLD is destroyed.
                continue;
            }
            // The CRT header is more or less transparent to the user, so
            // the information about the contained block will probably be
            // more useful to the user. Accordingly, that's the information
            // we'll include in the report.
            address = CRTDBGBLOCKDATA(block);
            size = crtheader->size;
        }
        // It looks like a real memory leak.
        if (m_leaksfound == 0) {
            report(L"WARNING: Visual Leak Detector detected memory leaks!\n");
        }
        m_leaksfound++;
        report(L"---------- Block %ld at " ADDRESSFORMAT L": %u bytes ----------\n", info->serialnumber, address, size);
        if (m_options & VLD_OPT_AGGREGATE_DUPLICATES) {
            // Aggregate all other leaks which are duplicates of this one
            // under this same heading, to cut down on clutter.
            duplicates = eraseduplicates(blockit);
            if (duplicates) {
                report(L"A total of %lu leaks match this size and call stack. Showing only the first one.\n",
                       duplicates + 1);
                m_leaksfound += duplicates;
            }
        }
        // Dump the call stack.
        report(L"  Call Stack:\n");
        info->callstack->dump(m_options & VLD_OPT_TRACE_INTERNAL_FRAMES);
        // Dump the data in the user data section of the memory block.
        if (m_maxdatadump != 0) {
            report(L"  Data:\n");
            if (m_options & VLD_OPT_UNICODE_REPORT) {
                dumpmemoryw(address, (m_maxdatadump < size) ? m_maxdatadump : size);
            }
            else {
                dumpmemorya(address, (m_maxdatadump < size) ? m_maxdatadump : size);
            }
        }
        report(L"\n");
    }

    LeaveCriticalSection(&m_maplock);
}

// unmapblock - Tracks memory blocks that are freed. Unmaps the specified block
//   from the block's information, relinquishing internally allocated resources.
//
//  - heap (IN): Handle to the heap to which this block is being freed.
//
//  - mem (IN): Pointer to the memory block being freed.
//
//  Return Value:
//
//    None.
//
VOID VisualLeakDetector::unmapblock (HANDLE heap, LPCVOID mem)
{
    BlockMap::Iterator  blockit;
    BlockMap           *blockmap;
    HeapMap::Iterator   heapit;
    blockinfo_t        *info;

    // Find this heap's block map.
    EnterCriticalSection(&m_maplock);
    heapit = m_heapmap->find(heap);
    if (heapit == m_heapmap->end()) {
        // We don't have a block map for this heap. We must not have monitored
        // this allocation (probably happened before VLD was initialized).
        LeaveCriticalSection(&m_maplock);
        return;
    }

    // Find this block in the block map.
    blockmap = &(*heapit).second->blockmap;
    blockit = blockmap->find(mem);
    if (blockit == blockmap->end()) {
        // This block is not in the block map. We must not have monitored this
        // allocation (probably happened before VLD was initialized).
        LeaveCriticalSection(&m_maplock);
        return;
    }

    // Free the blockinfo_t structure and erase it from the block map.
    info = (*blockit).second;
    delete info->callstack;
    delete info;
    blockmap->erase(blockit);
    LeaveCriticalSection(&m_maplock);
}

// unmapheap - Tracks heap destruction. Unmaps the specified heap from its block
//   map. The block map is cleared and deleted, relinquishing internally
//   allocated resources.
//
//  - heap (IN): Handle to the heap which is being destroyed.
//
//  Return Value:
//
//    None.
//
VOID VisualLeakDetector::unmapheap (HANDLE heap)
{
    BlockMap::Iterator  blockit;
    BlockMap           *blockmap;
    heapinfo_t         *heapinfo;
    HeapMap::Iterator   heapit;

    // Find this heap's block map.
    EnterCriticalSection(&m_maplock);
    heapit = m_heapmap->find(heap);
    if (heapit == m_heapmap->end()) {
        // This heap hasn't been mapped. We must not have monitored this heap's
        // creation (probably happened before VLD was initialized).
        LeaveCriticalSection(&m_maplock);
        return;
    }

    // Free all of the blockinfo_t structures stored in the block map.
    heapinfo = (*heapit).second;
    blockmap = &heapinfo->blockmap;
    for (blockit = blockmap->begin(); blockit != blockmap->end(); ++blockit) {
        delete (*blockit).second->callstack;
        delete (*blockit).second;
    }
    delete heapinfo;

    // Remove this heap's block map from the heap map.
    m_heapmap->erase(heapit);
    LeaveCriticalSection(&m_maplock);
}


////////////////////////////////////////////////////////////////////////////////
//
// Static Leak Detection Functions (Callbacks)
//
////////////////////////////////////////////////////////////////////////////////

// addloadedmodule - Callback function for EnumerateLoadedModules64. This
//   function records information about every module loaded in the process,
//   each time adding the module's information to the provided ModuleSet (the
//   "context" parameter).
//
//   When EnumerateLoadedModules64 has finished calling this function for each
//   loaded module, then the resulting ModuleSet can be used at any time to get
//   information about any modules loaded into the process.
//
//   - modulepath (IN): The fully qualified path from where the module was
//       loaded.
//
//   - modulebase (IN): The base address at which the module has been loaded.
//
//   - modulesize (IN): The size, in bytes, of the loaded module.
//
//   - context (IN): Pointer to the ModuleSet to which information about each
//       module is to be added.
//
//  Return Value:
//
//    Always returns TRUE, which tells EnumerateLoadedModules64 to continue
//    enumerating.
//
BOOL VisualLeakDetector::addloadedmodule (PCWSTR modulepath, DWORD64 modulebase, ULONG modulesize, PVOID context)
{
    size_t        count;
    patchentry_t *entry;
    CHAR          extension [_MAX_EXT];
    CHAR          filename [_MAX_FNAME];
    UINT          index;
    moduleinfo_t  moduleinfo;
    LPSTR         modulenamea;
    LPSTR         modulepatha;
    ModuleSet*    newmodules = (ModuleSet*)context;
    SIZE_T        size;
    UINT          tablesize = sizeof(m_patchtable) / sizeof(patchentry_t);

    // Convert the module path to ASCII.
    size = wcslen(modulepath) + 1;
    modulepatha = new CHAR [size];
    wcstombs_s(&count, modulepatha, size, modulepath, _TRUNCATE);

    // Extract just the filename and extension from the module path.
    _splitpath_s(modulepatha, NULL, 0, NULL, 0, filename, _MAX_FNAME, extension, _MAX_EXT);
    size = strlen(filename) + strlen(extension) + 1;
    modulenamea = new CHAR [size];
    strncpy_s(modulenamea, size, filename, _TRUNCATE);
    strncat_s(modulenamea, size, extension, _TRUNCATE);
    _strlwr_s(modulenamea, size);

    if (_stricmp(modulenamea, "vld.dll") == 0) {
        // Record Visual Leak Detector's own base address.
        vld.m_vldbase = (HMODULE)modulebase;
    }
    else {
        // See if this is a module listed in the patch table. If it is, update
        // the corresponding patch table entries' module base address.
        for (index = 0; index < tablesize; index++) {
            entry = &m_patchtable[index];
            if (_stricmp(entry->exportmodulename, modulenamea) == 0) {
                entry->modulebase = (SIZE_T)modulebase;
            }
        }
    }

    // Record the module's information and store it in the set.
    moduleinfo.addrlow  = (SIZE_T)modulebase;
    moduleinfo.addrhigh = (SIZE_T)(modulebase + modulesize) - 1;
    moduleinfo.flags    = 0x0;
    moduleinfo.name     = modulenamea;
    moduleinfo.path     = modulepatha;
    newmodules->insert(moduleinfo);

    return TRUE;
}

// detachfrommodule - Callback function for EnumerateLoadedModules64 that
//   detaches Visual Leak Detector from the specified module. If the specified
//   module has not previously been attached to, then calling this function will
//   not actually result in any changes.
//
//  - modulepath (IN): String containing the name, which may include a path, of
//      the module to detach from (ignored).
//
//  - modulebase (IN): Base address of the module.
//
//  - modulesize (IN): Total size of the module (ignored).
//
//  - context (IN): User-supplied context (ignored).
//
//  Return Value:
//
//    Always returns TRUE.
//
BOOL VisualLeakDetector::detachfrommodule (PCWSTR /*modulepath*/, DWORD64 modulebase, ULONG /*modulesize*/,
                                           PVOID /*context*/)
{
    UINT tablesize = sizeof(m_patchtable) / sizeof(patchentry_t);

    restoremodule((HMODULE)modulebase, m_patchtable, tablesize);

    return TRUE;
}


////////////////////////////////////////////////////////////////////////////////
//
// Standard CRT and MFC IAT Replacement Functions
//
// The addresses of these functions are not actually directly patched into the
// import address tables, but these functions do get indirectly called by the
// patch functions that are placed in the import address tables.
//
////////////////////////////////////////////////////////////////////////////////

// _calloc - This function is just a wrapper around the real calloc that sets
//   appropriate flags to be consulted when the memory is actually allocated by
//   RtlAllocateHeap.
//
//  - pcalloc (IN): Pointer to the particular calloc implementation to call.
//
//  - fp (IN): Frame pointer from the call that initiated this allocation.
//
//  - num (IN): The number of blocks, of size 'size', to be allocated.
//
//  - size (IN): The size, in bytes, of the memory block to be allocated.
//
//  Return Value:
//
//    Returns the value returned from the specified calloc.
//
void* VisualLeakDetector::_calloc (calloc_t pcalloc,
                                   SIZE_T   fp,
                                   size_t   num,
                                   size_t   size)
{
    void  *block;
    tls_t *tls = vld.gettls();

    // malloc is a CRT function and allocates from the CRT heap.
    tls->flags |= VLD_TLS_CRTALLOC;

    if (tls->addrfp == 0x0) {
        // This is the first call to enter VLD for the current allocation.
        // Record the current frame pointer.
        tls->addrfp = fp;
    }

    // Do the allocation. The block will be mapped by _RtlAllocateHeap.
    block = pcalloc(num, size);

    // Reset thread local flags and variables for the next allocation.
    tls->addrfp = 0x0;
    tls->flags &= ~VLD_TLS_CRTALLOC;

    return block;
}

// _malloc - This function is just a wrapper around the real malloc that sets
//   appropriate flags to be consulted when the memory is actually allocated by
//   RtlAllocateHeap.
//
//  - pmalloc (IN): Pointer to the particular malloc implementation to call.
//
//  - fp (IN): Frame pointer from the call that initiated this allocation.
//
//  - size (IN): The size, in bytes, of the memory block to be allocated.
//
//  Return Value:
//
//    Returns the value returned from the specified malloc.
//
void *VisualLeakDetector::_malloc (malloc_t pmalloc, SIZE_T fp, size_t size)
{
    void    *block;
    tls_t   *tls = vld.gettls();

    // malloc is a CRT function and allocates from the CRT heap.
    tls->flags |= VLD_TLS_CRTALLOC;

    if (tls->addrfp == 0x0) {
        // This is the first call to enter VLD for the current allocation.
        // Record the current frame pointer.
        tls->addrfp = fp;
    }

    // Do the allocation. The block will be mapped by _RtlAllocateHeap.
    block = pmalloc(size);

    // Reset thread local flags and variables for the next allocation.
    tls->addrfp = 0x0;
    tls->flags &= ~VLD_TLS_CRTALLOC;

    return block;
}

// _new - This function is just a wrapper around the real CRT and MFC new
//   operators that sets appropriate flags to be consulted when the memory is
//   actually allocated by RtlAllocateHeap.
//
//  - pnew (IN): Pointer to the particular new implementation to call.
//
//  - fp (IN): Frame pointer from the call that initiated this allocation.
//
//  - size (IN): The size, in bytes, of the memory block to be allocated.
//
//  Return Value:
//
//    Returns the value returned by the specified CRT new operator.
//
void* VisualLeakDetector::_new (new_t pnew, SIZE_T fp, size_t size)
{
    void  *block;
    tls_t *tls = vld.gettls();

    // The new operator is a CRT function and allocates from the CRT heap.
    tls->flags |= VLD_TLS_CRTALLOC;

    if (tls->addrfp == 0x0) {
        // This is the first call to enter VLD for the current allocation.
        // Record the current frame pointer.
        tls->addrfp = fp;
    }

    // Do the allocation. The block will be mapped by _RtlAllocateHeap.
    block = pnew(size);

    // Reset thread local flags and variables for the next allocation.
    tls->addrfp = 0x0;
    tls->flags &= ~VLD_TLS_CRTALLOC;

    return block;
}

// _realloc - This function is just a wrapper around the real realloc that sets
//   appropriate flags to be consulted when the memory is actually allocated by
//   RtlAllocateHeap.
//
//  - prealloc (IN): Pointer to the particular realloc implementation to call.
//
//  - fp (IN): Frame pointer from the call that initiated this allocation.
//
//  - mem (IN): Pointer to the memory block to reallocate.
//
//  - size (IN): Size of the memory block to reallocate.
//
//  Return Value:
//
//    Returns the value returned from the specified realloc.
//
void* VisualLeakDetector::_realloc (realloc_t  prealloc,
                                    SIZE_T     fp,
                                    void      *mem,
                                    size_t     size)
{
    void  *block;
    tls_t *tls = vld.gettls();

    // realloc is a CRT function and allocates from the CRT heap.
    tls->flags |= VLD_TLS_CRTALLOC;

    if (tls->addrfp == 0x0) {
        // This is the first call to enter VLD for the current allocation.
        // Record the current frame pointer.
        tls->addrfp = fp;
    }

    // Do the allocation. The block will be mapped by _RtlReAllocateHeap.
    block = prealloc(mem, size);

    // Reset thread local flags and variables for the next allocation.
    tls->addrfp = 0x0;
    tls->flags &= ~VLD_TLS_CRTALLOC;

    return block;
}

////////////////////////////////////////////////////////////////////////////////
//
// Debug CRT and MFC IAT Replacement Functions
//
// The addresses of these functions are not actually directly patched into the
// import address tables, but these functions do get indirectly called by the
// patch functions that are placed in the import address tables.
//
////////////////////////////////////////////////////////////////////////////////

// __calloc_dbg - This function is just a wrapper around the real _calloc_dbg
//   that sets appropriate flags to be consulted when the memory is actually
//   allocated by RtlAllocateHeap.
//
//  - p_calloc_dbg: Pointer to the particular _calloc_dbg implementation to
//      call.
//
//  - fp (IN): Frame pointer from the call that initiated this allocation.
//
//  - size (IN): The size, in bytes, of the memory block to be allocated.
//
//  - type (IN): The CRT "use type" of the block to be allocated.
//
//  - file (IN): The name of the file from which this function is being called.
//
//  - line (IN): The line number, in the above file, at which this function is
//      being called.
//
//  Return Value:
//
//    Returns the value returned by the specified _calloc_dbg.
//
void* VisualLeakDetector::__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  *block;
    tls_t *tls = vld.gettls();

    // _malloc_dbg is a CRT function and allocates from the CRT heap.
    tls->flags |= VLD_TLS_CRTALLOC;

    if (tls->addrfp == 0x0) {
        // This is the first call to enter VLD for the current allocation.
        // Record the current frame pointer.
        tls->addrfp = fp;
    }

    // Do the allocation. The block will be mapped by _RtlAllocateHeap.
    block = p_calloc_dbg(num, size, type, file, line);

    // Reset thread local flags and variables for the next allocation.
    tls->addrfp = 0x0;
    tls->flags &= ~VLD_TLS_CRTALLOC;

    return block;
}

// __malloc_dbg - This function is just a wrapper around the real _malloc_dbg
//   that sets appropriate flags to be consulted when the memory is actually
//   allocated by RtlAllocateHeap.
//
//  - p_malloc_dbg (IN): Pointer to the particular _malloc_dbg implementation to
//      call.
//
//  - fp (IN): Frame pointer from the call that initiated this allocation.
//
//  - size (IN): The size, in bytes, of the memory block to be allocated.
//
//  - type (IN): The CRT "use type" of the block to be allocated.
//
//  - file (IN): The name of the file from which this function is being called.
//
//  - line (IN): The line number, in the above file, at which this function is
//      being called.
//
//  Return Value:
//
//    Returns the value returned by the specified _malloc_dbg.
//
void* VisualLeakDetector::__malloc_dbg (_malloc_dbg_t  p_malloc_dbg,
                                        SIZE_T         fp,
                                        size_t         size,
                                        int            type,
                                        char const    *file,
                                        int            line)
{
    void  *block;
    tls_t *tls = vld.gettls();

    // _malloc_dbg is a CRT function and allocates from the CRT heap.
    tls->flags |= VLD_TLS_CRTALLOC;

    if (tls->addrfp == 0x0) {
        // This is the first call to enter VLD for the current allocation.
        // Record the current frame pointer.
        tls->addrfp = fp;
    }

    // Do the allocation. The block will be mapped by _RtlAllocateHeap.
    block = p_malloc_dbg(size, type, file, line);

    // Reset thread local flags and variables for the next allocation.
    tls->addrfp = 0x0;
    tls->flags &= ~VLD_TLS_CRTALLOC;

    return block;
}

// new_dbg_crt - This function is just a wrapper around the real CRT debug new
//   operators that sets appropriate flags to be consulted when the memory is
//   actually allocated by RtlAllocateHeap.
//
//  - pnew_dbg_crt (IN): Pointer to the particular CRT new operator
//      implementation to call.
//
//  - fp (IN): Frame pointer from the call that initiated this allocation.
//
//  - size (IN): The size, in bytes, of the memory block to be allocated.
//
//  - type (IN): The CRT "use type" of the block to be allocated.
//
//  - file (IN): The name of the file from which this function is being called.
//
//  - line (IN): The line number, in the above file, at which this function is
//      being called.
//
//  Return Value:
//
//    Returns the value returned by the specified CRT debug new operator.
//
void* VisualLeakDetector::new_dbg_crt (new_dbg_crt_t  pnew_dbg_crt,
                                       SIZE_T         fp,
                                       size_t         size,
                                       int            type,
                                       char const    *file,
                                       int            line)
{
    void  *block;
    tls_t *tls = vld.gettls();

    // The debug new operator is a CRT function and allocates from the CRT heap.
    tls->flags |= VLD_TLS_CRTALLOC;

    if (tls->addrfp == 0x0) {
        // This is the first call to enter VLD for the current allocation.
        // Record the current frame pointer.
        tls->addrfp = fp;
    }

    // Do the allocation. The block will be mapped by _RtlAllocateHeap.
    block = pnew_dbg_crt(size, type, file, line);

    // Reset thread local flags and variables for the next allocation.
    tls->addrfp = 0x0;
    tls->flags &= ~VLD_TLS_CRTALLOC;

    return block;
}

// new_dbg_mfc - This function is just a wrapper around the real MFC debug new
//   operators that sets appropriate flags to be consulted when the memory is
//   actually allocated by RtlAllocateHeap.
//
//  - pnew_dbg (IN): Pointer to the particular CRT new operator
//      implementation to call.
//
//  - fp (IN): Frame pointer from the call that initiated this allocation.
//
//  - size (IN): The size, in bytes, of the memory block to be allocated.
//
//  - type (IN): The CRT "use type" of the block to be allocated.
//
//  - file (IN): The name of the file from which this function is being called.
//
//  - line (IN): The line number, in the above file, at which this function is
//      being called.
//
//  Return Value:
//
//    Returns the value returned by the specified CRT debug new operator.
//
void* VisualLeakDetector::new_dbg_mfc (new_dbg_crt_t  pnew_dbg,
                                       SIZE_T         fp,
                                       size_t         size,
                                       int            type,
                                       char const    *file,
                                       int            line)
{
    void  *block;
    tls_t *tls = vld.gettls();

    if (tls->addrfp == 0x0) {
        // This is the first call to enter VLD for the current allocation.
        // Record the current frame pointer.
        tls->addrfp = fp;
    }

    // Do the allocation. The block will be mapped by _RtlAllocateHeap.
    block = pnew_dbg(size, type, file, line);

    // Reset thread local flags and variables for the next allocation.
    tls->addrfp = 0x0;
    tls->flags &= ~VLD_TLS_CRTALLOC;

    return block;
}

// new_dbg_mfc - This function is just a wrapper around the real MFC debug new
//   operators that sets appropriate flags to be consulted when the memory is
//   actually allocated by RtlAllocateHeap.
//
//  - pnew_dbg_mfc (IN): Pointer to the particular MFC new operator
//      implementation to call.
//
//  - fp (IN): Frame pointer of the call that initiated this allocation.
//
//  - size (IN): The size, in bytes, of the memory block to be allocated.
//
//  - file (IN): The name of the file from which this function is being called.
//
//  - line (IN): The line number, in the above file, at which this function is
//      being called.
//
//  Return Value:
//
//    Returns the value returned by the specified MFC debug new operator.
//
void* VisualLeakDetector::new_dbg_mfc (new_dbg_mfc_t  pnew_dbg_mfc,
                                       SIZE_T         fp,
                                       size_t         size,
                                       char const    *file,
                                       int            line)
{
    void  *block;
    tls_t *tls = vld.gettls();

    if (tls->addrfp == 0x0) {
        // This is the first call to enter VLD for the current allocation.
        // Record the current frame pointer.
        tls->addrfp = fp;
    }

    // Do the allocation. The block will be mapped by _RtlAllocateHeap.
    block = pnew_dbg_mfc(size, file, line);

    // Reset thread local flags and variables for the next allocation.
    tls->addrfp = 0x0;
    tls->flags &= ~VLD_TLS_CRTALLOC;

    return block;
}

// __realloc_debug - This function is just a wrapper around the real
//   _realloc_dbg that sets appropriate flags to be consulted when the memory is
//   actually allocated by RtlAllocateHeap.
//
//  - p_realloc_dbg (IN): Pointer to the particular __realloc_dbg implementation
//      to call.
//
//  - fp (IN): Frame pointer from the call that initiated this allocation.
//
//  - mem (IN): Pointer to the memory block to be reallocated.
//
//  - size (IN): The size of the memory block to reallocate.
//
//  - type (IN): The CRT "use type" of the block to be reallocated.
//
//  - file (IN): The name of the file from which this function is being called.
//
//  - line (IN): The line number, in the above file, at which this function is
//      being called.
//
//  Return Value:
//
//    Returns the value returned by the specified _realloc_dbg.
//
void* VisualLeakDetector::__realloc_dbg (_realloc_dbg_t  p_realloc_dbg,
                                         SIZE_T          fp,
                                         void           *mem,
                                         size_t          size,
                                         int             type,
                                         char const     *file,
                                         int             line)
{
    void  *block;
    tls_t *tls = vld.gettls();

    // _realloc_dbg is a CRT function and allocates from the CRT heap.
    tls->flags |= VLD_TLS_CRTALLOC;

    if (tls->addrfp == 0x0) {
        // This is the first call to enter VLD for the current allocation.
        // Record the current frame pointer.
        tls->addrfp = fp;
    }

    // Do the allocation. The block will be mapped by _RtlReAllocateHeap.
    block = p_realloc_dbg(mem, size, type, file, line);

    // Reset thread local flags and variables for the next allocation.
    tls->addrfp = 0x0;
    tls->flags &= ~VLD_TLS_CRTALLOC;

    return block;
}

////////////////////////////////////////////////////////////////////////////////
//
// Win32 IAT Replacement Functions
//
////////////////////////////////////////////////////////////////////////////////

// _GetProcAddress - Calls to GetProcAddress are patched through to this
//   function. If the requested function is a function that has been patched
//   through to one of VLD's handlers, then the address of VLD's handler
//   function is returned instead of the real address. Otherwise, this 
//   function is just a wrapper around the real GetProcAddress.
//
//  - module (IN): Handle (base address) of the module from which to retrieve
//      the address of an exported function.
//
//  - procname (IN): ANSI string containing the name of the exported function
//      whose address is to be retrieved.
//
//  Return Value:
//
//    Returns a pointer to the requested function, or VLD's replacement for
//    the function, if there is a replacement function.
//
FARPROC VisualLeakDetector::_GetProcAddress (HMODULE module, LPCSTR procname)
{
    patchentry_t *entry;
    UINT          index;
    UINT          tablesize = sizeof(vld.m_patchtable) / sizeof(patchentry_t);

    // See if there is an entry in the patch table that matches the requested
    // function.
    for (index = 0; index < tablesize; index++) {
        entry = &vld.m_patchtable[index];
        if ((entry->modulebase == 0x0) || ((HMODULE)entry->modulebase != module)) {
            // This patch table entry is for a different module.
            continue;
        }

        // This patch table entry is for the specified module. If the requested
        // import's name matches the entry's import name (or ordinal), then
        // return the address of the replacement instead of the address of the
        // actual import.
        if ((SIZE_T)entry->importname < (SIZE_T)vld.m_vldbase) {
            // This entry's import name is not a valid pointer to data in
            // vld.dll. It must be an ordinal value.
            if ((UINT)entry->importname == (UINT)procname) {
                return (FARPROC)entry->replacement;
            }
        }
        else {
            if (strcmp(entry->importname, procname) == 0) {
                return (FARPROC)entry->replacement;
            }
        }
    }

    // The requested function is not a patched function. Just return the real
    // address of the requested function.
    return GetProcAddress(module, procname);
}

// _HeapCreate - Calls to HeapCreate are patched through to this function. This
//   function is just a wrapper around the real HeapCreate that calls VLD's heap
//   creation tracking function after the heap has been created.
//
//  - options (IN): Heap options.
//
//  - initsize (IN): Initial size of the heap.
//
//  - maxsize (IN): Maximum size of the heap.
//
//  Return Value:
//
//    Returns the value returned by HeapCreate.
//
HANDLE VisualLeakDetector::_HeapCreate (DWORD options, SIZE_T initsize, SIZE_T maxsize)
{
    DWORD64            displacement;
    SIZE_T             fp;
    SYMBOL_INFO       *functioninfo;
    HANDLE             heap;
    HeapMap::Iterator  heapit;
    SIZE_T             ra;
    BYTE               symbolbuffer [sizeof(SYMBOL_INFO) + (MAXSYMBOLNAMELENGTH * sizeof(WCHAR)) - 1] = { 0 };
    BOOL               symfound;

    // Get the return address within the calling function.
    FRAMEPOINTER(fp);
    ra = *((SIZE_T*)fp + 1);

    // Create the heap.
    heap = HeapCreate(options, initsize, maxsize);

    // Map the created heap handle to a new block map.
    vld.mapheap(heap);

    // Try to get the name of the function containing the return address.
    functioninfo = (SYMBOL_INFO*)&symbolbuffer;
    functioninfo->SizeOfStruct = sizeof(SYMBOL_INFO);
    functioninfo->MaxNameLen = MAXSYMBOLNAMELENGTH;
    EnterCriticalSection(&symbollock);
    symfound = SymFromAddrW(currentprocess, ra, &displacement, functioninfo);
    LeaveCriticalSection(&symbollock);
    if (symfound == TRUE) {
        if (wcscmp(L"_heap_init", functioninfo->Name) == 0) {
            // HeapCreate was called by _heap_init. This is a static CRT heap.
            EnterCriticalSection(&vld.m_maplock);
            heapit = vld.m_heapmap->find(heap);
            assert(heapit != vld.m_heapmap->end());
            (*heapit).second->flags |= VLD_HEAP_CRT;
            LeaveCriticalSection(&vld.m_maplock);
        }
    }

    return heap;
}

// _HeapDestroy - Calls to HeapDestroy are patched through to this function.
//   This function is just a wrapper around the real HeapDestroy that calls
//   VLD's heap destruction tracking function after the heap has been destroyed.
//
//  - heap (IN): Handle to the heap to be destroyed.
//
//  Return Value:
//
//    Returns the valued returned by HeapDestroy.
//
BOOL VisualLeakDetector::_HeapDestroy (HANDLE heap)
{
    // After this heap is destroyed, the heap's address space will be unmapped
    // from the process's address space. So, we'd better generate a leak report
    // for this heap now, while we can still read from the memory blocks
    // allocated to it.
    vld.reportleaks(heap);

    vld.unmapheap(heap);

    return HeapDestroy(heap);
}

// _LdrLoadDll - Calls to LdrLoadDll are patched through to this function. This
//   function invokes the real LdrLoadDll and then re-attaches VLD to all
//   modules loaded in the process after loading of the new DLL is complete.
//   All modules must be re-enumerated because the explicit load of the
//   specified module may result in the implicit load of one or more additional
//   modules which are dependencies of the specified module.
//
//  - searchpath (IN): The path to use for searching for the specified module to
//      be loaded.
//
//  - flags (IN): Pointer to action flags.
//
//  - modulename (IN): Pointer to a unicodestring_t structure specifying the
//      name of the module to be loaded.
//
//  - modulehandle (OUT): Address of a HANDLE to receive the newly loaded
//      module's handle.
//
//  Return Value:
//
//    Returns the value returned by LdrLoadDll.
//
NTSTATUS VisualLeakDetector::_LdrLoadDll (LPWSTR searchpath, PDWORD flags, unicodestring_t *modulename,
                                          PHANDLE modulehandle)
{
    ModuleSet::Iterator  moduleit;
    ModuleSet           *newmodules;
    ModuleSet           *oldmodules;
    NTSTATUS             status;

    EnterCriticalSection(&vld.m_loaderlock);

    // Load the DLL.
    status = LdrLoadDll(searchpath, flags, modulename, modulehandle);
    
    if (STATUS_SUCCESS == status) {
        // Create a new set of all loaded modules, including any newly loaded
        // modules.
        newmodules = new ModuleSet;
        newmodules->reserve(MODULESETRESERVE);
        EnumerateLoadedModulesW64(currentprocess, addloadedmodule, newmodules);

        // Attach to all modules included in the set.
        vld.attachtoloadedmodules(newmodules);

        // Start using the new set of loaded modules.
        EnterCriticalSection(&vld.m_moduleslock);
        oldmodules = vld.m_loadedmodules;
        vld.m_loadedmodules = newmodules;
        LeaveCriticalSection(&vld.m_moduleslock);

        // Free resources used by the old module list.
        for (moduleit = oldmodules->begin(); moduleit != oldmodules->end(); ++moduleit) {
            delete (*moduleit).name;
            delete (*moduleit).path;
        }
        delete oldmodules;
    }

    LeaveCriticalSection(&vld.m_loaderlock);

    return status;
}

// _RtlAllocateHeap - Calls to RtlAllocateHeap are patched through to this
//   function. This function invokes the real RtlAllocateHeap and then calls
//   VLD's allocation tracking function. Pretty much all memory allocations
//   will eventually result in a call to RtlAllocateHeap, so this is where we
//   finally map the allocated block.
//
//  - heap (IN): Handle to the heap from which to allocate memory.
//
//  - flags (IN): Heap allocation control flags.
//
//  - size (IN): Size, in bytes, of the block to allocate.
//
//  Return Value:
//
//    Returns the return value from RtlAllocateHeap.
//
LPVOID VisualLeakDetector::_RtlAllocateHeap (HANDLE heap, DWORD flags, SIZE_T size)
{
    BOOL                 crtalloc;
    BOOL                 excluded = FALSE;
    SIZE_T               fp;
    LPVOID               block;
    moduleinfo_t         moduleinfo;
    ModuleSet::Iterator  moduleit;
    SIZE_T               returnaddress;
    tls_t               *tls = vld.gettls();

    // Allocate the block.
    block = RtlAllocateHeap(heap, flags, size);
    if ((block != NULL) && vld.enabled()) {
        if (tls->addrfp == 0x0) {
            // This is the first call to enter VLD for the current allocation.
            // Record the current frame pointer.
            FRAMEPOINTER(fp);
        }
        else {
            fp = tls->addrfp;
        }
        crtalloc = (tls->flags & VLD_TLS_CRTALLOC) ? TRUE : FALSE;

        // Reset thread local flags and variables, in case any libraries called
        // into while mapping the block allocate some memory.
        tls->addrfp = 0x0;
        tls->flags &=~VLD_TLS_CRTALLOC;

        // Find the information for the module that initiated this allocation.
        returnaddress = *((SIZE_T*)fp + 1);
        moduleinfo.addrhigh = returnaddress;
        moduleinfo.addrlow  = returnaddress;
        EnterCriticalSection(&vld.m_moduleslock);
        moduleit = vld.m_loadedmodules->find(moduleinfo);
        if (moduleit != vld.m_loadedmodules->end()) {
            excluded = (*moduleit).flags & VLD_MODULE_EXCLUDED ? TRUE : FALSE;
        }
        LeaveCriticalSection(&vld.m_moduleslock);
        if (!excluded) {
            // The module that initiated this allocation is included in leak
            // detection. Map this block to the specified heap.
            vld.mapblock(heap, block, size, fp, crtalloc);
        }
    }

    // Reset thread local flags and variables for the next allocation.
    tls->addrfp = 0x0;
    tls->flags &= ~VLD_TLS_CRTALLOC;

    return block;
}

// _RtlFreeHeap - Calls to RtlFreeHeap are patched through to this function.
//   This function calls VLD's free tracking function and then invokes the real
//   RtlFreeHeap. Pretty much all memory frees will eventually result in a call
//   to RtlFreeHeap, so this is where we finally unmap the freed block.
//
//  - heap (IN): Handle to the heap to which the block being freed belongs.
//
//  - flags (IN): Heap control flags.
//
//  - mem (IN): Pointer to the memory block being freed.
//
//  Return Value:
//
//    Returns the value returned by RtlFreeHeap.
//
BOOL VisualLeakDetector::_RtlFreeHeap (HANDLE heap, DWORD flags, LPVOID mem)
{
    BOOL status;

    // Unmap the block from the specified heap.
    vld.unmapblock(heap, mem);

    status = RtlFreeHeap(heap, flags, mem);

    return status;
}

// _RtlReAllocateHeap - Calls to RtlReAllocateHeap are patched through to this
//   function. This function invokes the real RtlReAllocateHeap and then calls
//   VLD's reallocation tracking function. All arguments passed to this function
//   are passed on to the real RtlReAllocateHeap without modification. Pretty
//   much all memory re-allocations will eventually result in a call to
//   RtlReAllocateHeap, so this is where we finally remap the reallocated block.
//
//  - heap (IN): Handle to the heap to reallocate memory from.
//
//  - flags (IN): Heap control flags.
//
//  - mem (IN): Pointer to the currently allocated block which is to be
//      reallocated.
//
//  - size (IN): Size, in bytes, of the block to reallocate.
//
//  Return Value:
//
//    Returns the value returned by RtlReAllocateHeap.
//
LPVOID VisualLeakDetector::_RtlReAllocateHeap (HANDLE heap, DWORD flags, LPVOID mem, SIZE_T size)
{
    BOOL                 crtalloc;
    BOOL                 excluded = FALSE;
    SIZE_T               fp;
    moduleinfo_t         moduleinfo;
    ModuleSet::Iterator  moduleit;
    LPVOID               newmem;
    SIZE_T               returnaddress;
    tls_t               *tls = vld.gettls();

    // Reallocate the block.
    newmem = RtlReAllocateHeap(heap, flags, mem, size);

    if (newmem != NULL) {
        if (tls->addrfp == 0x0) {
            // This is the first call to enter VLD for the current allocation.
            // Record the current frame pointer.
            FRAMEPOINTER(fp);
        }
        else {
            fp = tls->addrfp;
        }
        crtalloc = (tls->flags & VLD_TLS_CRTALLOC) ? TRUE : FALSE;

        // Reset thread local flags and variables, in case any libraries called
        // into while remapping the block allocate some memory.
        tls->addrfp = 0x0;
        tls->flags &= ~VLD_TLS_CRTALLOC;

        // Find the information for the module that initiated this reallocation.
        returnaddress = *((SIZE_T*)fp + 1);
        moduleinfo.addrhigh = returnaddress;
        moduleinfo.addrlow  = returnaddress;
        EnterCriticalSection(&vld.m_moduleslock);
        moduleit = vld.m_loadedmodules->find(moduleinfo);
        if (moduleit != vld.m_loadedmodules->end()) {
            excluded = (*moduleit).flags & VLD_MODULE_EXCLUDED ? TRUE : FALSE;
        }
        LeaveCriticalSection(&vld.m_moduleslock);
        if (!excluded) {
            // The module that initiated this allocation is included in leak
            // detection. Remap the block.
            vld.remapblock(heap, mem, newmem, size, fp, crtalloc);
        }
    }

    // Reset thread local flags and variables for the next allocation.
    tls->addrfp = 0x0;
    tls->flags &= ~VLD_TLS_CRTALLOC;

    return newmem;
}

////////////////////////////////////////////////////////////////////////////////
//
// COM IAT Replacement Functions
//
////////////////////////////////////////////////////////////////////////////////

// _CoGetMalloc - Calls to CoGetMalloc are patched through to this function.
//   This function returns a pointer to Visual Leak Detector's implementation
//   of the IMalloc interface, instead of returning a pointer to the system
//   implementation. This allows VLD's implementation of the IMalloc interface
//   (which is basically a thin wrapper around the system implementation) to be
//   invoked in place of the system implementation.
//
//  - context (IN): Reserved; value must be 1.
//
//  - imalloc (IN): Address of a pointer to receive the address of VLD's
//      implementation of the IMalloc interface.
//
//  Return Value:
//
//    Always returns S_OK.
//
HRESULT VisualLeakDetector::_CoGetMalloc (DWORD context, LPMALLOC *imalloc)
{
    static CoGetMalloc_t pCoGetMalloc = NULL;

    HMODULE ole32;

    *imalloc = (LPMALLOC)&vld;

    if (pCoGetMalloc == NULL) {
        // This is the first call to this function. Link to the real
        // CoGetMalloc and get a pointer to the system implementation of the
        // IMalloc interface.
        ole32 = GetModuleHandle(L"ole32.dll");
        pCoGetMalloc = (CoGetMalloc_t)GetProcAddress(ole32, "CoGetMalloc");
        pCoGetMalloc(context, &vld.m_imalloc);
    }

    return S_OK;
}

// _CoTaskMemAlloc - Calls to CoTaskMemAlloc are patched through to this
//   function. This function is just a wrapper around the real CoTaskMemAlloc
//   that sets appropriate flags to be consulted when the memory is actually
//   allocated by RtlAllocateHeap.
//
//  - size (IN): Size of the memory block to allocate.
//
//  Return Value:
//
//    Returns the value returned from CoTaskMemAlloc.
//
LPVOID VisualLeakDetector::_CoTaskMemAlloc (ULONG size)
{
    static CoTaskMemAlloc_t pCoTaskMemAlloc = NULL;

    LPVOID   block;
    SIZE_T   fp;
    HMODULE  ole32;
    tls_t   *tls = vld.gettls();

    if (tls->addrfp == 0x0) {
        // This is the first call to enter VLD for the current allocation.
        // Record the current frame pointer.
        FRAMEPOINTER(fp);
        tls->addrfp = fp;
    }

    if (pCoTaskMemAlloc == NULL) {
        // This is the first call to this function. Link to the real
        // CoTaskMemAlloc.
        ole32 = GetModuleHandle(L"ole32.dll");
        pCoTaskMemAlloc = (CoTaskMemAlloc_t)GetProcAddress(ole32, "CoTaskMemAlloc");
    }

    // Do the allocation. The block will be mapped by _RtlAllocateHeap.
    block = pCoTaskMemAlloc(size);

    // Reset thread local flags and variables for the next allocation.
    tls->addrfp = 0x0;
    tls->flags &= ~VLD_TLS_CRTALLOC;
    
    return block;
}

// _CoTaskMemRealloc - Calls to CoTaskMemRealloc are patched through to this
//   function. This function is just a wrapper around the real CoTaskMemRealloc
//   that sets appropriate flags to be consulted when the memory is actually
//   allocated by RtlAllocateHeap.
//
//  - mem (IN): Pointer to the memory block to reallocate.
//
//  - size (IN): Size, in bytes, of the block to reallocate.
//
//  Return Value:
//
//    Returns the value returned from CoTaskMemRealloc.
//
LPVOID VisualLeakDetector::_CoTaskMemRealloc (LPVOID mem, ULONG size)
{
    static CoTaskMemRealloc_t pCoTaskMemRealloc = NULL;

    LPVOID   block;
    SIZE_T   fp;
    HMODULE  ole32;
    tls_t   *tls = vld.gettls();

    if (tls->addrfp == 0x0) {
        // This is the first call to enter VLD for the current allocation.
        // Record the current frame pointer.
        FRAMEPOINTER(fp);
        tls->addrfp = fp;
    }

    if (pCoTaskMemRealloc == NULL) {
        // This is the first call to this function. Link to the real
        // CoTaskMemRealloc.
        ole32 = GetModuleHandle(L"ole32.dll");
        pCoTaskMemRealloc = (CoTaskMemRealloc_t)GetProcAddress(ole32, "CoTaskMemRealloc");
    }

    // Do the allocation. The block will be mapped by _RtlReAllocateHeap.
    block = pCoTaskMemRealloc(mem, size);

    // Reset thread local flags and variables for the next allocation.
    tls->addrfp = 0x0;
    tls->flags &= ~VLD_TLS_CRTALLOC;

    return block;
}

////////////////////////////////////////////////////////////////////////////////
//
// Public COM IMalloc Implementation Functions
//
////////////////////////////////////////////////////////////////////////////////

// AddRef - Calls to IMalloc::AddRef end up here. This function is just a
//   wrapper around the real IMalloc::AddRef implementation.
//
//  Return Value:
//
//    Returns the value returned by the system implementation of
//    IMalloc::AddRef.
//
ULONG VisualLeakDetector::AddRef ()
{
    assert(m_imalloc != NULL);
    return m_imalloc->AddRef();
}

// Alloc - Calls to IMalloc::Alloc end up here. This function is just a wrapper
//   around the real IMalloc::Alloc implementation that sets appropriate flags
//   to be consulted when the memory is actually allocated by RtlAllocateHeap.
//
//  - size (IN): The size of the memory block to allocate.
//
//  Return Value:
//
//    Returns the value returned by the system's IMalloc::Alloc implementation.
//
LPVOID VisualLeakDetector::Alloc (ULONG size)
{
    LPVOID  block;
    SIZE_T  fp;
    tls_t  *tls = vld.gettls();

    if (tls->addrfp == 0x0) {
        // This is the first call to enter VLD for the current allocation.
        // Record the current frame pointer.
        FRAMEPOINTER(fp);
        tls->addrfp = fp;
    }

    // Do the allocation. The block will be mapped by _RtlAllocateHeap.
    assert(m_imalloc != NULL);
    block = m_imalloc->Alloc(size);

    // Reset thread local flags and variables for the next allocation.
    tls->addrfp = 0x0;
    tls->flags &= ~VLD_TLS_CRTALLOC;

    return block;
}

// DidAlloc - Calls to IMalloc::DidAlloc will end up here. This function is just
//   a wrapper around the system implementation of IMalloc::DidAlloc.
//
//  - mem (IN): Pointer to a memory block to inquire about.
//
//  Return Value:
//
//    Returns the value returned by the system implementation of
//    IMalloc::DidAlloc.
//
INT VisualLeakDetector::DidAlloc (LPVOID mem)
{
    assert(m_imalloc != NULL);
    return m_imalloc->DidAlloc(mem);
}

// Free - Calls to IMalloc::Free will end up here. This function is just a
//   wrapper around the real IMalloc::Free implementation.
//
//  - mem (IN): Pointer to the memory block to be freed.
//
//  Return Value:
//
//    None.
//
VOID VisualLeakDetector::Free (LPVOID mem)
{
    assert(m_imalloc != NULL);
    m_imalloc->Free(mem);
}

// GetSize - Calls to IMalloc::GetSize will end up here. This function is just a
//   wrapper around the real IMalloc::GetSize implementation.
//
//  - mem (IN): Pointer to the memory block to inquire about.
//
//  Return Value:
//
//    Returns the value returned by the system implementation of
//    IMalloc::GetSize.
//
ULONG VisualLeakDetector::GetSize (LPVOID mem)
{
    assert(m_imalloc != NULL);
    return m_imalloc->GetSize(mem);
}

// HeapMinimize - Calls to IMalloc::HeapMinimize will end up here. This function
//   is just a wrapper around the real IMalloc::HeapMinimize implementation.
//
//  Return Value:
//
//    None.
//
VOID VisualLeakDetector::HeapMinimize ()
{
    assert(m_imalloc != NULL);
    m_imalloc->HeapMinimize();
}

// QueryInterface - Calls to IMalloc::QueryInterface will end up here. This
//   function is just a wrapper around the real IMalloc::QueryInterface
//   implementation.
//
//  - iid (IN): COM interface ID to query about.
//
//  - object (IN): Address of a pointer to receive the requested interface
//      pointer.
//
//  Return Value:
//
//    Returns the value returned by the system implementation of
//    IMalloc::QueryInterface.
//
HRESULT VisualLeakDetector::QueryInterface (REFIID iid, LPVOID *object)
{
    assert(m_imalloc != NULL);
    return m_imalloc->QueryInterface(iid, object);
}

// Realloc - Calls to IMalloc::Realloc will end up here. This function is just a
//   wrapper around the real IMalloc::Realloc implementation that sets
//   appropriate flags to be consulted when the memory is actually allocated by
//   RtlAllocateHeap.
//
//  - mem (IN): Pointer to the memory block to reallocate.
//
//  - size (IN): Size, in bytes, of the memory block to reallocate.
//
//  Return Value:
//
//    Returns the value returned by the system implementation of
//    IMalloc::Realloc.
//
LPVOID VisualLeakDetector::Realloc (LPVOID mem, ULONG size)
{
    LPVOID  block;
    SIZE_T  fp;
    tls_t  *tls = vld.gettls();

    if (tls->addrfp == 0x0) {
        // This is the first call to enter VLD for the current allocation.
        // Record the current frame pointer.
        FRAMEPOINTER(fp);
        tls->addrfp = fp;
    }

    // Do the allocation. The block will be mapped by _RtlReAllocateHeap.
    assert(m_imalloc != NULL);
    block = m_imalloc->Realloc(mem, size);

    // Reset thread local flags and variables for the next allocation.
    tls->addrfp = 0x0;
    tls->flags &= ~VLD_TLS_CRTALLOC;
    
    return block;
}

// Release - Calls to IMalloc::Release will end up here. This function is just
//   a wrapper around the real IMalloc::Release implementation.
//
//  Return Value:
//
//    Returns the value returned by the system implementation of
//    IMalloc::Release.
//
ULONG VisualLeakDetector::Release ()
{
    assert(m_imalloc != NULL);
    return m_imalloc->Release();
}
