--- /dev/null
+Visual Leak Detector (VLD) Version 1.9f (beta)
+
+ Change Log / Release Notes
+
+1.9f beta (18 November 2006)
+----------------------------
+ Bugs Fixed:
+ + Deadlocks or access violations may occur when loading DLLs into
+ multithreaded processes.
+ + In multithreaded programs, if the main thread terminates before other
+ threads in the process, then Visual Leak Detector may cause an access
+ violation while generating the memory leak report.
+
+ Known Bugs/Restrictions:
+ + Memory allocations made through calls to functions loaded from a DLL using
+ delayed loading may not be detected.
+ + Support for programs that use MFC 7.0 or MFC 7.1 is not complete yet. Some
+ memory leaks from such MFC-based programs may not be detected.
+ + Visual Leak Detector may report leaks internal to Visual Leak Detector
+ if the main thread of the process terminates while other threads are still
+ running.
+ + If more than one copy of the same C Runtime DLL is loaded in the process at
+ the same time, then some leaks may go undetected (note that loading more
+ than one copy of the C Runtime DLL into a process at the same time is
+ probably a bad idea to begin with).
+
+1.9e beta (16 November 2006)
+----------------------------
+ New Features/Enhancements:
+ + Added a master on/off switch configuration option to vld.ini that can be
+ used to completely disable Visual Leak Detector.
+
+ Bugs Fixed:
+ + Numerous deadlock situations. The multithread synchronization scheme has
+ been completely re-written which should make deadlocks in VLD much less
+ likey to happen.
+ + An access violation will occur in VLD if GetProcAddress is called to obtain
+ an export's address by ordinal, for certain libraries.
+ + Problems may potentially occur when the program being debugged exits due to
+ the Debug Help Library having been detached from the process too early.
+ Symptoms might include access violation exceptions or other erratic behavior
+ just as the program exits and while VLD is generating the leak report.
+ + The copy of vld.ini installed in VLD's installation directory overrides any
+ other copies of vld.ini that are created, even copies placed in the
+ working directory of the program being debugged.
+
+ Known Bugs/Restrictions:
+ + Memory allocations made through calls to functions loaded from a DLL using
+ delayed loading may not be detected.
+ + Support for programs that use MFC 7.0 or MFC 7.1 is not complete yet. Some
+ memory leaks from such MFC-based programs may not be detected.
+ + If more than one copy of the same C Runtime DLL is loaded in the process at
+ the same time, then some leaks may go undetected (note that loading more
+ than one copy of the C Runtime DLL into a process at the same time is
+ probably a bad idea to begin with).
+
+1.9d beta (12 November 2006)
+----------------------------
+ Bugs Fixed:
+ + Failed assertion "freed == TRUE" pops up when running a program with VLD
+ without the debugger attached.
+ + Some, but not all, multithreaded programs that dynamically load and unload
+ many DLLs have been known to experience problems, such as deadlocks or
+ exceptions, when used with VLD.
+ + Failed assertion "exportmodule != NULL" pops up when running some programs
+ with VLD.
+ + VLD fails to show file names or function names in the memory leak report for
+ some programs that are linked with the dynamic CRT library.
+ + Access violation exceptions are thrown, but caught by the operating system,
+ when running some programs with VLD.
+
+1.9c beta (6 November 2006)
+---------------------------
+ New Features/Enhancments:
+ + New NSIS installer makes setting up and using VLD much easier.
+ + No need to manually copy dbghelp.dll to the right location, VLD will always
+ find the right version.
+ + MFC 8.0 is now fully supported.
+ + The memory leak report is now written to the output window much faster.
+ Support has been added, through a new configuration option, to slow down
+ the report output for older versions of Visual Studio that have trouble
+ when it is written too quickly.
+
+ Bugs Fixed:
+ + All known compatibilities with Visual Studio 2005 have been eliminated.
+ + Leaks from calloc may go undetected.
+ + Leaks from vector new operator may go undetected.
+ + VLDDisable and VLDEnable do not work as expected; some memory leaks that
+ should be ignored by VLD due to a previous call to VLDDisable are still
+ reported.
+ + Unloading and reloading a previously loaded module may cause leaks that
+ occur in the module after it was reloaded to go undetected.
+ + If vld.h is included in a release build, then the compiler will generate
+ errors if the VLDEnable or VLDDisable APIs have been used.
+
+1.9b beta (26 October 2006)
+---------------------------
+ Bugs Fixed:
+ + Source compiles under Visual Studio 2005 and the binaries are compatible
+ with applications that link with the Visual Studio 2005 C Runtime Library
+ (msvcr80d.dll).
+
+ Known Restrictions in this Release:
+ + Memory allocations made through calls to functions loaded from a DLL using
+ delayed loading may not be detected.
+
+ + Support for programs that use MFC 7.0, MFC 7.1, or MFC 8.0 is not complete
+ yet. Some memory leaks from such MFC-based programs may not be detected. A
+ workaround for this restriction is to forcefully include the MFC DLLs in
+ memory leak detection, by setting the "ForceIncludeModules" configuration
+ option to: "mfc70d.dll mfc71d.dll mfc80d.dll" and explicitly adding vld.lib
+ as an input file on the linker command line (can be added through project
+ settings by adding it to the list of library modules in the linker options).
+ This restriction does not apply to programs that use MFC 4.2, which is fully
+ supported.
+
+1.9a beta (9 March 2006)
+------------------------
+ New Features/Enhancments:
+ + All new leak detection engine detects most, if not all, in-process memory
+ leaks, not just leaks from "new" or "malloc", including COM-based leaks.
+
+ + Packaged as an easier-to-use DLL. There's no longer any need to carefully
+ decide which modules should be linked with the VLD library. Instead, you
+ just include the vld.h header file in at least one source file from each
+ module (DLL or EXE) to be included in memory leak detection.
+
+ + Configuration is done from an INI file instead of using preprocessor macros.
+ This allows VLD's configuration to be changed without needing to recompile
+ the program.
+
+ + Many new configuration options have been added. One of the most often
+ requested option that has been added is the option to save the leak report
+ to a file instead of, or in addition to, the debugger.
+
+ Bugs Fixed:
+ + The improved design of the new leak detection engine has resolved all of the
+ previously known restrictions in version 1.0.
+
+ Known Restrictions in this Release:
+ + Memory allocations made through calls to functions loaded from a DLL using
+ delayed loading may not be detected.
+
+ + Support for programs that use MFC 7.0, MFC 7.1, or MFC 8.0 is not complete
+ yet. Some memory leaks from such MFC-based programs may not be detected. A
+ workaround for this restriction is to forcefully include the MFC DLLs in
+ memory leak detection, by setting the "ForceIncludeModules" configuration
+ option to: "mfc70d.dll mfc71d.dll mfc80d.dll" and explicitly adding vld.lib
+ as an input file on the linker command line (can be added through project
+ settings by adding it to the list of library modules in the linker options).
+ This restriction does not apply to programs that use MFC 4.2, which is fully
+ supported.
+
+
+1.0 (5 August 2005)
+-------------------
+ New Features/Enhancements:
+ + Memory leak detection can now be selectively disabled and enabled at
+ runtime, using provided APIs. This provides a straightforward way of
+ allowing VLD to selectively "ignore" certain allocations. It can also be
+ used to disable VLD altogether at runtime, improving application performance
+ without needing to recompile.
+
+ + If there are multiple identical memory leaks (i.e. leaks that originate from
+ the same call stack and that leak the same size memory block) then VLD can
+ optionally aggregate all of the repeated leaks, showing only the first such
+ leaked block in detail in the memory leak report. A tally of the total
+ number of leaks that match that particular size and call stack accompanies
+ the information for that leak.
+
+ + When VLD is initialized at program startup, the library type which was
+ linked-in is displayed. This can help verify that the expected VLD library
+ (either single-threaded static, multithreaded static, or multithreaded DLL)
+ is being linked with your program.
+
+ + The Visual Leak Detector name is displayed on most messages output to the
+ debugger to easily differentiate VLD's output from the output produced by
+ the built-in memory leak detector.
+
+ + If any of the compile-time configuration options have been changed from
+ their default values, then the current state of the option is displayed in
+ the debugger when VLD is initialized.
+
+ + VLD's memory leak self-checking capability (checking for leaks in VLD
+ itself) can be verified using a new preprocessor macro that allows VLD to
+ perform a self-test at runtime.
+
+ Bugs Fixed:
+ + If the MFC libraries are statically linked to the program being debugged,
+ then MFC will erroneously report memory leaks in the Visual Leak Detector
+ code and may cause an access violation while attempting to report the false
+ memory leaks. These bogus leaks are always reported as "client block at
+ <address>, subtype bf42" and are claimed to be "invalid objects".
+
+ + VLD will leak a fixed-sized block of memory when the program exits if VLD
+ failed to initialize because the Debug Help library (dbghelp.dll) could not
+ be loaded.
+
+ + In multithreaded programs, if the program's main thread terminates before
+ other threads in the same process, then VLD may cause an access violation
+ while freeing resources used internally by VLD.
+
+
+0.9i beta (30 April 2005)
+-------------------------
+ New Features/Enhancements:
+ + Added support in the source code for x64 architecture. The pre-built
+ libraries will continue to support 32-bit only. If you need 64-bit support
+ you'll need to build 64-bit versions of the libraries from source. Note that
+ x64 is the only 64-bit architecture supported at this time. Itanium (aka
+ IA-64) is NOT currently supported.
+
+ Bugs Fixed:
+ + VLD does not report memory leaks that are the result of a failure to free
+ memory allocated via a call to realloc().
+ + In multithreaded programs, if the program's main thread terminates before
+ other threads in the same process, then VLD may cause an access violation
+ while checking for memory leaks.
+ + If VLD cannot find the source file and line number information for a program
+ address, the last known file and line number will be repeated in the call
+ stack section of the memory leak report. The correct behavior should be for
+ VLD to print "File and line number not available" for that call stack entry.
+
+
+0.9h beta (22 April 2005)
+-------------------------
+ Bugs Fixed:
+ + Access Violations occur at random places within the VLD code when using
+ VLD version 0.9g.
+ + When using VLD version 0.9g, VLD may fail to report some memory leaks.
+
+
+0.9g beta (22 April 2005)
+-------------------------
+ New Features/Enhancements:
+ + Replaced the temporary internal search algorithm with a permanent search
+ algorithm that is much faster. Programs that dynamically allocate a large
+ number of memory blocks (tens of thousands or more) will see the most
+ significant performance boost from this version of VLD versus the previous
+ version. Overall, this is the fastest version of VLD released to date.
+
+
+0.9f beta (13 April 2005)
+-------------------------
+ New Features/Enhancements:
+ + Changed the internal search algorithm to a temporary simpler, but
+ more stable algorithm. A permanent algorithm which should be much
+ more efficient will be in a forthcoming release.
+
+ Bugs Fixed:
+ + Access Violation at line 319 in vldutil.cpp may occur when running a
+ program linked with the VLD library.
+
+
+0.9e beta (12 April 2005)
+-------------------------
+ New Features/Enhancements:
+ + VLD no longer uses any STL containers or STL strings. This solves all of the
+ compatibility problems with Visual Studio .NET when using the pre-built
+ VLD libraries.
+
+ + The configuration preprocessor macros now work with C programs without the
+ need to call VLDConfigure from within the program being debugged.
+ Because VLDConfigure is now obsolete, it has been removed.
+
+ + One new source file (vldutil.cpp) and one new header (vldutil.h) have been
+ added. They contain utility functions and utility classes that replace
+ functionality previously performed by STL containers and strings.
+
+ + The VisualLeakDetector global class object is now constructed at C runtime
+ initialization (i.e. it resides in the "compiler" initialization area).
+ Because VLD no longer uses any STL components, there is no longer the risk
+ that VLD will conflict with any STL libraries that also are constructed at
+ C runtime initialization. The end result is that VLD starts running earlier
+ and is destroyed later, which leads to more accurate leak detection.
+
+ Bugs Fixed:
+ + Linking to the VLD 0.9d libraries from the VLD distribution under Visual
+ Studio .NET results in a number of linker "unresolved external symbol"
+ errors. Unresolved symbols include "__declspec(dllimport) void __cdecl
+ std::_Xran(void)" and "__declspec(dllimport) private: void __thiscall
+ std::basic_string,class std::allocator >::_Eos(unsigned int)", among others.
+
+ + Call stacks do not appear in the memory leak report when linking against
+ release VLD libraries built from source with Visual Studio .NET.
+
+ + If the preprocessor macro VLD_MAX_DATA_DUMP is defined as 0 (zero), then VLD
+ will get stuck in an infinite loop, repeatedly printing the same information
+ while attempting to display the memory leak report in the debugger's output
+ window.
+
+
+0.9d beta (30 March 2005)
+-------------------------
+ New Features/Enhancements:
+ + This version of VLD brings with it some major changes to the way VLD
+ interfaces with programs that use it. Instead of requiring that VLD be built
+ from source and then linked with the application, VLD is now packaged as a
+ pre-built static library. For those who just want to use VLD and are not
+ interested in modifying the source, this eliminates the complexities of
+ building VLD from source. A single header file, vld.h, has been added. To
+ link with the static library, this header needs to be included in one of the
+ program's source files. Please see the README.txt file for details on how
+ these changes affect how to use Visual Leak Detector.
+
+ + The Microsoft Debug Help Library (dbghelp.dll) version 6.3 is now included
+ with the VLD distribution.
+
+
+0.9c beta (17 March 2005)
+-------------------------
+ Bugs Fixed:
+ + Compile error, "error C2039: 'size' : is not a member of '_CrtMemBlockHeader'"
+ occurs at line 644 of vld.cpp when building VLD with the VLD_MAX_DATA_DUMP
+ preprocessor macro defined.
+
+
+0.9b beta (15 March 2005)
+-------------------------
+ Bugs Fixed:
+ + VLD fails to detect memory leaks in class constructors if the objects
+ constructed are global objects.
+
+ + If a debug executable is built with certain compiler optimizations turned on,
+ specifically frame pointer omission optimization or automatic inlining, then
+ theoretically VLD may produce incomplete or inaccurate stack traces or might
+ fail to produce stack traces altogether.
+
+
+0.9a beta (12 March 2005)
+-------------------------
+ Initial Public Release
+
+
+
+
+
+
+
+
+
+
+
+
--- /dev/null
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+\f
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+\f
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+\f
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+\f
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="iso-8859-1"?>\r
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\r
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr">\r
+\r
+<head>\r
+ <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />\r
+\r
+ <style title="Visual Leak Detector" type="text/css" media="screen,print">\r
+ body {\r
+ margin: 0;\r
+ font-family: verdana, sans-serif;\r
+ }\r
+\r
+ #masthead {\r
+ border-width: 0 0 1px 0;\r
+ border-style: solid;\r
+ border-color: #808080;\r
+ color: #ffffff;\r
+ background-color: #3569cc;\r
+ }\r
+\r
+ #content {\r
+ margin: 1em 1em 1em 1em;\r
+ font-size: 10pt;\r
+ }\r
+\r
+ #toc {\r
+ float: right;\r
+ color: #000000;\r
+ background-color: #ffeda5;\r
+ }\r
+\r
+ h1 {\r
+ margin: 0 0 0 0;\r
+ padding: 0.5em 1em 0 1em;\r
+ text-align: right;\r
+ font-size: 24pt;\r
+ font-family: arial, sans-serif;\r
+ }\r
+\r
+ h2 {\r
+ margin-top: 0;\r
+ border-width: 2px;\r
+ border-style: solid;\r
+ border-color: #3569cc;\r
+ padding-left: 1em;\r
+ font-size: 16pt;\r
+ font-family: "trebuchet ms", sans-serif;\r
+ letter-spacing: -1pt;\r
+ color: #000000;\r
+ background-color: #6599fc;\r
+ }\r
+\r
+ h3 {\r
+ font-size: 11pt;\r
+ }\r
+\r
+ li {\r
+ margin-bottom: 1em;\r
+ }\r
+\r
+ #toc h2 {\r
+ margin: 0;\r
+ border-width: 2px 2px 2px 0;\r
+ border-style: solid;\r
+ border-color: #6599fc;\r
+ text-align: center;\r
+ color: #ffffff;\r
+ background-color: #3569cc;\r
+ }\r
+\r
+ #toc ul {\r
+ margin-left: 0;\r
+ padding: 0;\r
+ list-style: none;\r
+ }\r
+\r
+ #toc li {\r
+ margin: 1em;\r
+ }\r
+\r
+ a {\r
+ color: #0000ff;\r
+ background-color: inherit;\r
+ text-decoration:none;\r
+ }\r
+\r
+ a:hover {\r
+ text-decoration: underline;\r
+ }\r
+\r
+ a:visited {\r
+ color: #0000ff;\r
+ background-color: inherit;\r
+ }\r
+\r
+ .api {\r
+ font-size: 12pt;\r
+ font-weight: bold;\r
+ }\r
+\r
+ .code {\r
+ font-family: "courier new", monospace;\r
+ color: #000000;\r
+ background-color: #e0e0e0;\r
+ }\r
+\r
+ .filename {\r
+ font-style: italic;\r
+ }\r
+\r
+ .function {\r
+ font-style: italic;\r
+ }\r
+\r
+ .note {\r
+ margin-left: 2em;\r
+ }\r
+\r
+ .operator {\r
+ font-style: italic;\r
+ }\r
+\r
+ .option {\r
+ font-size: 10pt;\r
+ font-weight: bold;\r
+ }\r
+\r
+ ul.vcsearchpath {\r
+ border-width: 1px;\r
+ border-style: dashed;\r
+ border-color: #000000;\r
+ color: #000000;\r
+ background-color: #ffeda5;\r
+ list-style: none;\r
+ }\r
+\r
+ ul.vcsearchpath li {\r
+ margin-bottom: 0;\r
+ }\r
+\r
+ #slogan {\r
+ margin-bottom: 0;\r
+ padding: 0 1em 1em 1em;\r
+ border-width: 0 0 1px 0;\r
+ border-style: solid;\r
+ border-color: #404040;\r
+ text-align: right;\r
+ font-size: larger;\r
+ font-style: italic;\r
+ color: #6599fc;\r
+ background-color: inherit;\r
+ }\r
+\r
+ #copyright {\r
+ text-align: right;\r
+ font-family: georgia, serif;\r
+ color: #808080;\r
+ background-color: inherit;\r
+ }\r
+\r
+ #compliance {\r
+ text-align: right;\r
+ }\r
+\r
+ #compliance img {\r
+ border: 0;\r
+ }\r
+ \r
+ blockquote {\r
+ font-style: italic;\r
+ }\r
+ </style>\r
+\r
+ <title>Visual Leak Detector (Beta)</title>\r
+\r
+</head>\r
+\r
+\r
+\r
+\r
+<body>\r
+\r
+<div id="masthead">\r
+\r
+<h1>Visual Leak Detector 1.9f (Beta)</h1>\r
+\r
+<p id="slogan">Enhanced Memory Leak Detection for Visual C++</p>\r
+\r
+</div> <!-- #masthead -->\r
+\r
+\r
+\r
+\r
+<div id="content">\r
+\r
+<div id="toc">\r
+\r
+<h2>Table of Contents</h2>\r
+\r
+<ul>\r
+ <li><a href="#intro">Introduction</a></li>\r
+\r
+ <li><a href="#use">Using Visual Leak Detector</a></li>\r
+\r
+ <li><a href="#configure">Configuration Options</a></li>\r
+\r
+ <li><a href="#control">Controlling Leak Detection at Runtime</a></li>\r
+\r
+ <li><a href="#build">Building Visual Leak Detector from Source</a></li>\r
+\r
+ <li><a href="#x64">Windows x64 Support</a></li>\r
+\r
+ <li><a href="#faq">Frequently Asked Questions</a></li>\r
+\r
+ <li><a href="#restrictions">Known Restrictions</a></li>\r
+\r
+ <li><a href="#license">License</a></li>\r
+\r
+ <li><a href="#contact">Contacting the Author</a></li>\r
+</ul>\r
+\r
+</div> <!-- #toc -->\r
+\r
+\r
+\r
+\r
+<h2 id="intro">Introduction</h2>\r
+\r
+<p>Visual C++ provides built-in memory leak detection, but its capabilities are minimal at best. This memory leak\r
+ detector was created as a free alternative to the built-in memory leak detector provided with Visual C++. Here\r
+ are some of Visual Leak Detector's features, none of which exist in the built-in detector:</p>\r
+\r
+<ul>\r
+ <li>Provides a complete stack trace for each leaked block, including source file and line number information when\r
+ available.</li>\r
+\r
+ <li>Detects most, if not all, types of in-process memory leaks including COM-based leaks, and pure Win32 heap-based\r
+ leaks.</li>\r
+\r
+ <li>Selected modules (DLLs or even the main EXE) can be excluded from leak detection.</li>\r
+\r
+ <li>Provides complete data dumps (in hex and ASCII) of leaked blocks.</li>\r
+\r
+ <li>Customizable memory leak report: can be saved to a file or sent to the debugger and can include a variable level\r
+ of detail.</li>\r
+</ul>\r
+\r
+<p>Other after-market leak detectors for Visual C++ are already available. But most of the really popular ones,\r
+ like Purify and BoundsChecker, are very expensive. A few free alternatives exist, but they're often too intrusive,\r
+ restrictive, or unreliable. Visual Leak Detector is currently the only freely available memory leak\r
+ detector for Visual C++ that provides all of the above professional-level features packaged neatly in an easy-to-use\r
+ library.</p>\r
+\r
+<p>Visual Leak Detector is <a href="#license">licensed</a> free of charge as a service to the Windows developer\r
+ community. If you find it to be useful and would like to just say "Thanks!", or you think it stinks and would like to\r
+ say "This thing sucks!", please feel free to <a href="mailto:dmoulding@gmail.com">drop me a note</a>. Or, if you'd\r
+ prefer, you can <a href="#contact">contribute a small donation</a>. Both are very appreciated.</p>\r
+\r
+\r
+\r
+\r
+<h2 id="use">Using Visual Leak Detector</h2>\r
+\r
+<p>This section briefly describes the basics of using Visual Leak Detector (VLD).</p>\r
+\r
+<p><strong>Important! :</strong> Before using VLD with any Visual C++ project, you must first add the Visual Leak\r
+ Detector include and library directories to the Visual C++ include and library directory search paths:</p>\r
+\r
+<ul>\r
+ <li><strong>Visual C++ 8</strong>: Go to Tools -> Options -> Projects and Solutions -> VC++ Directories.\r
+ Select "Include files" from the "Show Directories For" drop-down menu. Add the\r
+ <span class="filename">include</span> subdirectory from the Visual Leak Detector installation directory. Move it\r
+ to the bottom of the list. Then select "Library files" from the drop-down menu and add the\r
+ <span class="filename">lib</span> subdirectory from the Visual Leak Detector installation directory. Again, move\r
+ it to the bottom of the list.</li>\r
+ \r
+ <li><strong>Visual C++ 7</strong>: Go to Project Properties -> C/C++ -> General -> Additional Include\r
+ Directories and add the <span class="filename">include</span> subdirectory from the Visual Leak Detector\r
+ installation directory. Move it to the bottom of the list. Then select Additional Library Directories and add\r
+ the <span class="filename">lib</span> subdirectory from the Visual Leak Detector installation directory. Again,\r
+ move it to the bottom of the list.</li>\r
+\r
+ <li><strong>Visual C++ 6</strong>: Go to Tools -> Options -> Directories. Select "Include files" from\r
+ the "Show Directories For" drop-down menu. Add the <span class="filename">include</span> subdirectory\r
+ from the Visual Leak Detector installation directory. Move it to the bottom of the list. Then select "Library\r
+ files" from the drop-down menu and add the <span class="filename">lib</span> subdirectory from the Visual Leak\r
+ Detector installation directory. Again, move it to the bottom of the list.</li>\r
+</ul>\r
+ \r
+<p>To use VLD with your project, follow these simple steps:</p>\r
+\r
+<ol>\r
+ <li>In at least one C/C++ source file from your program, include the <span class="filename">vld.h</span> header\r
+ file. It should not matter which file you add the include statement to. It also should not matter in what order\r
+ the header is included in relation to other headers. The only exception is\r
+ <span class="filename">stdafx.h</span> (or any other precompiled header). A precompiled header, such as\r
+ <span class="filename">stdafx.h</span>, must always be the first header included in a source file, so\r
+ <span class="filename">vld.h</span> must be included after any precompiled headers.</li>\r
+\r
+ <li>If your program contains one or more DLLs that you would also like to check for memory leaks, then also include\r
+ <span class="filename">vld.h</span> in at least one source file from each DLL to be included in leak\r
+ detection.</li>\r
+\r
+ <li>Build the debug version of your program.</li>\r
+</ol>\r
+\r
+<p class="note"><strong>Note:</strong> Unlike earlier (pre-1.9) versions of VLD, it is now acceptable to include\r
+ <span class="filename">vld.h</span> in every source file, or to include it in a common header that is included by\r
+ many or all source files. Only one copy of the VLD code will be loaded into the process, regardless of how many\r
+ source files include <span class="filename">vld.h</span>.</p>\r
+\r
+<p>VLD will detect memory leaks in your program whenever you run the debug version. When you run the program under the\r
+ Visual C++ debugger, a report of all the memory leaks detected will be displayed in the debugger's output window\r
+ when your program exits (the report can optionally be saved to a file instead, see\r
+ <span class="option">ReportFile</span> under <a href="#configure">Configuration Options</a>). Double-clicking on a\r
+ source file's line number in the memory leak report will take you to that file and line in the editor window,\r
+ allowing easy navigation of the code path leading up to the allocation that resulted in the memory leak.</p>\r
+\r
+<p class="note"><strong>Note:</strong> When you build release versions of your program, VLD will not be linked into the\r
+ executable. So it is safe to leave <span class="filename">vld.h</span> included in your source files when doing\r
+ release builds. Doing so will not result in any performance degradation or any other undesirable overhead.</p>\r
+\r
+\r
+\r
+\r
+<h2 id="configure">Configuration Options</h2>\r
+\r
+<p>There are a several configuration options that control specific aspects of VLD's operation. These configuration\r
+ options are stored in the <span class="filename">vld.ini</span> configuration file. By default, the configuration\r
+ file should be in the Visual Leak Detector installation directory. However, the configuration file can be copied to\r
+ the program's working directory, in which case the configuration settings in that copy of\r
+ <span class="filename">vld.ini</span> will apply only when debugging that one program.</p>\r
+\r
+<dl>\r
+ <dt class="option">VLD</dt>\r
+ <dd>\r
+ <p>This option acts as a master on/off switch. By default, this option is set to "on". To <em>completely\r
+ disable</em> Visual Leak Detector at runtime, set this option to "off". When VLD is turned off using this\r
+ option, it will do nothing but print a message to the debugger indicating that it has been turned off.</p>\r
+ </dd>\r
+ \r
+ <dt class="option">AggregateDuplicates</dt>\r
+ <dd>\r
+ <p>Normally, VLD displays each individual leaked block in detail. Setting this option to "yes" will make VLD\r
+ aggregate all leaks that share the same size and call stack under a single entry in the memory leak report.\r
+ Only the first leaked block will be reported in detail. No other identical leaks will be displayed. Instead,\r
+ a tally showing the total number of leaks matching that size and call stack will be shown. This can be useful\r
+ if there are only a few sources of leaks, but those few sources are repeatedly leaking a very large number of\r
+ memory blocks.</p>\r
+ </dd>\r
+\r
+ <dt class="option">ForceIncludeModules</dt>\r
+ <dd>\r
+ <p>In some rare cases, it may be necessary to include a module in leak detection, but it may not be possible to\r
+ include <span class="filename">vld.h</span> in any of the module's sources. In such cases, this option can be\r
+ used to force VLD to include those modules in leak detection. List the names of the modules (DLLs) to be\r
+ forcefully included in leak detection. If you do use this option, it's advisable to also add\r
+ <span class="filename">vld.lib</span> to the list of library modules in the linker options of your project's\r
+ settings.</p>\r
+\r
+ <p class="note"><strong>Caution:</strong> Use this option only when absolutely necessary. In some situations,\r
+ use of this option may result in unpredictable behavior including false leak reports and/or crashes. It's\r
+ best to stay away from this option unless you are sure you understand what you are doing.</p>\r
+ </dd>\r
+\r
+ <dt class="option">MaxDataDump</dt>\r
+ <dd>\r
+ <p>Set this option to an integer value to limit the amount of data displayed in memory block data dumps. When\r
+ this number of bytes of data have been dumped, the dump will stop. This can be useful if any of the leaked\r
+ blocks are very large and the debugger's output window becomes too cluttered. You can set this option to 0\r
+ (zero) if you want to suppress data dumps altogether.</p>\r
+ </dd>\r
+\r
+ <dt class="option">MaxTraceFrames</dt>\r
+ <dd>\r
+ <p>By default, VLD will trace the call stack for each allocated block as far back as possible. Each frame traced\r
+ adds additional overhead (in both CPU time and memory usage) to your debug executable. If you'd like to limit\r
+ this overhead, you can define this macro to an integer value. The stack trace will stop when it has traced\r
+ this number of frames. The frame count may include some of the "internal" frames which, by default, are not\r
+ displayed in the debugger's output window (see <span class="option">TraceInternalFrames</span> below). In\r
+ some cases there may be about three or four "internal" frames at the beginning of the call stack. Keep this\r
+ in mind when using this macro, or you may not see the number of frames you expect.</p>\r
+ </dd>\r
+\r
+ <dt class="option">ReportEncoding</dt>\r
+ <dd>\r
+ <p>When the memory leak report is saved to a file, the report may optionally be Unicode encoded instead of using\r
+ the default ASCII encoding. This might be useful if the data contained in leaked blocks is likely to consist\r
+ of Unicode text. Set this option to "unicode" to generate a Unicode encoded report.</p>\r
+ </dd>\r
+\r
+ <dt class="option">ReportFile</dt>\r
+ <dd>\r
+ <p>Use this option to specify the name and location of the file in which to save the memory leak report when\r
+ using a file as the report destination, as specified by the <span class="option">ReportTo</span> option. If\r
+ no file is specified here, then VLD will save the report in a file named "memory_leak_report.txt" in the\r
+ working directory of the program.</p>\r
+ </dd>\r
+\r
+ <dt class="option">ReportTo</dt>\r
+ <dd>\r
+ <p>The memory leak report may be sent to a file in addition to, or instead of, the debugger. Use this option to\r
+ specify which type of destination to use. Specify one of "debugger" (the default), "file", or "both".</p>\r
+ </dd>\r
+\r
+ <dt class="option">SelfTest</dt>\r
+ <dd>\r
+ <p>VLD has the ability to check itself for memory leaks. This feature is always active. Every time you run VLD,\r
+ in addition to checking your own program for memory leaks, it is also checking itself for leaks. Setting this\r
+ option to "on" forces VLD to intentionally leak a small amount of memory: a 21-character block filled with\r
+ the text "Memory Leak Self-Test". This provides a way to test VLD's ability to check itself for memory leaks\r
+ and verify that this capability is working correctly. This option is usually only useful for debugging VLD\r
+ itself.</p>\r
+ </dd>\r
+ \r
+ <dt class="option">SlowDebuggerDump</dt>\r
+ <dd>\r
+ <p>If enabled, this option causes Visual Leak Detector to write the memory leak report to the debugger's output\r
+ window at a slower than normal rate. This option is specifically designed to work around a known issue with\r
+ some older versions of Visual Studio where some data sent to the output window might be lost if it is sent\r
+ too quickly. If you notice that some information seems to be missing from the memory leak report, try turning\r
+ this on.</p>\r
+ </dd>\r
+\r
+ <dt class="option">StackWalkMethod</dt>\r
+ <dd>\r
+ <p>Selects the method to be used for walking the stack to obtain call stacks for allocated memory blocks. The\r
+ default "fast" method may not always be able to successfully trace completely through all call stacks. In\r
+ such cases, the "safe" method may prove to be more reliable in obtaining the full stack trace. The\r
+ disadvantage with the "safe" method is that it is significantly slower than the "fast" method and will\r
+ probably result in very noticeable performance degradation of the program being debugged. In most cases it\r
+ should be okay to leave this option set to "fast". If you experience problems getting VLD to show call\r
+ stacks, you can try setting this option to "safe".</p>\r
+\r
+ <p>If you do use the "safe" method, and notice a significant performance decrease, you may want to consider\r
+ using the <span class="option">MaxTraceFrames</span> option to limit the number of frames traced to a\r
+ relatively small number. This can reduce the amount of time spent tracing the stack by a very large\r
+ amount.</p>\r
+ </dd>\r
+\r
+ <dt class="option">StartDisabled</dt>\r
+ <dd>\r
+ <p>Set this option to "yes" to disable memory leak detection initially. This can be useful if you need to be\r
+ able to selectively enable memory leak detection from runtime, without needing to rebuild the executable;\r
+ however, this option should be used with caution. Any memory leaks that may occur before memory leak\r
+ detection is enabled at runtime will go undetected. For example, if the constructor of some global variable\r
+ allocates memory before execution reaches a subsequent call to <span class="function">VLDEnable</span>, then\r
+ VLD will not be able to detect if the memory allocated by the global variable is never freed. Refer to the\r
+ following section on <a href="#control">controlling leak detection at runtime</a> for details on using the\r
+ runtime APIs which can be useful in conjunction with this option.</p>\r
+ </dd>\r
+\r
+ <dt class="option">TraceInternalFrames</dt>\r
+ <dd>\r
+ <p>This option determines whether or not all frames of the call stack, including frames internal to the heap,\r
+ are traced. There will always be a number of frames on the call stack which are internal to Visual Leak\r
+ Detector and C/C++ or Win32 heap APIs that aren't generally useful for determining the cause of a leak.\r
+ Normally these frames are skipped during the stack trace, which somewhat reduces the time spent tracing and\r
+ amount of data collected and stored in memory. Including all frames in the stack trace, all the way down into\r
+ VLD's own code can, however, be useful for debugging VLD itself.</p>\r
+ </dd>\r
+</dl>\r
+\r
+\r
+\r
+\r
+<h2 id="control">Controlling Leak Detection at Runtime</h2>\r
+\r
+<p>Using the default configuration, VLD's memory leak detection will be enabled during the entire run of your program.\r
+ In certain scenarios it may be desirable to selectively disable memory leak detection in certain segments of your\r
+ code. VLD provides simple APIs for controlling the state of memory leak detection at runtime. To access these APIs,\r
+ include <span class="filename">vld.h</span> in the source file that needs to use them.</p>\r
+\r
+<dl>\r
+ <dt class="api">VLDDisable</dt>\r
+ <dd>\r
+ <p>This function disables memory leak detection. After calling this function, memory leak detection will remain\r
+ disabled until it is explicitly re-enabled via a call to VLDEnable.</p>\r
+\r
+ <pre class="code">void VLDDisable (void);</pre>\r
+\r
+ <h3>Arguments:</h3>\r
+\r
+ <p>This function accepts no arguments.</p>\r
+\r
+ <h3>Return Value:</h3>\r
+\r
+ <p>None (this function always succeeds).</p>\r
+\r
+ <h3>Notes:</h3>\r
+\r
+ <p>This function controls memory leak detection on a per-thread basis. In other words, calling this function\r
+ disables memory leak detection for only the thread that called the function. Memory leak detection will\r
+ remain enabled for any other threads in the same process. This insulates the programmer from having to\r
+ synchronize multiple threads that disable and enable memory leak detection. However, note also that this\r
+ means that in order to disable memory leak detection process-wide, this function must be called from every\r
+ thread in the process.</p>\r
+ </dd>\r
+\r
+\r
+ <dt class="api">VLDEnable</dt>\r
+ <dd>\r
+ <p>This function enables memory leak detection if it was previously disabled. After calling this function,\r
+ memory leak detection will remain enabled unless it is explicitly disabled again via a call to\r
+ VLDDisable().</p>\r
+\r
+ <pre class="code">void VLDEnable (void);</pre>\r
+\r
+ <h3>Arguments:</h3>\r
+\r
+ <p>This function accepts no arguments.</p>\r
+\r
+ <h3>Return Value:</h3>\r
+\r
+ <p>None (this function always succeeds).</p>\r
+\r
+ <h3>Notes:</h3>\r
+\r
+ <p>This function controls memory leak detection on a per-thread basis. See the remarks for\r
+ <span class="function">VLDDisable</span> regarding multithreading and memory leak detection for details.\r
+ Those same concepts also apply to this function.</p>\r
+ </dd>\r
+</dl>\r
+\r
+\r
+\r
+\r
+<h2 id="build">Building Visual Leak Detector from Source</h2>\r
+\r
+<p>Because Visual Leak Detector is open source, it can be built from source if you want to tweak it to your\r
+ liking. The most difficult part about building VLD from source is getting your build environment correctly set up.\r
+ But if you follow these instructions carefully, the process should be fairly painless.</p>\r
+\r
+<ol>\r
+ <li>VLD depends on the Debug Help Library. This library is part of\r
+ <a href="http://www.microsoft.com/whdc/devtools/debugging/default.mspx">Debugging Tools for Windows</a> (DTfW).\r
+ Download and install DTfW in order to install the required headers and libraries. I recommend installing version\r
+ 6.5 of DTfW. Newer versions may also work, but older versions will probably not work. Be sure to manually select\r
+ to install the SDK files during the DTfW installation or the headers and libraries will not be installed (they\r
+ are not installed with a default installation).</li>\r
+\r
+ <li>Visual C++ will need to be made aware of where it can find the Debug Help Library header and library files.\r
+ Add the <span class="filename">sdk\inc</span> and <span class="filename">sdk\lib</span> subdirectories from the\r
+ DTfW installation directory to the include and library search paths in Visual C++. (See the section above\r
+ on <a href="#use">using Visual Leak Detector</a> on instructions for adding to these search paths).\r
+ </li>\r
+\r
+ <li>VLD also requires a reasonably up-to-date Platform SDK. It is known to work with the latest SDK (as of this\r
+ writing) which is the Windows Server 2003 R2 SDK. It should also work with earlier SDKs, such as the Windows XP\r
+ SP2 SDK or may even work with SDKs as old as the February 2003 SDK. If in doubt,\r
+ <a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=A55B6B43-E24F-4EA3-A93E-40C0EC4F68E5&displaylang=en">update\r
+ your Platform SDK</a> to the latest version.</li>\r
+\r
+ <li>Again, Visual C++ will need to know where to find the Platform SDK headers and libraries. Add the\r
+ <span class="filename">Include</span> and <span class="filename">Lib</span> subdirectories from the\r
+ Platform SDK installation directory to the Include and Library search paths, respectively. The\r
+ Platform SDK directories should be placed just after the DTfW directories.</li>\r
+</ol>\r
+\r
+<p>To summarize, your Visual C++ include search path should look something like this:</p>\r
+\r
+<ul class="vcsearchpath">\r
+ <li>C:\Program Files\Debugging Tools for Windows\sdk\inc</li>\r
+\r
+ <li>C:\Program Files\Microsoft Platform SDK\Include</li>\r
+\r
+ <li>C:\Program Files\Microsoft Visual Studio\VCx\Include</li>\r
+ \r
+ <li>...</li>\r
+</ul>\r
+\r
+<p>And your Visual C++ library search path should look like this:</p>\r
+\r
+<ul class="vcsearchpath">\r
+ <li>C:\Program Files\Debugging Tools for Windows\sdk\lib</li>\r
+\r
+ <li>C:\Program Files\Microsoft Platform SDK\Lib</li>\r
+\r
+ <li>C:\Program Files\Microsoft Visual Studio\VCx\Lib</li>\r
+ \r
+ <li>...</li>\r
+</ul>\r
+\r
+<p>In the above examples, "VCx" could be "VC", "VC7", or "VC98" (or possibly other values) depending on which version of\r
+ Visual Studio you have installed. Also, the name of your Platform SDK directory will probably be different from\r
+ the example depending on which version of the Platform SDK you have installed.</p>\r
+\r
+<p>Once you have completed all of the above steps, your build environment should be ready. To build VLD, just open the\r
+ <span class="filename">vld.sln</span> solution file and do a full build.</p>\r
+\r
+<p>When actually running the built project, <span class="filename">vld.dll</span> will expect to find the Debug Help\r
+ Library as a private assembly. The private assembly must be located in the same directory as\r
+ <span class="filename">vld.dll</span> (either the <span class="filename">Release</span> or\r
+ <span class="filename">Debug</span> directory by default). Otherwise, when VLD is loaded, an error message will pop\r
+ up indicating that the program failed to initialize, and you will see a message similar to the following in the\r
+ debugger's output window:</p>\r
+ <blockquote><p>LDR: LdrpWalkImportDescriptor() failed to probe C:\Projects\vld\Release\vld.dll for its manifest,\r
+ ntstatus 0xc0150002</p></blockquote>\r
+ \r
+<p>To ensure that <span class="filename">vld.dll</span> finds the required private assembly, you need to copy\r
+ <span class="filename">dbghelp.dll</span> and <span class="filename">Microsoft.DTfW.DHL.manifest</span> to the\r
+ same directory that <span class="filename">vld.dll</span> is in.</p>\r
+\r
+\r
+\r
+\r
+<h2 id="x64">Windows x64 Support</h2>\r
+\r
+<p>The VLD source code has been modified to add support for x64-based 64-bit Windows. However, the binary contained in\r
+ the distributed version of VLD is 32-bit only. To take advantage of the 64-bit support, you'll need to build a 64-bit\r
+ version of VLD from source. To build the 64-bit version, follow the instructions for <a href="#build">building VLD\r
+ from source</a>. So long as it is built using a x64-compatible compiler in 64-bit mode, the resulting DLL will be a\r
+ 64-bit binary.</p>\r
+\r
+<p class="note"><strong>Note:</strong> I have not personally tested the 64-bit extensions so they are not absolutely\r
+ guaranteed to work out-of-the-box. There may be a few lingering 64-bit compiler errors that still need to be worked\r
+ out. If you need 64-bit support and run into problems trying to build the source in 64-bit mode, please\r
+ <a href="mailto:dmoulding@gmail.com">let me know</a>. I'll be glad to assist in getting the 64-bit code working\r
+ properly.</p>\r
+\r
+\r
+\r
+\r
+<h2 id="faq">Frequently Asked Questions</h2>\r
+\r
+<dl>\r
+ <dt>When I try to compile my program with VLD, it fails and the compiler gives this error: <strong>Cannot open include file:\r
+ 'vld.h': No such file or directory</strong>.</dt>\r
+ <dd>\r
+ <p>The compiler can't find the header file that VLD installed. This probably means that VLD's include\r
+ subdirectory has not been added to the Visual C++ include search path. See the section above about\r
+ <a href="#use">Using Visual Leak Detector</a> for instructions on how to add VLD's directories to the search\r
+ path.</p>\r
+ </dd>\r
+ <dt>In the memory leak report, the callstack contains many lines that say\r
+ <strong>"File and line number unvailable"</strong> or <strong>"Function name unavailable"</strong>.</dt>\r
+ <dd>\r
+ <p>This may mean that VLD couldn't find the symbol database for your program. The symbol database is ususally in\r
+ a file named <span class="filename">[my-program-name].pdb</span>. If this file is not located in the same\r
+ directory as the program itself, then VLD will probably not find it and can't show any file or function\r
+ names.</p>\r
+ </dd>\r
+</dl>\r
+\r
+\r
+\r
+\r
+<h2 id="restrictions">Known Restrictions</h2>\r
+\r
+<p>Known restrictions/limitations in this version of VLD include:</p>\r
+\r
+<ul>\r
+ <li>Memory allocations made through calls to functions loaded from a DLL using delayed loading may not be\r
+ detected.</li> \r
+\r
+ <li>Support for programs that use MFC 7.0 or MFC 7.1 is not complete yet. Some memory leaks from such MFC-based\r
+ programs may not be detected. A possible workaround for this restriction is to try forcefully including the MFC\r
+ DLLs in memory leak detection, by setting the <span class="option">ForceIncludeModules</span> configuration\r
+ option to: "mfc70d.dll mfc71d.dll" and explicitly adding <span class="filename">vld.lib</span> as an input file\r
+ on the linker command line (can be added through project settings by adding it to the list of library modules in\r
+ the linker options). This restriction does not apply to programs that use MFC 4.2 or MFC 8.0 which are both fully\r
+ supported.</li>\r
+ \r
+ <li>Visual Leak Detector may report leaks internal to Visual Leak Detector if the main thread of the process\r
+ terminates while other threads are still running.</li>\r
+ \r
+ <li>On Windows 2000 and earlier operating systems, you may need to manually add the\r
+ <span class="filename">bin\Microsoft.VC80.CRT</span> subdirectory from the Visual Leak Detector installation\r
+ directory to the system PATH environment variable. Also, <span class="filename">dbghelp.dll</span> will probably\r
+ need to be manually copied to the directory where the program being debugged resides. Otherwise the system may\r
+ not find the required DLLs when running VLD.</li>\r
+ \r
+ <li>If more than one copy of the same C Runtime DLL is loaded in the process at the same time, then some leaks may\r
+ go undetected (note that loading more than one copy of the C Runtime DLL at the same time is probably a bad idea\r
+ to begin with).</li>\r
+</ul>\r
+\r
+\r
+\r
+\r
+<h2 id="license">License</h2>\r
+\r
+<p>Visual Leak Detector is distributed under the terms of the\r
+ <a href="http://www.gnu.org/copyleft/lesser.html">GNU Lesser General Public License</a>. This license allows you to\r
+ use the VLD library with your own programs without restriction. However, if you build a program (or another library)\r
+ that is <em>based</em> on the VLD source code, or uses parts of the VLD source code in it, then some restrictions\r
+ will apply. What this means is that you are free to ship and use the distributed version of the VLD DLL with regular\r
+ commercial programs. But if you create a modified version of VLD, that modified version must remain "free software".\r
+ See the <span class="filename"><a href="COPYING.txt">COPYING.txt</a></span> file for details.</p>\r
+\r
+<p>The Debug Help Library (<span class="filename">dbghelp.dll</span>) and Microsoft C Runtime Library\r
+ (<span class="filename">msvcr80.dll</span>) distributed with this software are not part of\r
+ Visual Leak Detector and are not covered under the terms of the GNU Lesser General Public License. They are\r
+ separately copyrighted works of Microsoft Corporation. Microsoft reserves all its rights to its copyrights in the\r
+ Debug Help Library and Microsoft C Runtime Library. Neither your use of the Visual Leak Detector software,\r
+ nor your license under the GNU Lesser General Public license grant you any rights to use the Debug Help Library or\r
+ Microsoft C Runtime Library in <strong>ANY WAY</strong> (for example, redistributing them) that would infringe upon\r
+ Microsoft Corporation's copyright in the Debug Help Library or Microsoft C Runtime Library.</p>\r
+\r
+<h3>NO WARRANTY</h3>\r
+\r
+<p>BECAUSE VISUAL LEAK DETECTOR ("THE SOFTWARE") IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE SOFTWARE, TO\r
+ THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER\r
+ PARTIES PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT\r
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE\r
+ QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL\r
+ NECESSARY SERVICING, REPAIR OR CORRECTION.</p>\r
+\r
+<p>IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY\r
+ WHO MAY MODIFY AND/OR REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE LICENSING TERMS SET FORTH ABOVE, BE LIABLE TO YOU\r
+ FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY\r
+ TO USE THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED\r
+ BY YOU OR THIRD PARTIES OR A FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR\r
+ OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</p>\r
+\r
+\r
+\r
+\r
+<h2 id="contact">Contacting the Author</h2>\r
+\r
+<p>Please forward any bug reports, questions, comments or suggestions to me at\r
+<a href="mailto:dmoulding@gmail.com">dmoulding@gmail.com.</a></p>\r
+\r
+<p>Donations to help support ongoing development of Visual Leak Detector are very appreciated!</p>\r
+\r
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">\r
+ <div>\r
+ <input type="hidden" name="cmd" value="_s-xclick" />\r
+ <input type="image" src="https://www.paypal.com/en_US/i/btn/x-click-but21.gif" name="submit" alt="Make payments with PayPal - it's fast, free and secure!" />\r
+ <input type="hidden" name="encrypted" value="-----BEGIN PKCS7-----MIIHJwYJKoZIhvcNAQcEoIIHGDCCBxQCAQExggEwMIIBLAIBADCBlDCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb20CAQAwDQYJKoZIhvcNAQEBBQAEgYB96070OV1fBDnfqkGvVtR2bQf+WKQk1DquH9rhxL3QPke1DxmckKvbKQwjqYRjZN+FbaFky71Lz75RsdeJHKcxgcJWw6cMYOI2xrmsa4Vjp00iOPjKGpMBE7roPqnnZT7l36wBBVk7Hbnm8A3MHsqTQXN9/S/rbngN57tANCbsRTELMAkGBSsOAwIaBQAwgaQGCSqGSIb3DQEHATAUBggqhkiG9w0DBwQIfRWj6EIw0C+AgYCtBQ3JuPXxq/j/RpOCteLqJqyePyFExF3ic44Doj4py33hRo9EqJrSUTbigQVT2eHkwQWS9Exs8L9aeBQQahsZNbUCyLgqPvXOOG/Zk+5Xj/2m2oBZ5AMW8rdPVCYJ7NhAc92aiU2yObd/I8n4mLGDRf768HhASKwe/LGmZiH2bKCCA4cwggODMIIC7KADAgECAgEAMA0GCSqGSIb3DQEBBQUAMIGOMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxFDASBgNVBAoTC1BheVBhbCBJbmMuMRMwEQYDVQQLFApsaXZlX2NlcnRzMREwDwYDVQQDFAhsaXZlX2FwaTEcMBoGCSqGSIb3DQEJARYNcmVAcGF5cGFsLmNvbTAeFw0wNDAyMTMxMDEzMTVaFw0zNTAyMTMxMDEzMTVaMIGOMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxFDASBgNVBAoTC1BheVBhbCBJbmMuMRMwEQYDVQQLFApsaXZlX2NlcnRzMREwDwYDVQQDFAhsaXZlX2FwaTEcMBoGCSqGSIb3DQEJARYNcmVAcGF5cGFsLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwUdO3fxEzEtcnI7ZKZL412XvZPugoni7i7D7prCe0AtaHTc97CYgm7NsAtJyxNLixmhLV8pyIEaiHXWAh8fPKW+R017+EmXrr9EaquPmsVvTywAAE1PMNOKqo2kl4Gxiz9zZqIajOm1fZGWcGS0f5JQ2kBqNbvbg2/Za+GJ/qwUCAwEAAaOB7jCB6zAdBgNVHQ4EFgQUlp98u8ZvF71ZP1LXChvsENZklGswgbsGA1UdIwSBszCBsIAUlp98u8ZvF71ZP1LXChvsENZklGuhgZSkgZEwgY4xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLUGF5UGFsIEluYy4xEzARBgNVBAsUCmxpdmVfY2VydHMxETAPBgNVBAMUCGxpdmVfYXBpMRwwGgYJKoZIhvcNAQkBFg1yZUBwYXlwYWwuY29tggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAgV86VpqAWuXvX6Oro4qJ1tYVIT5DgWpE692Ag422H7yRIr/9j/iKG4Thia/Oflx4TdL+IFJBAyPK9v6zZNZtBgPBynXb048hsP16l2vi0k5Q2JKiPDsEfBhGI+HnxLXEaUWAcVfCsQFvd2A1sxRr67ip5y2wwBelUecP3AjJ+YcxggGaMIIBlgIBATCBlDCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbi\r
+BWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb20CAQAwCQYFKw4DAhoFAKBdMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTA1MDgwMTE5NDQ0NlowIwYJKoZIhvcNAQkEMRYEFKLDwHJFsU6L329159saLBrfszYcMA0GCSqGSIb3DQEBAQUABIGAe4Mjshnc1RvJU9zF6nL8zPJ+nHO2ct1CbS1WFkQMWvh2NTwlIVSZFWSLJQZ32kNoyseoxUvE587qdBKyMOATXjchDeMr1y815+GWE6Ffqw3rWw/ytfVEtEJd4yUUq0gHqFACul4nWM5zP5A3zkLZEVN3gAmX1eLbMIcSCKuVafM=-----END PKCS7-----" />\r
+ </div>\r
+</form>\r
+\r
+<p id="compliance">\r
+ <a href="http://validator.w3.org"><img src="http://www.w3.org/Icons/valid-xhtml10" alt="Valid XHTML 1.0!" height="31" width="88" /></a>\r
+ <a href="http://jigsaw.w3.org/css-validator"><img id="valid-css" src="http://jigsaw.w3.org/css-validator/images/vcss" alt="Valid CSS!" /></a>\r
+</p>\r
+\r
+<p id="copyright">Copyright © 2005-2006 Dan Moulding</p>\r
+\r
+</div> <!-- #content -->\r
+\r
+</body>\r
+\r
+</html>
\ No newline at end of file
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////
+// $Id: vld.h,v 1.29 2006/11/18 03:12:35 dmouldin Exp $
+//
+// Visual Leak Detector - Import Library Header
+// Copyright (c) 2006 Dan Moulding
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+//
+// See COPYING.txt for the full terms of the GNU Lesser General Public License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#ifdef _DEBUG
+
+#pragma comment(lib, "vld.lib")
+
+// Force a symbolic reference to the global VisualLeakDetector class object from
+// the DLL. This enusres that the DLL is loaded and linked with the program,
+// even if no code otherwise imports any of the DLL's exports.
+#pragma comment(linker, "/include:__imp_?vld@@3VVisualLeakDetector@@A")
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Visual Leak Detector APIs
+//
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+// VLDDisable - Disables Visual Leak Detector's memory leak detection at
+// runtime. If memory leak detection is already disabled, then calling this
+// function has no effect.
+//
+// Note: In multithreaded programs, this function operates on a per-thread
+// basis. In other words, if you call this function from one thread, then
+// memory leak detection is only disabled for that thread. If memory leak
+// detection is enabled for other threads, then it will remain enabled for
+// those other threads. It was designed to work this way to insulate you,
+// the programmer, from having to ensure thread synchronization when calling
+// VLDEnable() and VLDDisable(). Without this, calling these two functions
+// unsychronized could result in unpredictable and unintended behavior.
+// But this also means that if you want to disable memory leak detection
+// process-wide, then you need to call this function from every thread in
+// the process.
+//
+// Return Value:
+//
+// None.
+//
+__declspec(dllimport) void VLDDisable ();
+
+// VLDEnable - Enables Visual Leak Detector's memory leak detection at runtime.
+// If memory leak detection is already enabled, which it is by default, then
+// calling this function has no effect.
+//
+// Note: In multithreaded programs, this function operates on a per-thread
+// basis. In other words, if you call this function from one thread, then
+// memory leak detection is only enabled for that thread. If memory leak
+// detection is disabled for other threads, then it will remain disabled for
+// those other threads. It was designed to work this way to insulate you,
+// the programmer, from having to ensure thread synchronization when calling
+// VLDEnable() and VLDDisable(). Without this, calling these two functions
+// unsychronized could result in unpredictable and unintended behavior.
+// But this also means that if you want to enable memory leak detection
+// process-wide, then you need to call this function from every thread in
+// the process.
+//
+// Return Value:
+//
+// None.
+//
+__declspec(dllimport) void VLDEnable ();
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#else // !_DEBUG
+
+#define VLDEnable()
+#define VLDDisable()
+
+#endif // _DEBUG
\ No newline at end of file
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////
+// $Id: callstack.cpp,v 1.20 2006/11/18 03:12:34 dmouldin Exp $
+//
+// Visual Leak Detector - CallStack Class Implementations
+// Copyright (c) 2005-2006 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.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include <cassert>
+#include <windows.h>
+#define __out_xcount(x) // Workaround for the specstrings.h bug in the Platform SDK.
+#define DBGHELP_TRANSLATE_TCHAR
+#include <dbghelp.h> // Provides symbol handling services.
+#define VLDBUILD
+#include "callstack.h" // This class' header.
+#include "utility.h" // Provides various utility functions.
+#include "vldheap.h" // Provides internal new and delete operators.
+#include "vldint.h" // Provides access to VLD internals.
+
+#define MAXSYMBOLNAMELENGTH 256
+
+// Imported global variables.
+extern HANDLE currentprocess;
+extern HANDLE currentthread;
+extern CRITICAL_SECTION stackwalklock;
+extern CRITICAL_SECTION symbollock;
+
+// Constructor - Initializes the CallStack with an initial size of zero and one
+// Chunk of capacity.
+//
+CallStack::CallStack ()
+{
+ m_capacity = CALLSTACKCHUNKSIZE;
+ m_size = 0;
+ m_status = 0x0;
+ m_store.next = NULL;
+ m_topchunk = &m_store;
+ m_topindex = 0;
+}
+
+// Copy Constructor - For efficiency, we want to avoid ever making copies of
+// CallStacks (only pointer passing or reference passing should be performed).
+// The sole purpose of this copy constructor is to ensure that no copying is
+// being done inadvertently.
+//
+CallStack::CallStack (const CallStack &)
+{
+ // Don't make copies of CallStacks!
+ assert(FALSE);
+}
+
+// Destructor - Frees all memory allocated to the CallStack.
+//
+CallStack::~CallStack ()
+{
+ CallStack::chunk_t *chunk = m_store.next;
+ CallStack::chunk_t *temp;
+
+ while (chunk) {
+ temp = chunk;
+ chunk = temp->next;
+ delete temp;
+ }
+}
+
+// operator = - Assignment operator. For efficiency, we want to avoid ever
+// making copies of CallStacks (only pointer passing or reference passing
+// should be performed). The sole purpose of this assignment operator is to
+// ensure that no copying is being done inadvertently.
+//
+CallStack& CallStack::operator = (const CallStack &)
+{
+ // Don't make copies of CallStacks!
+ assert(FALSE);
+ return *this;
+}
+
+// operator == - Equality operator. Compares the CallStack to another CallStack
+// for equality. Two CallStacks are equal if they are the same size and if
+// every frame in each is identical to the corresponding frame in the other.
+//
+// other (IN) - Reference to the CallStack to compare the current CallStack
+// against for equality.
+//
+// Return Value:
+//
+// Returns true if the two CallStacks are equal. Otherwise returns false.
+//
+BOOL CallStack::operator == (const CallStack &other) const
+{
+ const CallStack::chunk_t *chunk = &m_store;
+ UINT32 index;
+ const CallStack::chunk_t *otherchunk = &other.m_store;
+ const CallStack::chunk_t *prevchunk = NULL;
+
+ if (m_size != other.m_size) {
+ // They can't be equal if the sizes are different.
+ return FALSE;
+ }
+
+ // Walk the chunk list and within each chunk walk the frames array until we
+ // either find a mismatch, or until we reach the end of the call stacks.
+ while (prevchunk != m_topchunk) {
+ for (index = 0; index < ((chunk == m_topchunk) ? m_topindex : CALLSTACKCHUNKSIZE); index++) {
+ if (chunk->frames[index] != otherchunk->frames[index]) {
+ // Found a mismatch. They are not equal.
+ return FALSE;
+ }
+ }
+ prevchunk = chunk;
+ chunk = chunk->next;
+ otherchunk = otherchunk->next;
+ }
+
+ // Reached the end of the call stacks. They are equal.
+ return TRUE;
+}
+
+// operator [] - Random access operator. Retrieves the frame at the specified
+// index.
+//
+// Note: We give up a bit of efficiency here, in favor of efficiency of push
+// operations. This is because walking of a CallStack is done infrequently
+// (only if a leak is found), whereas pushing is done very frequently (for
+// each frame in the program's call stack when the program allocates some
+// memory).
+//
+// - index (IN): Specifies the index of the frame to retrieve.
+//
+// Return Value:
+//
+// Returns the program counter for the frame at the specified index. If the
+// specified index is out of range for the CallStack, the return value is
+// undefined.
+//
+SIZE_T CallStack::operator [] (UINT32 index) const
+{
+ UINT32 count;
+ const CallStack::chunk_t *chunk = &m_store;
+ UINT32 chunknumber = index / CALLSTACKCHUNKSIZE;
+
+ for (count = 0; count < chunknumber; count++) {
+ chunk = chunk->next;
+ }
+
+ return chunk->frames[index % CALLSTACKCHUNKSIZE];
+}
+
+// clear - Resets the CallStack, returning it to a state where no frames have
+// been pushed onto it, readying it for reuse.
+//
+// Note: Calling this function does not release any memory allocated to the
+// CallStack. We give up a bit of memory-usage efficiency here in favor of
+// performance of push operations.
+//
+// Return Value:
+//
+// None.
+//
+VOID CallStack::clear ()
+{
+ m_size = 0;
+ m_topchunk = &m_store;
+ m_topindex = 0;
+}
+
+// dump - Dumps a nicely formatted rendition of the CallStack, including
+// symbolic information (function names and line numbers) if available.
+//
+// Note: The symbol handler must be initialized prior to calling this
+// function.
+//
+// - showinternalframes (IN): If true, then all frames in the CallStack will be
+// dumped. Otherwise, frames internal to the heap will not be dumped.
+//
+// Return Value:
+//
+// None.
+//
+VOID CallStack::dump (BOOL showinternalframes) const
+{
+ DWORD displacement;
+ DWORD64 displacement64;
+ BOOL foundline;
+ UINT32 frame;
+ SYMBOL_INFO *functioninfo;
+ LPWSTR functionname;
+ SIZE_T programcounter;
+ IMAGEHLP_LINE64 sourceinfo = { 0 };
+ BYTE symbolbuffer [sizeof(SYMBOL_INFO) + (MAXSYMBOLNAMELENGTH * sizeof(WCHAR)) - 1] = { 0 };
+
+ if (m_status & CALLSTACK_STATUS_INCOMPLETE) {
+ // This call stack appears to be incomplete. Using StackWalk64 may be
+ // more reliable.
+ report(L" HINT: The following call stack may be incomplete. Setting \"StackWalkMethod\"\n"
+ L" in the vld.ini file to \"safe\" instead of \"fast\" may result in a more\n"
+ L" complete stack trace.\n");
+ }
+
+ // Initialize structures passed to the symbol handler.
+ functioninfo = (SYMBOL_INFO*)&symbolbuffer;
+ functioninfo->SizeOfStruct = sizeof(SYMBOL_INFO);
+ functioninfo->MaxNameLen = MAXSYMBOLNAMELENGTH;
+ sourceinfo.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
+
+ // Iterate through each frame in the call stack.
+ for (frame = 0; frame < m_size; frame++) {
+ // Try to get the source file and line number associated with
+ // this program counter address.
+ programcounter = (*this)[frame];
+ EnterCriticalSection(&symbollock);
+ if ((foundline = SymGetLineFromAddrW64(currentprocess, programcounter, &displacement, &sourceinfo)) == TRUE) {
+ if (!showinternalframes) {
+ _wcslwr_s(sourceinfo.FileName, wcslen(sourceinfo.FileName) + 1);
+ if (wcsstr(sourceinfo.FileName, L"afxmem.cpp") ||
+ wcsstr(sourceinfo.FileName, L"dbgheap.c") ||
+ wcsstr(sourceinfo.FileName, L"malloc.c") ||
+ wcsstr(sourceinfo.FileName, L"new.cpp") ||
+ wcsstr(sourceinfo.FileName, L"newaop.cpp")) {
+ // Don't show frames in files internal to the heap.
+ continue;
+ }
+ }
+ }
+
+ // Try to get the name of the function containing this program
+ // counter address.
+ if (SymFromAddrW(currentprocess, (*this)[frame], &displacement64, functioninfo)) {
+ functionname = functioninfo->Name;
+ }
+ else {
+ functionname = L"(Function name unavailable)";
+ }
+ LeaveCriticalSection(&symbollock);
+
+ // Display the current stack frame's information.
+ if (foundline) {
+ report(L" %s (%d): %s\n", sourceinfo.FileName, sourceinfo.LineNumber, functionname);
+ }
+ else {
+ report(L" " ADDRESSFORMAT L" (File and line number not available): ", (*this)[frame]);
+ report(L"%s\n", functionname);
+ }
+ }
+}
+
+// push_back - Pushes a frame's program counter onto the CallStack. Pushes are
+// always appended to the back of the chunk list (aka the "top" chunk).
+//
+// Note: This function will allocate additional memory as necessary to make
+// room for new program counter addresses.
+//
+// - programcounter (IN): The program counter address of the frame to be pushed
+// onto the CallStack.
+//
+// Return Value:
+//
+// None.
+//
+VOID CallStack::push_back (const SIZE_T programcounter)
+{
+ CallStack::chunk_t *chunk;
+
+ if (m_size == m_capacity) {
+ // At current capacity. Allocate additional storage.
+ chunk = new CallStack::chunk_t;
+ chunk->next = NULL;
+ m_topchunk->next = chunk;
+ m_topchunk = chunk;
+ m_topindex = 0;
+ m_capacity += CALLSTACKCHUNKSIZE;
+ }
+ else if (m_topindex == CALLSTACKCHUNKSIZE) {
+ // There is more capacity, but not in this chunk. Go to the next chunk.
+ // Note that this only happens if this CallStack has previously been
+ // cleared (clearing resets the data, but doesn't give up any allocated
+ // space).
+ m_topchunk = m_topchunk->next;
+ m_topindex = 0;
+ }
+
+ m_topchunk->frames[m_topindex++] = programcounter;
+ m_size++;
+}
+
+// getstacktrace - Traces the stack as far back as possible, or until 'maxdepth'
+// frames have been traced. Populates the CallStack with one entry for each
+// stack frame traced.
+//
+// Note: This function uses a very efficient method to walk the stack from
+// frame to frame, so it is quite fast. However, unconventional stack frames
+// (such as those created when frame pointer omission optimization is used)
+// will not be successfully walked by this function and will cause the
+// stack trace to terminate prematurely.
+//
+// - maxdepth (IN): Maximum number of frames to trace back.
+//
+// - framepointer (IN): Frame (base) pointer at which to begin the stack trace.
+// If NULL, then the stack trace will begin at this function.
+//
+// Return Value:
+//
+// None.
+//
+VOID FastCallStack::getstacktrace (UINT32 maxdepth, SIZE_T *framepointer)
+{
+ UINT32 count = 0;
+
+ if (framepointer == NULL) {
+ // Begin the stack trace with the current frame. Obtain the current
+ // frame pointer.
+ FRAMEPOINTER(framepointer);
+ }
+
+ while (count < maxdepth) {
+ if ((SIZE_T*)*framepointer < framepointer) {
+ if ((SIZE_T*)*framepointer == NULL) {
+ // Looks like we reached the end of the stack.
+ break;
+ }
+ else {
+ // Invalid frame pointer. Frame pointer addresses should always
+ // increase as we move up the stack.
+ m_status |= CALLSTACK_STATUS_INCOMPLETE;
+ break;
+ }
+ }
+ if ((SIZE_T)*framepointer & (sizeof(SIZE_T*) - 1)) {
+ // Invalid frame pointer. Frame pointer addresses should always
+ // be aligned to the size of a pointer. This probably means that
+ // we've encountered a frame that was created by a module built with
+ // frame pointer omission (FPO) optimization turned on.
+ m_status |= CALLSTACK_STATUS_INCOMPLETE;
+ break;
+ }
+ if (IsBadReadPtr((SIZE_T*)*framepointer, sizeof(SIZE_T*))) {
+ // Bogus frame pointer. Again, this probably means that we've
+ // encountered a frame built with FPO optimization.
+ m_status |= CALLSTACK_STATUS_INCOMPLETE;
+ break;
+ }
+ count++;
+ push_back(*(framepointer + 1));
+ framepointer = (SIZE_T*)*framepointer;
+ }
+}
+
+// getstacktrace - Traces the stack as far back as possible, or until 'maxdepth'
+// frames have been traced. Populates the CallStack with one entry for each
+// stack frame traced.
+//
+// Note: This function uses a documented Windows API to walk the stack. This
+// API is supposed to be the most reliable way to walk the stack. It claims
+// to be able to walk stack frames that do not follow the conventional stack
+// frame layout. However, this robustness comes at a cost: it is *extremely*
+// slow compared to walking frames by following frame (base) pointers.
+//
+// - maxdepth (IN): Maximum number of frames to trace back.
+//
+// - framepointer (IN): Frame (base) pointer at which to begin the stack trace.
+// If NULL, then the stack trace will begin at this function.
+//
+// Return Value:
+//
+// None.
+//
+VOID SafeCallStack::getstacktrace (UINT32 maxdepth, SIZE_T *framepointer)
+{
+ DWORD architecture;
+ CONTEXT context;
+ UINT32 count = 0;
+ STACKFRAME64 frame;
+ SIZE_T programcounter;
+ SIZE_T stackpointer;
+
+ if (framepointer == NULL) {
+ // Begin the stack trace with the current frame. Obtain the current
+ // frame pointer.
+ FRAMEPOINTER(framepointer);
+ }
+
+ // Get the required values for initialization of the STACKFRAME64 structure
+ // to be passed to StackWalk64(). Required fields are AddrPC and AddrFrame.
+#if defined(_M_IX86) || defined(_M_X64)
+ architecture = X86X64ARCHITECTURE;
+ programcounter = *(framepointer + 1);
+ stackpointer = *framepointer; // An approximation.
+ context.BPREG = *framepointer;
+ context.IPREG = programcounter;
+ context.SPREG = stackpointer;
+#else
+// If you want to retarget Visual Leak Detector to another processor
+// architecture then you'll need to provide architecture-specific code to
+// obtain the program counter and stack pointer from the given frame pointer.
+#error "Visual Leak Detector is not supported on this architecture."
+#endif // _M_IX86 || _M_X64
+
+ // Initialize the STACKFRAME64 structure.
+ memset(&frame, 0x0, sizeof(frame));
+ frame.AddrFrame.Offset = *framepointer;
+ frame.AddrFrame.Mode = AddrModeFlat;
+ frame.AddrPC.Offset = programcounter;
+ frame.AddrPC.Mode = AddrModeFlat;
+ frame.AddrStack.Offset = stackpointer;
+ frame.AddrStack.Mode = AddrModeFlat;
+
+ // Walk the stack.
+ EnterCriticalSection(&stackwalklock);
+ while (count < maxdepth) {
+ count++;
+ if (!StackWalk64(architecture, currentprocess, currentthread, &frame, &context, NULL,
+ SymFunctionTableAccess64, SymGetModuleBase64, NULL)) {
+ // Couldn't trace back through any more frames.
+ break;
+ }
+ if (frame.AddrFrame.Offset == 0) {
+ // End of stack.
+ break;
+ }
+
+ // Push this frame's program counter onto the CallStack.
+ push_back((SIZE_T)frame.AddrPC.Offset);
+ }
+ LeaveCriticalSection(&stackwalklock);
+}
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////
+// $Id: callstack.h,v 1.10 2006/11/18 03:12:34 dmouldin Exp $
+//
+// Visual Leak Detector - CallStack Class Definitions
+// Copyright (c) 2005-2006 Dan Moulding
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+//
+// See COPYING.txt for the full terms of the GNU Lesser General Public License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#ifndef VLDBUILD
+#error \
+"This header should only be included by Visual Leak Detector when building it from source. \
+Applications should never include this header."
+#endif
+
+#include <windows.h>
+
+#define CALLSTACKCHUNKSIZE 32 // Number of frame slots in each CallStack chunk.
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// The CallStack Class
+//
+// CallStack objects can be used for obtaining, storing, and displaying the
+// call stack at a given point during program execution.
+//
+// The primary data structure used by the CallStack is similar in concept to
+// a STL vector, but is specifically tailored for use by VLD, making it more
+// efficient than a standard STL vector.
+//
+// Inside the CallStack are a number of "chunks" which are arranged in a
+// linked list. Each chunk contains an array of frames (each frame is
+// represented by a program counter address). If we run out of space when
+// pushing new frames onto an existing chunk in the CallStack chunk list,
+// then a new chunk is allocated and appended to the end of the list. In this
+// way, the CallStack can grow dynamically as needed. New frames are always
+// pushed onto the chunk at the end of the list known as the "top" chunk.
+//
+class CallStack
+{
+public:
+ CallStack ();
+ CallStack (const CallStack &other);
+ ~CallStack ();
+
+ // Public APIs - see each function definition for details.
+ VOID clear ();
+ VOID dump (BOOL showinternalframes) const;
+ virtual VOID getstacktrace (UINT32 maxdepth, SIZE_T *framepointer) = 0;
+ CallStack& operator = (const CallStack &other);
+ BOOL operator == (const CallStack &other) const;
+ SIZE_T operator [] (UINT32 index) const;
+ VOID push_back (const SIZE_T programcounter);
+
+protected:
+ // Protected data.
+ UINT32 m_status; // Status flags:
+#define CALLSTACK_STATUS_INCOMPLETE 0x1 // If set, the stack trace stored in this CallStack appears to be incomplete.
+
+private:
+ // The chunk list is made of a linked list of Chunks.
+ typedef struct chunk_s {
+ struct chunk_s *next; // Pointer to the next chunk in the chunk list.
+ SIZE_T frames [CALLSTACKCHUNKSIZE]; // Pushed frames (program counter addresses) are stored in this array.
+ } chunk_t;
+
+ // Private data.
+ UINT32 m_capacity; // Current capacity limit (in frames)
+ UINT32 m_size; // Current size (in frames)
+ CallStack::chunk_t m_store; // Pointer to the underlying data store (i.e. head of the chunk list)
+ CallStack::chunk_t *m_topchunk; // Pointer to the chunk at the top of the stack
+ UINT32 m_topindex; // Index, within the top chunk, of the top of the stack
+};
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// The FastCallStack Class
+//
+// This class is a specialization of the CallStack class which provides a
+// very fast stack tracing function.
+//
+class FastCallStack : public CallStack
+{
+public:
+ VOID getstacktrace (UINT32 maxdepth, SIZE_T *framepointer);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// The SafeCallStack Class
+//
+// This class is a specialization of the CallStack class which provides a
+// more robust, but quite slow, stack tracing function.
+//
+class SafeCallStack : public CallStack
+{
+public:
+ VOID getstacktrace (UINT32 maxdepth, SIZE_T *framepointer);
+};
\ No newline at end of file
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////
+// $Id: map.h,v 1.10 2006/11/18 03:12:34 dmouldin Exp $
+//
+// Visual Leak Detector - Lightweight STL-like Map Template
+// Copyright (c) 2006 Dan Moulding
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+//
+// See COPYING.txt for the full terms of the GNU Lesser General Public License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#ifndef VLDBUILD
+#error \
+"This header should only be included by Visual Leak Detector when building it from source. \
+Applications should never include this header."
+#endif
+
+#include "tree.h" // Provides access to the Tree template class.
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// The Pair Template Class
+//
+// This is a lightweight STL-like pair template, for use with the lightweight
+// Map class template.
+//
+// Note that while this is a STL-like class, it is not a full STL-compliant
+// implementation of the STL pair utility class. It provides just the bare
+// minimum functionality required by the Visual Leak Detector Map template
+// class below.
+//
+template <typename Tf, typename Ts>
+class Pair {
+public:
+ // Constructor
+ Pair ()
+ {
+ first = Tf();
+ second = Ts();
+ }
+
+ // Constructor with initializers.
+ Pair (const Tf &f, const Ts &s)
+ {
+ first = f;
+ second = s;
+ }
+
+ // Less-than operator - Compares this Pair with another Pair to determine
+ // if this Pair is less than the other Pair. The Pair with the smallest
+ // "first" value is the lesser Pair.
+ //
+ // - other (IN): The other pair to compare against.
+ //
+ // Return Value:
+ //
+ // Returns true if this Pair is less than the other Pair. Otherwise
+ // returns false.
+ //
+ BOOL operator < (const Pair &other) const
+ {
+ return (first < other.first);
+ }
+
+ // Public data.
+ Tf first; // The first value of the pair.
+ Ts second; // The second value of the pair.
+};
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// The Map Template Class
+//
+// This is a lightweidht STL-like map template. It makes use of the Tree class
+// template to enable fast insert, find, and erase operations.
+//
+// Note that while this is a STL-like class, it is not a full STL-compliant
+// implementation of the STL map container. It contains just the bare minimum
+// functionality required by Visual Leak Detector. Because of its "lightweight"
+// nature, this map class has a noticeable performance advantage over some
+// other standard STL map implementations.
+//
+template <typename Tk, typename Tv>
+class Map {
+public:
+ class Iterator {
+ public:
+ // Constructor
+ Iterator ()
+ {
+ // Plainly constructed iterators don't reference anything.
+ m_node = NULL;
+ m_tree = NULL;
+ }
+
+ // operator != - Inequality operator for Map Iterators. Two Map
+ // Iterators are considered equal if and only if they both reference
+ // the same key/value pair in the same Map.
+ //
+ // - other (IN): The other Map Iterator to compare against.
+ //
+ // Return Value:
+ //
+ // Returns true if the specified Map Iterator is not equal to this
+ // Map Iterator; otherwise, returns false.
+ //
+ BOOL operator != (const Iterator &other) const
+ {
+ return ((m_tree != other.m_tree) || (m_node != other.m_node));
+ }
+
+ // operator * - Dereference operator for Map Iterators.
+ //
+ // Note: The reference returned by this function is "const", so the
+ // value referenced by the Iterator may not be modified through the
+ // Iterator. This is a departure from STL iterator behavior.
+ //
+ // Also, dereferencing an Iterator which does not reference a valid
+ // value in the Map is undefined and will almost certainly cause a
+ // crash.
+ //
+ // Return Value:
+ //
+ // Returns a const reference to the key/value pair in the Map
+ // referenced by the Iterator.
+ //
+ const Pair<Tk, Tv>& operator * () const
+ {
+ return m_node->key;
+ }
+
+ // operator ++ - Prefix increment operator for Map Iterators. Causes the
+ // Iterator to reference the in-oder successor of the key/value pair
+ // currently referenced by the Iterator. If the Iterator is currently
+ // referencing the largest key/value pair in the Map, then the
+ // resulting Iterator will reference the Map's end (the NULL pair).
+ //
+ // Note: Incrementing an Iterator which does not reference a valid
+ // key/value pair in the Map is undefined and will almost certainly
+ // cause a crash.
+ //
+ // Return Value:
+ //
+ // Returns the Iterator after it has been incremented.
+ //
+ Iterator& operator ++ (int)
+ {
+ m_node = m_tree->next(m_node);
+ return *this;
+ }
+
+ // operator ++ - Postfix increment operator for Map Iterators. Causes
+ // the Iterator to reference the in-order successor of the key/value
+ // pair currently referenced by the Iterator. If the Iterator is
+ // currently referencing the largest key/value pair in the Map, then
+ // the resulting Iterator will reference the Map's end (the NULL
+ // pair).
+ //
+ // Note: Incrementing an Iterator which does not reference a valid
+ // key/value pair in the Map is undefined and will almost certainly
+ // cause a crash.
+ //
+ // Return Value:
+ //
+ // Returns the Iterator before it has been incremented.
+ //
+ Iterator operator ++ ()
+ {
+ typename Tree<Pair<Tk, Tv> >::node_t *cur = m_node;
+
+ m_node = m_tree->next(m_node);
+ return Iterator(m_tree, cur);
+ }
+
+ // operator - - Subtraction operator for Map Iterators. Causes the
+ // the Iterator to reference a key/value pair that is an in-order
+ // predecessor of the currently refereced key/value pair.
+ //
+ // - num (IN): Number indicating the number of preceding key/value
+ // pairs to decrement the iterator.
+ //
+ // Return Value:
+ //
+ // Returns an Iterator referencing the key/value pair that precedes
+ // the original Iterator by "num" pairs.
+ //
+ Iterator operator - (SIZE_T num) const
+ {
+ SIZE_T count;
+ typename Tree<Pair<Tk, Tv> >::node_t *cur = m_node;
+
+ cur = m_tree->prev(m_node);
+ for (count = 0; count < num; count++) {
+ cur = m_tree->prev(m_node);
+ if (cur == NULL) {
+ return Iterator(m_tree, NULL);
+ }
+ }
+ return Iterator(m_tree, cur);
+ }
+
+ // operator == - Equality operator for Map Iterators. Map Iterators are
+ // considered equal if and only if they both refernce the same
+ // key/value pair in the same Map.
+ //
+ // - other (IN): The other Map Iterator to compare against.
+ //
+ // Return Value:
+ //
+ // Returns true if the specified Map Iterator is equal to this Map
+ // Iterator; otherwise returns false.
+ //
+ BOOL operator == (const Iterator &other) const
+ {
+ return ((m_tree == other.m_tree) && (m_node == other.m_node));
+ }
+
+ private:
+ // Private constructor. Only the Map class itself may use this
+ // constructor. It is used for constructing Iterators which reference
+ // specific nodes in the internal tree's structure.
+ Iterator (const Tree<Pair<Tk, Tv> > *tree, typename Tree<Pair<Tk, Tv> >::node_t *node)
+ {
+ m_node = node;
+ m_tree = tree;
+ }
+
+ typename Tree<Pair<Tk, Tv> >::node_t *m_node; // Pointer to the node referenced by the Map Iterator.
+ const Tree<Pair<Tk, Tv> > *m_tree; // Pointer to the tree containing the referenced node.
+
+ // The Map class is a friend of Map Iterators.
+ friend class Map<Tk, Tv>;
+ };
+
+ // begin - Obtains an Iterator referencing the beginning of the Map (i.e.
+ // the lowest key/value pair currently stored in the Map).
+ //
+ // Return Value:
+ //
+ // Returns an Iterator referencing the first key/value pair in the Map.
+ // If no key/value pairs are currenly stored in the map, returns the
+ // "NULL" Iterator.
+ //
+ Iterator begin () const
+ {
+ return Iterator(&m_tree, m_tree.begin());
+ }
+
+ // end - Obtains an Iterator referencing the end of the Map. The end of
+ // the map does not reference an actual key/value pair. Instead it
+ // represents a "null" key/value pair which signifies the end (i.e. just
+ // beyond largest key/value pair currently stored in the Map). Also
+ // known as the "NULL" Iterator.
+ //
+ // Return Value:
+ //
+ // Returns the "NULL" Iterator, signifying the end of the Map.
+ //
+ Iterator end () const
+ {
+ return Iterator(&m_tree, NULL);
+ }
+
+ // erase - Erases a key/value pair from the map.
+ //
+ // - it (IN): Iterator referencing the key/value pair to be erased from
+ // the map.
+ //
+ // Return Value:
+ //
+ // None.
+ //
+ VOID erase (Iterator& it)
+ {
+ m_tree.erase(it.m_node);
+ }
+
+ // erase - Erases a key/value pair from the map.
+ //
+ // - key (IN): The key corresponding to the key/value pair to be erased
+ // from the map.
+ //
+ // Return Value:
+ //
+ // None.
+ //
+ VOID erase (const Tk &key)
+ {
+ m_tree.erase(Pair<Tk, Tv>(key, Tv()));
+ }
+
+ // find - Finds a key/value pair in the map.
+ //
+ // - key (IN): The key corresponding to the key/value pair to be found.
+ //
+ // Return Value:
+ //
+ // Returns an Iterator referencing the found key/value pair. If no
+ // key/value pair with the specified key could be found, then the "NULL"
+ // Iterator is returned.
+ //
+ Iterator find (const Tk &key) const
+ {
+ return Iterator(&m_tree, m_tree.find(Pair<Tk, Tv>(key, Tv())));
+ }
+
+ // insert - Inserts a key/value pair into the map.
+ //
+ // - key (IN): The key of the key/value pair to be inserted.
+ //
+ // - data (IN): The value of the key/value pair to be inserted.
+ //
+ // Return Value:
+ //
+ // Returns an Iterator referencing the resulting key/value pair after
+ // if has been inserted into the map.
+ //
+ Iterator insert (const Tk &key, const Tv &data)
+ {
+ return Iterator(&m_tree, m_tree.insert(Pair<Tk, Tv>(key, data)));
+ }
+
+ // reserve - Sets the reserve size of the map. The reserve size is the
+ // number of key/value pairs for which space should be pre-allocated
+ // to avoid frequent heap hits when inserting new key/value pairs into
+ // the map.
+ //
+ // - count (IN): The number of key/value pairs for which to reserve space
+ // in advance.
+ //
+ // Return Value:
+ //
+ // Returns the reserve size previously in use by the map.
+ //
+ size_t reserve (size_t count)
+ {
+ return m_tree.reserve(count);
+ }
+
+private:
+ // Private data
+ Tree<Pair<Tk, Tv> > m_tree; // The key/value pairs are actually stored in a tree.
+};
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////
+// $Id: ntapi.cpp,v 1.7 2006/11/18 03:12:34 dmouldin Exp $
+//
+// Visual Leak Detector - Global NT API Function Pointers
+// Copyright (c) 2006 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.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#define VLDBUILD
+#include "ntapi.h"
+
+// Global function pointers for explicit dynamic linking with NT APIs that can't
+// be load-time linked (there is no import library available for these).
+LdrLoadDll_t LdrLoadDll;
+RtlAllocateHeap_t RtlAllocateHeap;
+RtlFreeHeap_t RtlFreeHeap;
+RtlReAllocateHeap_t RtlReAllocateHeap;
\ No newline at end of file
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////
+// $Id: ntapi.h,v 1.8 2006/11/18 03:12:35 dmouldin Exp $
+//
+// Visual Leak Detector - NT API Definitions
+// Copyright (c) 2006 Dan Moulding
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+//
+// See COPYING.txt for the full terms of the GNU Lesser General Public License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#ifndef VLDBUILD
+#error \
+"This header should only be included by Visual Leak Detector when building it from source. \
+Applications should never include this header."
+#endif
+
+#include <windows.h>
+
+// Return code type used by LdrLoadDll.
+typedef ULONG NTSTATUS;
+#define STATUS_SUCCESS 0
+
+// Unicode string structure used by NT APIs.
+typedef struct unicodestring_s {
+ USHORT length; // Length of the string.
+ USHORT maxlength; // Length of the buffer.
+ PWSTR buffer; // The buffer containing the string.
+} unicodestring_t;
+
+// Function pointer types for explicit dynamic linking with functions that can't
+// be load-time linked (no import library is available for these).
+typedef NTSTATUS (__stdcall *LdrLoadDll_t) (LPWSTR, PDWORD, unicodestring_t *, PHANDLE);
+typedef LPVOID (__stdcall *RtlAllocateHeap_t) (HANDLE, DWORD, SIZE_T);
+typedef BOOL (__stdcall *RtlFreeHeap_t) (HANDLE, DWORD, LPVOID);
+typedef LPVOID (__stdcall *RtlReAllocateHeap_t) (HANDLE, DWORD, LPVOID, SIZE_T);
+
+// Provide forward declarations for the NT APIs for any source files that
+// include this header.
+extern LdrLoadDll_t LdrLoadDll;
+extern RtlAllocateHeap_t RtlAllocateHeap;
+extern RtlFreeHeap_t RtlFreeHeap;
+extern RtlReAllocateHeap_t RtlReAllocateHeap;
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////
+// $Id: set.h,v 1.9 2006/11/18 03:12:35 dmouldin Exp $
+//
+// Visual Leak Detector - Lightweight STL-like Set Template
+// Copyright (c) 2006 Dan Moulding
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+//
+// See COPYING.txt for the full terms of the GNU Lesser General Public License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#ifndef VLDBUILD
+#error \
+"This header should only be included by Visual Leak Detector when building it from source. \
+Applications should never include this header."
+#endif
+
+#include "tree.h" // Provides access to the Tree template class.
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// The Set Template Class
+//
+// This is a lightweight STL-like set template. It makes use of the Tree class
+// template to enable fast insert, find, and erase operations.
+//
+// Note that while this is a STL-like class, it is not a full STL-compliant
+// implementation of the STL set container. It contains just the bare minimum
+// functionality required by Visual Leak Detector. Because of its "lightweight"
+// nature, this set class has a noticeable performance advantage over some
+// other standard STL set implementations.
+//
+template <typename Tk>
+class Set {
+public:
+ class Iterator {
+ public:
+ // Constructor
+ Iterator ()
+ {
+ // Plainly constructed iterators don't reference anything.
+ m_node = NULL;
+ m_tree = NULL;
+ }
+
+ // operator != - Inequality operator for Set Iterators. Two Set
+ // Iterators are considered equal if and only if they both reference
+ // the same key in the same Set.
+ //
+ // - other (IN): The other Set Iterator to compare against.
+ //
+ // Return Value:
+ //
+ // Returns true if the specified Set Iterator is not equal to this
+ // Set Iterator; otherwise, returns false.
+ //
+ BOOL operator != (const Iterator &other) const
+ {
+ return ((m_tree != other.m_tree) || (m_node != other.m_node));
+ }
+
+ // operator * - Dereference operator for Set Iterators.
+ //
+ // Note: The reference returned by this function is "const", so the
+ // value referenced by the Iterator may not be modified through the
+ // Iterator. This is a departure from STL iterator behavior.
+ //
+ // Also, dereferencing an Iterator which does not reference a valid
+ // value in the Set is undefined and will almost certainly cause a
+ // crash.
+ //
+ // Return Value:
+ //
+ // Returns a const reference to the key in the Map referenced by the
+ // Iterator.
+ //
+ const Tk& operator * () const
+ {
+ return m_node->key;
+ }
+
+ // operator ++ - Prefix increment operator for Set Iterators. Causes the
+ // Iterator to reference the in-oder successor of the key currently
+ // referenced by the Iterator. If the Iterator is currently
+ // referencing the largest key in the Map, then the resulting Iterator
+ // will reference the Set's end (the NULL pair).
+ //
+ // Note: Incrementing an Iterator which does not reference a valid
+ // key in the Set is undefined and will almost certainly cause a
+ // crash.
+ //
+ // Return Value:
+ //
+ // Returns the Iterator after it has been incremented.
+ //
+ Iterator& operator ++ (int)
+ {
+ m_node = m_tree->next(m_node);
+ return *this;
+ }
+
+ // operator ++ - Postfix increment operator for Map Iterators. Causes
+ // the Iterator to reference the in-order successor of the key/value
+ // pair currently referenced by the Iterator. If the Iterator is
+ // currently referencing the largest key/value pair in the Map, then
+ // the resulting Iterator will reference the Map's end (the NULL
+ // pair).
+ //
+ // Note: Incrementing an Iterator which does not reference a valid
+ // key/value pair in the Map is undefined and will almost certainly
+ // cause a crash.
+ //
+ // Return Value:
+ //
+ // Returns the Iterator before it has been incremented.
+ //
+ Iterator operator ++ ()
+ {
+ typename Tree<Tk>::node_t *cur = m_node;
+
+ m_node = m_tree->next(m_node);
+ return Iterator(m_tree, cur);
+ }
+
+ // operator - - Subtraction operator for Set Iterators. Causes the
+ // the Iterator to reference a key that is an in-order predecessor of
+ // the currently refereced key.
+ //
+ // - num (IN): Number indicating the number of preceding keys to
+ // decrement the iterator.
+ //
+ // Return Value:
+ //
+ // Returns an Iterator referencing the key that precedes the original
+ // Iterator by "num" keys.
+ //
+ Iterator operator - (SIZE_T num) const
+ {
+ SIZE_T count;
+ typename Tree<Tk>::node_t *cur = m_node;
+
+ cur = m_tree->prev(m_node);
+ for (count = 0; count < num; count++) {
+ cur = m_tree->prev(m_node);
+ if (cur == NULL) {
+ return Iterator(m_tree, NULL);
+ }
+ }
+ return Iterator(m_tree, cur);
+ }
+
+ // operator == - Equality operator for Set Iterators. Set Iterators are
+ // considered equal if and only if they both refernce the same
+ // key in the same Set.
+ //
+ // - other (IN): The other Set Iterator to compare against.
+ //
+ // Return Value:
+ //
+ // Returns true if the specified Set Iterator is equal to this Set
+ // Iterator; otherwise returns false.
+ //
+ BOOL operator == (const Iterator &other) const
+ {
+ return ((m_tree == other.m_tree) && (m_node == other.m_node));
+ }
+
+ private:
+ // Private constructor. Only the Set class itself may use this
+ // constructor. It is used for constructing Iterators which reference
+ // specific nodes in the internal tree's structure.
+ Iterator (const Tree<Tk> *tree, typename Tree<Tk>::node_t *node)
+ {
+ m_node = node;
+ m_tree = tree;
+ }
+
+ protected:
+ typename Tree<Tk>::node_t *m_node; // Pointer to the node referenced by the Set Iterator.
+ const Tree<Tk> *m_tree; // Pointer to the tree containing the referenced node.
+
+ // The Set class is a friend of Set Iterators.
+ friend class Set<Tk>;
+ };
+
+ // Muterator class - This class provides a mutable Iterator (the regular
+ // Iterators are const Iterators). By dereferencing a Muterator, you get
+ // a modifiable element.
+ //
+ // Caution: Modifing an element in a way that changes its sorting value
+ // will corrupt the Set container. Muterators should only be used when
+ // you are absolutely certain you will not be using it to make a
+ // modification that changes the sort order of the referenced element.
+ //
+ class Muterator : public Iterator
+ {
+ public:
+ // operator = - Assignment operator for Set Muterators. Can be used to
+ // copy a Muterator from an existing Iterator, such that the Muterator
+ // references the same element referenced by the Iterator.
+ Muterator& operator = (const Iterator& other) {
+ *(Iterator*)this = other;
+ return *this;
+ }
+
+ // operator * - Dereference operator for Set Muterators.
+ //
+ // Note: Dereferencing a Muterator which does not reference a valid
+ // value in the Set is undefined and will almost certainly cause a
+ // crash.
+ //
+ // Return Value:
+ //
+ // Returns a reference to the key in the Map referenced by the
+ // Muterator.
+ //
+ Tk& operator * ()
+ {
+ return m_node->key;
+ }
+ };
+
+ // begin - Obtains an Iterator referencing the beginning of the Set (i.e.
+ // the lowest key currently stored in the Set).
+ //
+ // Return Value:
+ //
+ // Returns an Iterator referencing the first key in the Set. If no keys
+ // are currenly stored in the Set, returns the "NULL" Iterator.
+ //
+ Iterator begin () const
+ {
+ return Iterator(&m_tree, m_tree.begin());
+ }
+
+ // end - Obtains an Iterator referencing the end of the Set. The end of
+ // the Set does not reference an actual key. Instead it represents a
+ // "null" key which signifies the end (i.e. just beyond largest key
+ // currently stored in the Set). Also known as the "NULL" Iterator.
+ //
+ // Return Value:
+ //
+ // Returns the "NULL" Iterator, signifying the end of the Set.
+ //
+ Iterator end () const
+ {
+ return Iterator(&m_tree, NULL);
+ }
+
+ // erase - Erases a key from the Set.
+ //
+ // - it (IN): Iterator referencing the key to be erased from the Set.
+ //
+ // Return Value:
+ //
+ // None.
+ //
+ VOID erase (Iterator& it)
+ {
+ m_tree.erase(it.m_node);
+ }
+
+ // erase - Erases a key from the Set.
+ //
+ // - key (IN): The key to be erased from the Set.
+ //
+ // Return Value:
+ //
+ // None.
+ //
+ VOID erase (const Tk &key)
+ {
+ m_tree.erase(key);
+ }
+
+ // find - Finds a key in the Set.
+ //
+ // - key (IN): The key to be found.
+ //
+ // Return Value:
+ //
+ // Returns an Iterator referencing the found key. If the key could not
+ // be found, then the "NULL" Iterator is returned.
+ //
+ Iterator find (const Tk &key) const
+ {
+ return Iterator(&m_tree, m_tree.find(key));
+ }
+
+ // insert - Inserts a key into the Set.
+ //
+ // - key (IN): The key to be inserted.
+ //
+ // Return Value:
+ //
+ // Returns an Iterator referencing the key after it has been inserted
+ // into the Set. If an element with an identical key value already exists
+ // in the Set, then the NULL Iterator is returned.
+ //
+ Iterator insert (const Tk &key)
+ {
+ return Iterator(&m_tree, m_tree.insert(key));
+ }
+
+ // reserve - Sets the reserve size of the Set. The reserve size is the
+ // number of keys for which space should be pre-allocated to avoid
+ // frequent heap hits when inserting new keys into the Set.
+ //
+ // - count (IN): The number of keys for which to reserve space in advance.
+ //
+ // Return Value:
+ //
+ // Returns the reserve size previously in use by the Set.
+ //
+ size_t reserve (size_t count)
+ {
+ return m_tree.reserve(count);
+ }
+
+private:
+ // Private data
+ Tree<Tk> m_tree; // The keys are actually stored in a tree.
+};
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////
+// $Id: tree.h,v 1.13 2006/11/18 03:12:35 dmouldin Exp $
+//
+// Visual Leak Detector - Red-black Tree Template
+// Copyright (c) 2005-2006 Dan Moulding
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+//
+// See COPYING.txt for the full terms of the GNU Lesser General Public License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#ifndef VLDBUILD
+#error \
+"This header should only be included by Visual Leak Detector when building it from source. \
+Applications should never include this header."
+#endif
+
+#include "vldheap.h" // Provides internal new and delete operators.
+
+#define TREE_DEFAULT_RESERVE 32 // By default, trees reserve enough space, in advance, for this many nodes.
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// The Tree Template Class
+//
+// This data structure is the internal data structure behind the lightweight
+// STL-like container classes. This is a red-black tree which provides for
+// fast insert, find, and erase operations.
+//
+// The binary tree nodes are overlaid on top of larger chunks of allocated
+// memory (called chunks) which are arranged in a simple linked list. This
+// allows the tree to grow (add nodes) dynamically without incurring a heap
+// hit each time a new node is added.
+//
+// The Tree class provides member functions which make it easily adaptable to
+// an STL-like interface so that it can be used as the backend for STL-like
+// container classes.
+//
+template <typename T>
+class Tree
+{
+public:
+ // This is a red-black tree.
+ enum color_e {
+ red,
+ black
+ };
+
+ // The node is the basic data structure which the tree is built from.
+ typedef struct node_s {
+ color_e color; // The node's color.
+ T key; // The node's value, by which nodes are sorted.
+ union {
+ struct node_s *left; // For nodes in the tree, the node's left child.
+ struct node_s *next; // For nodes in the free list, the next node on the free list.
+ };
+ struct node_s *parent; // The node's parent.
+ struct node_s *right; // The node's right child.
+ } node_t;
+
+ // Reserve capacity for the tree is allocated in large chunks with room for
+ // many nodes.
+ typedef struct chunk_s {
+ struct chunk_s *next; // Pointer to the next node in the chunk list.
+ node_t *nodes; // Pointer to an array (of variable size) where nodes are stored.
+ } chunk_t;
+
+ // Constructor
+ Tree ()
+ {
+ m_freelist = NULL;
+ InitializeCriticalSection(&m_lock);
+ m_nil.color = black;
+ m_nil.key = T();
+ m_nil.left = &m_nil;
+ m_nil.parent = &m_nil;
+ m_nil.right = &m_nil;
+ m_reserve = TREE_DEFAULT_RESERVE;
+ m_root = &m_nil;
+ m_store = NULL;
+ m_storetail = NULL;
+ }
+
+ // Copy constructor - The sole purpose of this constructor's existence is
+ // to ensure that trees are not being inadvertently copied.
+ Tree (const Tree& source)
+ {
+ assert(FALSE); // Do not make copies of trees!
+ }
+
+ // Destructor
+ ~Tree ()
+ {
+ chunk_t *cur;
+ chunk_t *temp;
+
+ // Free all the chunks in the chunk list.
+ EnterCriticalSection(&m_lock);
+ cur = m_store;
+ while (cur != NULL) {
+ temp = cur;
+ cur = cur->next;
+ delete [] temp->nodes;
+ delete temp;
+ }
+ LeaveCriticalSection(&m_lock);
+ DeleteCriticalSection(&m_lock);
+ }
+
+ // operator = - Assignment operator. For efficiency, we want to avoid ever
+ // making copies of Trees (only pointer passing or reference passing
+ // should be performed). The sole purpose of this assignment operator is
+ // to ensure that no copying is being done inadvertently.
+ //
+ Tree<T>& operator = (const Tree<T> &other)
+ {
+ // Don't make copies of Trees!
+ assert(FALSE);
+ return *this;
+ }
+
+ // begin - Obtains a pointer to the first node (the node with the smallest
+ // key value) in the tree.
+ //
+ // Return Value:
+ //
+ // Returns a pointer to the first node in the tree.
+ //
+ typename Tree::node_t* begin () const
+ {
+ node_t *cur;
+
+ EnterCriticalSection(&m_lock);
+ if (m_root == &m_nil) {
+ LeaveCriticalSection(&m_lock);
+ return NULL;
+ }
+
+ cur = m_root;
+ while (cur->left != &m_nil) {
+ cur = cur->left;
+ }
+ LeaveCriticalSection(&m_lock);
+
+ return cur;
+ }
+
+ // erase - Erases the specified node from the tree. Note that this does
+ // not cause the key associated with the erased node to be freed. The
+ // caller is responsible for freeing any dynamically allocated memory
+ // associated with the key.
+ //
+ // - node (IN): Pointer to the node to erase from the tree.
+ //
+ // Return Value:
+ //
+ // None.
+ //
+ VOID erase (typename Tree::node_t *node)
+ {
+ node_t *child;
+ node_t *cur;
+ node_t *erasure;
+ node_t *sibling;
+
+ EnterCriticalSection(&m_lock);
+
+ if ((node->left == &m_nil) || (node->right == &m_nil)) {
+ // The node to be erased has less than two children. It can be directly
+ // removed from the tree.
+ erasure = node;
+ }
+ else {
+ // The node to be erased has two children. It can only be removed
+ // indirectly. The actual node will stay where it is, but it's contents
+ // will be replaced by it's in-order successor's contents. The successor
+ // node will then be erased. Find the successor.
+ erasure = node->right;
+ while (erasure->left != &m_nil) {
+ erasure = erasure->left;
+ }
+ }
+
+ // Select the child node which will replace the node to be erased.
+ if (erasure->left != &m_nil) {
+ child = erasure->left;
+ }
+ else {
+ child = erasure->right;
+ }
+
+ // Replace the node to be erased with the selected child.
+ child->parent = erasure->parent;
+ if (child->parent == &m_nil) {
+ // The root of the tree is being erased. The child becomes root.
+ m_root = child;
+ }
+ else {
+ if (erasure == erasure->parent->left) {
+ erasure->parent->left = child;
+ }
+ else {
+ erasure->parent->right = child;
+ }
+ }
+
+ if (erasure != node) {
+ // The node being erased from the tree is the successor of the actual
+ // node to be erased. Replace the contents of the node to be erased
+ // with the successor's contents.
+ node->key = erasure->key;
+ }
+
+ if (erasure->color == black) {
+ // The node being erased from the tree is black. Restructuring of the
+ // tree may be needed so that black-height is maintained.
+ cur = child;
+ while ((cur != m_root) && (cur->color == black)) {
+ if (cur == cur->parent->left) {
+ // Current node is a left child.
+ sibling = cur->parent->right;
+ if (sibling->color == red) {
+ // Sibling is red. Rotate sibling up and color it black.
+ sibling->color = black;
+ cur->parent->color = red;
+ _rotateleft(cur->parent);
+ sibling = cur->parent->right;
+ }
+ if ((sibling->left->color == black) && (sibling->right->color == black)) {
+ // Both of sibling's children are black. Color sibling red.
+ sibling->color = red;
+ cur = cur->parent;
+ }
+ else {
+ // At least one of sibling's children is red.
+ if (sibling->right->color == black) {
+ sibling->left->color = black;
+ sibling->color = red;
+ _rotateright(sibling);
+ sibling = cur->parent->right;
+ }
+ sibling->color = cur->parent->color;
+ cur->parent->color = black;
+ sibling->right->color = black;
+ _rotateleft(cur->parent);
+ cur = m_root;
+ }
+ }
+ else {
+ // Current node is a right child.
+ sibling = cur->parent->left;
+ if (sibling->color == red) {
+ // Sibling is red. Rotate sibling up and color it black.
+ sibling->color = black;
+ cur->parent->color = red;
+ _rotateright(cur->parent);
+ sibling = cur->parent->left;
+ }
+ if ((sibling->left->color == black) && (sibling->right->color == black)) {
+ // Both of sibling's children are black. Color sibling red.
+ sibling->color = red;
+ cur = cur->parent;
+ }
+ else {
+ // At least one of sibling's children is red.
+ if (sibling->left->color == black) {
+ sibling->right->color = black;
+ sibling->color = red;
+ _rotateleft(sibling);
+ sibling = cur->parent->left;
+ }
+ sibling->color = cur->parent->color;
+ cur->parent->color = black;
+ sibling->left->color = black;
+ _rotateright(cur->parent);
+ cur = m_root;
+ }
+ }
+ }
+ cur->color = black;
+ }
+
+ // Put the erased node onto the free list.
+ erasure->next = m_freelist;
+ m_freelist = erasure;
+
+ LeaveCriticalSection(&m_lock);
+ }
+
+ // erase - Erases the specified key from the tree. Note that this does
+ // not cause the key associated with the erased node to be freed. The
+ // caller is responsible for freeing any dynamically allocated memory
+ // associated with the key.
+ //
+ // - key (IN): The key to erase from the tree. This value is treated as
+ // the key for sorting within the tree. It must therefore be of a type
+ // which supports the "<" operator.
+ //
+ // Return Value:
+ //
+ // None.
+ //
+ VOID erase (const T &key)
+ {
+ node_t *node;
+
+ // Find the node to erase.
+ EnterCriticalSection(&m_lock);
+ node = m_root;
+ while (node != &m_nil) {
+ if (node->key < key) {
+ // Go right.
+ node = node->right;
+ }
+ else if (key < node->key) {
+ // Go left.
+ node = node->left;
+ }
+ else {
+ // Found it.
+ erase(node);
+ LeaveCriticalSection(&m_lock);
+ return;
+ }
+ }
+ LeaveCriticalSection(&m_lock);
+
+ // 'key' is not in the tree.
+ return;
+ }
+
+ // find - Obtains a pointer to the node corresponding to the specified key.
+ //
+ // - key (IN): The value to search for in the tree. This value is treated
+ // as the key for sorting within the tree. It must therefore be of a
+ // type which supports the "<" operator.
+ //
+ // Return Value:
+ //
+ // Returns a pointer to the node corresponding to the specified key. If
+ // the key is not in the tree, then "find" returns NULL.
+ //
+ typename Tree::node_t* find (const T &key) const
+ {
+ node_t *cur;
+
+ EnterCriticalSection(&m_lock);
+ cur = m_root;
+ while (cur != &m_nil) {
+ if (cur->key < key) {
+ // Go right.
+ cur = cur->right;
+ }
+ else if (key < cur->key) {
+ // Go left.
+ cur = cur->left;
+ }
+ else {
+ // Found it.
+ LeaveCriticalSection(&m_lock);
+ return cur;
+ }
+ }
+ LeaveCriticalSection(&m_lock);
+
+ // 'key' is not in the tree.
+ return NULL;
+ }
+
+ // insert - Inserts a new key into the tree.
+ //
+ // - key (IN): The key to insert into the tree. This value is treated as
+ // the key for sorting within the tree. It must therefore be of a type
+ // which supports the "<" operator.
+ //
+ // Return Value:
+ //
+ // Returns a pointer to the node corresponding to the newly inserted
+ // key. If an attempt is made to insert a key which is already in the
+ // tree, then NULL is returned and the new key is not inserted.
+ //
+ typename Tree::node_t* insert (const T &key)
+ {
+ node_t *cur;
+ node_t *node;
+ node_t *parent;
+ node_t *uncle;
+
+ EnterCriticalSection(&m_lock);
+
+ // Find the location where the new node should be inserted..
+ cur = m_root;
+ parent = &m_nil;
+ while (cur != &m_nil) {
+ parent = cur;
+ if (cur->key < key) {
+ // Go right.
+ cur = cur->right;
+ }
+ else if (key < cur->key) {
+ // Go left.
+ cur = cur->left;
+ }
+ else {
+ // Keys in the tree must be unique.
+ LeaveCriticalSection(&m_lock);
+ return NULL;
+ }
+ }
+
+ // Obtain a new node from the free list.
+ if (m_freelist == NULL) {
+ // Allocate additional storage.
+ reserve(m_reserve);
+ }
+ node = m_freelist;
+ m_freelist = m_freelist->next;
+
+ // Initialize the new node and insert it.
+ node->color = red;
+ node->key = key;
+ node->left = &m_nil;
+ node->parent = parent;
+ node->right = &m_nil;
+ if (parent == &m_nil) {
+ // The tree is empty. The new node becomes root.
+ m_root = node;
+ }
+ else {
+ if (parent->key < key) {
+ // New node is a right child.
+ parent->right = node;
+ }
+ else {
+ // New node is a left child.
+ parent->left = node;
+ }
+ }
+
+ // Rebalance and/or adjust the tree, if necessary.
+ cur = node;
+ while (cur->parent->color == red) {
+ // Double-red violation. Rebalancing/adjustment needed.
+ if (cur->parent == cur->parent->parent->left) {
+ // Parent is the left child. Uncle is the right child.
+ uncle = cur->parent->parent->right;
+ if (uncle->color == red) {
+ // Uncle is red. Recolor.
+ cur->parent->parent->color = red;
+ cur->parent->color = black;
+ uncle->color = black;
+ cur = cur->parent->parent;
+ }
+ else {
+ // Uncle is black. Restructure.
+ if (cur == cur->parent->right) {
+ cur = cur->parent;
+ _rotateleft(cur);
+ }
+ cur->parent->color = black;
+ cur->parent->parent->color = red;
+ _rotateright(cur->parent->parent);
+ }
+ }
+ else {
+ // Parent is the right child. Uncle is the left child.
+ uncle = cur->parent->parent->left;
+ if (uncle->color == red) {
+ // Uncle is red. Recolor.
+ cur->parent->parent->color = red;
+ cur->parent->color = black;
+ uncle->color = black;
+ cur = cur->parent->parent;
+ }
+ else {
+ // Uncle is black. Restructure.
+ if (cur == cur->parent->left) {
+ cur = cur->parent;
+ _rotateright(cur);
+ }
+ cur->parent->color = black;
+ cur->parent->parent->color = red;
+ _rotateleft(cur->parent->parent);
+ }
+ }
+ }
+
+ // The root node is always colored black.
+ m_root->color = black;
+
+ LeaveCriticalSection(&m_lock);
+
+ return node;
+ }
+
+ // next - Obtains a pointer to the in-order successor of the specified
+ // node.
+ //
+ // - node (IN): Pointer to the node whose in-order successor to retrieve.
+ //
+ // Return Value:
+ //
+ // Returns a pointer to the node's in-order successor. If the specified
+ // node corresponds to the largest value in the tree, then the specified
+ // node has no successor and "next" will return NULL.
+ //
+ typename Tree::node_t* next (typename Tree::node_t *node) const
+ {
+ node_t* cur;
+
+ if (node == NULL) {
+ return NULL;
+ }
+
+ EnterCriticalSection(&m_lock);
+ if (node->right != &m_nil) {
+ // 'node' has a right child. Successor is the far left node in
+ // the right subtree.
+ cur = node->right;
+ while (cur->left != &m_nil) {
+ cur = cur->left;
+ }
+ LeaveCriticalSection(&m_lock);
+ return cur;
+ }
+ else if (node->parent != &m_nil) {
+ // 'node' has no right child, but does have a parent.
+ if (node == node->parent->left) {
+ // 'node' is a left child; node's parent is successor.
+ LeaveCriticalSection(&m_lock);
+ return node->parent;
+ }
+ else {
+ // 'node' is a right child.
+ cur = node;
+ // Go up the tree until we find a parent to the right.
+ while (cur->parent != &m_nil) {
+ if (cur == cur->parent->right) {
+ cur = cur->parent;
+ continue;
+ }
+ else {
+ LeaveCriticalSection(&m_lock);
+ return cur->parent;
+ }
+ }
+
+ // There is no parent greater than 'node'. 'node' is the
+ // maximum node.
+ LeaveCriticalSection(&m_lock);
+ return NULL;
+ }
+ }
+ else {
+ // 'node' is root and root is the maximum node.
+ LeaveCriticalSection(&m_lock);
+ return NULL;
+ }
+ }
+
+ // prev - Obtains a pointer to the in-order predecessor of the specified
+ // node.
+ //
+ // - node (IN): Pointer to the node whose in-order predecessor to retrieve.
+ //
+ // Return Value:
+ //
+ // Returns a pointer to the node's in-order predecessor. If the specified
+ // node corresponds to the smallest value in the tree, then the specified
+ // node has no predecessor and "prev" will return NULL.
+ //
+ typename Tree::node_t* prev (typename Tree::node_t *node) const
+ {
+ node_t* cur;
+
+ if (node == NULL) {
+ return NULL;
+ }
+
+ EnterCriticalSection(&m_lock);
+ if (node->left != &m_nil) {
+ // 'node' has left child. Predecessor is the far right node in the
+ // left subtree.
+ cur = node->left;
+ while (cur->right != &m_nil) {
+ cur = cur->right;
+ }
+ LeaveCriticalSection(&m_lock);
+ return cur;
+ }
+ else if (node->parent != & m_nil) {
+ // 'node' has no left child, but does have a parent.
+ if (node == node->parent->right) {
+ // 'node' is a right child; node's parent is predecessor.
+ LeaveCriticalSection(&m_lock);
+ return node->parent;
+ }
+ else {
+ // 'node is a left child.
+ cur = node;
+ // Go up the tree until we find a parent to the left.
+ while (cur->parent != &m_nil) {
+ if (cur == cur->parent->left) {
+ cur = cur->parent;
+ continue;
+ }
+ else {
+ LeaveCriticalSection(&m_lock);
+ return cur->parent;
+ }
+ }
+
+ // There is no parent less than 'node'. 'node' is the minimum
+ // node.
+ LeaveCriticalSection(&m_lock);
+ return NULL;
+ }
+ }
+ else {
+ // 'node' is root and root is the minimum node.
+ LeaveCriticalSection(&m_lock);
+ return NULL;
+ }
+ }
+
+ // reserve - Reserves storage for a number of nodes in advance and/or sets
+ // the number of nodes for which the tree will automatically reserve
+ // storage when the tree needs to "grow" to accomodate new values being
+ // inserted into the tree. If this function is not called to set the
+ // reserve size to a specific value, then a pre-determined default value
+ // will be used. If this function is called when the tree currently has
+ // no reserve storage, then in addition to setting the tree's reserve
+ // value, it will also cause the tree to immediately reserve the
+ // specified amount of storage.
+ //
+ // - count (IN): The number of individual nodes' worth of storage to
+ // reserve.
+ //
+ // Return Value:
+ //
+ // Returns the previously defined reserve value.
+ //
+ UINT32 reserve (UINT32 count)
+ {
+ chunk_t *chunk;
+ UINT32 index;
+ UINT32 oldreserve = m_reserve;
+
+ if (count != m_reserve) {
+ if (count < 1) {
+ // Minimum reserve size is 1.
+ m_reserve = 1;
+ }
+ else {
+ m_reserve = count;
+ }
+ }
+
+ EnterCriticalSection(&m_lock);
+ if (m_freelist == NULL) {
+ // Allocate additional storage.
+ // Link a new chunk into the chunk list.
+ chunk = new Tree::chunk_t;
+ chunk->nodes = new Tree::node_s [m_reserve];
+ chunk->next = NULL;
+ if (m_store == NULL) {
+ m_store = chunk;
+ }
+ else {
+ m_storetail->next = chunk;
+ }
+ m_storetail = chunk;
+
+ // Link the individual nodes together to form a new free list.
+ for (index = 0; index < m_reserve - 1; index++) {
+ chunk->nodes[index].next = &chunk->nodes[index + 1];
+ }
+ chunk->nodes[index].next = NULL;
+ m_freelist = chunk->nodes;
+ }
+ LeaveCriticalSection(&m_lock);
+
+ return oldreserve;
+ }
+
+private:
+ // _rotateleft: Rotates a pair of nodes counter-clockwise so that the parent
+ // node becomes the left child and the right child becomes the parent.
+ //
+ // - parent (IN): Pointer to the parent to rotate about.
+ //
+ // Return Value:
+ //
+ // None.
+ //
+ VOID _rotateleft (typename Tree::node_t *parent)
+ {
+ node_t *child = parent->right;
+
+ // Reassign the child's left subtree to the parent.
+ parent->right = child->left;
+ if (child->left != &m_nil) {
+ child->left->parent = parent;
+ }
+
+ // Reassign the child/parent relationship.
+ child->parent = parent->parent;
+ if (parent->parent == &m_nil) {
+ // The child becomes the new root node.
+ m_root = child;
+ }
+ else {
+ // Point the grandparent at the child.
+ if (parent == parent->parent->left) {
+ parent->parent->left = child;
+ }
+ else {
+ parent->parent->right = child;
+ }
+ }
+ child->left = parent;
+ parent->parent = child;
+ }
+
+ // _rotateright - Rotates a pair of nodes clockwise so that the parent node
+ // becomes the right child and the left child becomes the parent.
+ //
+ // - parent (IN): Pointer to the parent to rotate about.
+ //
+ // Return Value:
+ //
+ // None.
+ //
+ VOID _rotateright (typename Tree::node_t *parent)
+ {
+ node_t *child = parent->left;
+
+ // Reassign the child's right subtree to the parent.
+ parent->left = child->right;
+ if (child->right != &m_nil) {
+ child->right->parent = parent;
+ }
+
+ // Reassign the child/parent relationship.
+ child->parent = parent->parent;
+ if (parent->parent == &m_nil) {
+ // The child becomes the new root node.
+ m_root = child;
+ }
+ else {
+ // Point the grandparent at the child.
+ if (parent == parent->parent->left) {
+ parent->parent->left = child;
+ }
+ else {
+ parent->parent->right = child;
+ }
+ }
+ child->right = parent;
+ parent->parent = child;
+ }
+
+ // Private data members.
+ node_t *m_freelist; // Pointer to the list of free nodes (reserve storage).
+ mutable CRITICAL_SECTION m_lock; // Protects the tree's integrity against concurrent accesses.
+ node_t m_nil; // The tree's nil node. All leaf nodes point to this.
+ UINT32 m_reserve; // The size (in nodes) of the chunks of reserve storage.
+ node_t *m_root; // Pointer to the tree's root node.
+ chunk_t *m_store; // Pointer to the start of the chunk list.
+ chunk_t *m_storetail; // Pointer to the end of the chunk list.
+};
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////
+// $Id: utility.cpp,v 1.24 2006/11/18 03:12:35 dmouldin Exp $
+//
+// Visual Leak Detector - Various Utility Functions
+// Copyright (c) 2005-2006 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.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include <cassert>
+#include <cstdio>
+#include <windows.h>
+#define __out_xcount(x) // Workaround for the specstrings.h bug in the Platform SDK.
+#define DBGHELP_TRANSLATE_TCHAR
+#include <dbghelp.h> // Provides portable executable (PE) image access functions.
+#define VLDBUILD // Declares that we are building Visual Leak Detector.
+#include "utility.h" // Provides various utility functions and macros.
+#include "vldheap.h" // Provides internal new and delete operators.
+
+// Imported Global Variables
+extern CRITICAL_SECTION imagelock;
+
+// Global variables.
+static BOOL reportdelay = FALSE; // If TRUE, we sleep for a bit after calling OutputDebugString to give the debugger time to catch up.
+static FILE *reportfile = NULL; // Pointer to the file, if any, to send the memory leak report to.
+static BOOL reporttodebugger = TRUE; // If TRUE, a copy of the memory leak report will be sent to the debugger for display.
+static encoding_e reportencoding = ascii; // Output encoding of the memory leak report.
+
+// dumpmemorya - Dumps a nicely formatted rendition of a region of memory.
+// Includes both the hex value of each byte and its ASCII equivalent (if
+// printable).
+//
+// - address (IN): Pointer to the beginning of the memory region to dump.
+//
+// - size (IN): The size, in bytes, of the region to dump.
+//
+// Return Value:
+//
+// None.
+//
+VOID dumpmemorya (LPCVOID address, SIZE_T size)
+{
+ WCHAR ascdump [18] = {0};
+ SIZE_T ascindex;
+ BYTE byte;
+ SIZE_T byteindex;
+ SIZE_T bytesdone;
+ SIZE_T dumplen;
+ WCHAR formatbuf [BYTEFORMATBUFFERLENGTH];
+ WCHAR hexdump [HEXDUMPLINELENGTH] = {0};
+ SIZE_T hexindex;
+
+ // Each line of output is 16 bytes.
+ if ((size % 16) == 0) {
+ // No padding needed.
+ dumplen = size;
+ }
+ else {
+ // We'll need to pad the last line out to 16 bytes.
+ dumplen = size + (16 - (size % 16));
+ }
+
+ // For each byte of data, get both the ASCII equivalent (if it is a
+ // printable character) and the hex representation.
+ bytesdone = 0;
+ for (byteindex = 0; byteindex < dumplen; byteindex++) {
+ hexindex = 3 * ((byteindex % 16) + ((byteindex % 16) / 4)); // 3 characters per byte, plus a 3-character space after every 4 bytes.
+ ascindex = (byteindex % 16) + (byteindex % 16) / 8; // 1 character per byte, plus a 1-character space after every 8 bytes.
+ if (byteindex < size) {
+ byte = ((PBYTE)address)[byteindex];
+ _snwprintf_s(formatbuf, BYTEFORMATBUFFERLENGTH, _TRUNCATE, L"%.2X ", byte);
+ formatbuf[3] = '\0';
+ wcsncpy_s(hexdump + hexindex, HEXDUMPLINELENGTH - hexindex, formatbuf, 4);
+ if (isgraph(byte)) {
+ ascdump[ascindex] = (WCHAR)byte;
+ }
+ else {
+ ascdump[ascindex] = L'.';
+ }
+ }
+ else {
+ // Add padding to fill out the last line to 16 bytes.
+ wcsncpy_s(hexdump + hexindex, HEXDUMPLINELENGTH - hexindex, L" ", 4);
+ ascdump[ascindex] = L'.';
+ }
+ bytesdone++;
+ if ((bytesdone % 16) == 0) {
+ // Print one line of data for every 16 bytes. Include the
+ // ASCII dump and the hex dump side-by-side.
+ report(L" %s %s\n", hexdump, ascdump);
+ }
+ else {
+ if ((bytesdone % 8) == 0) {
+ // Add a spacer in the ASCII dump after every 8 bytes.
+ ascdump[ascindex + 1] = L' ';
+ }
+ if ((bytesdone % 4) == 0) {
+ // Add a spacer in the hex dump after every 4 bytes.
+ wcsncpy_s(hexdump + hexindex + 3, HEXDUMPLINELENGTH - hexindex - 3, L" ", 4);
+ }
+ }
+ }
+}
+
+// dumpmemoryw - Dumps a nicely formatted rendition of a region of memory.
+// Includes both the hex value of each byte and its Unicode equivalent.
+//
+// - address (IN): Pointer to the beginning of the memory region to dump.
+//
+// - size (IN): The size, in bytes, of the region to dump.
+//
+// Return Value:
+//
+// None.
+//
+VOID dumpmemoryw (LPCVOID address, SIZE_T size)
+{
+ BYTE byte;
+ SIZE_T byteindex;
+ SIZE_T bytesdone;
+ SIZE_T dumplen;
+ WCHAR formatbuf [BYTEFORMATBUFFERLENGTH];
+ WCHAR hexdump [HEXDUMPLINELENGTH] = {0};
+ SIZE_T hexindex;
+ WORD word;
+ WCHAR unidump [18] = {0};
+ SIZE_T uniindex;
+
+ // Each line of output is 16 bytes.
+ if ((size % 16) == 0) {
+ // No padding needed.
+ dumplen = size;
+ }
+ else {
+ // We'll need to pad the last line out to 16 bytes.
+ dumplen = size + (16 - (size % 16));
+ }
+
+ // For each word of data, get both the Unicode equivalent and the hex
+ // representation.
+ bytesdone = 0;
+ for (byteindex = 0; byteindex < dumplen; byteindex++) {
+ hexindex = 3 * ((byteindex % 16) + ((byteindex % 16) / 4)); // 3 characters per byte, plus a 3-character space after every 4 bytes.
+ uniindex = ((byteindex / 2) % 8) + ((byteindex / 2) % 8) / 8; // 1 character every other byte, plus a 1-character space after every 8 bytes.
+ if (byteindex < size) {
+ byte = ((PBYTE)address)[byteindex];
+ _snwprintf_s(formatbuf, BYTEFORMATBUFFERLENGTH, _TRUNCATE, L"%.2X ", byte);
+ formatbuf[BYTEFORMATBUFFERLENGTH - 1] = '\0';
+ wcsncpy_s(hexdump + hexindex, HEXDUMPLINELENGTH - hexindex, formatbuf, 4);
+ if (((byteindex % 2) == 0) && ((byteindex + 1) < dumplen)) {
+ // On every even byte, print one character.
+ word = ((PWORD)address)[byteindex / 2];
+ if ((word == 0x0000) || (word == 0x0020)) {
+ unidump[uniindex] = L'.';
+ }
+ else {
+ unidump[uniindex] = word;
+ }
+ }
+ }
+ else {
+ // Add padding to fill out the last line to 16 bytes.
+ wcsncpy_s(hexdump + hexindex, HEXDUMPLINELENGTH - hexindex, L" ", 4);
+ unidump[uniindex] = L'.';
+ }
+ bytesdone++;
+ if ((bytesdone % 16) == 0) {
+ // Print one line of data for every 16 bytes. Include the
+ // ASCII dump and the hex dump side-by-side.
+ report(L" %s %s\n", hexdump, unidump);
+ }
+ else {
+ if ((bytesdone % 8) == 0) {
+ // Add a spacer in the ASCII dump after every 8 bytes.
+ unidump[uniindex + 1] = L' ';
+ }
+ if ((bytesdone % 4) == 0) {
+ // Add a spacer in the hex dump after every 4 bytes.
+ wcsncpy_s(hexdump + hexindex + 3, HEXDUMPLINELENGTH - hexindex - 3, L" ", 4);
+ }
+ }
+ }
+}
+
+// findimport - Determines if the specified module imports the named import
+// from the named exporting module.
+//
+// - importmodule (IN): Handle (base address) of the module to be searched to
+// see if it imports the specified import.
+//
+// - exportmodule (IN): Handle (base address) of the module that exports the
+// import to be searched for.
+//
+// - exportmodulename (IN): ANSI string containing the name of the module that
+// exports the import to be searched for.
+//
+// - importname (IN): ANSI string containing the name of the import to search
+// for. May be an integer cast to a string if the import is exported by
+// ordinal.
+//
+// Return Value:
+//
+// Returns TRUE if the module imports to the specified import. Otherwise
+// returns FALSE.
+//
+BOOL findimport (HMODULE importmodule, HMODULE exportmodule, LPCSTR exportmodulename, LPCSTR importname)
+{
+ IMAGE_THUNK_DATA *iate;
+ IMAGE_IMPORT_DESCRIPTOR *idte;
+ FARPROC import;
+ IMAGE_SECTION_HEADER *section;
+ ULONG size;
+
+ // Locate the importing module's Import Directory Table (IDT) entry for the
+ // exporting module. The importing module actually can have several IATs --
+ // one for each export module that it imports something from. The IDT entry
+ // gives us the offset of the IAT for the module we are interested in.
+ EnterCriticalSection(&imagelock);
+ idte = (IMAGE_IMPORT_DESCRIPTOR*)ImageDirectoryEntryToDataEx((PVOID)importmodule, TRUE,
+ IMAGE_DIRECTORY_ENTRY_IMPORT, &size, §ion);
+ LeaveCriticalSection(&imagelock);
+ if (idte == NULL) {
+ // This module has no IDT (i.e. it imports nothing).
+ return FALSE;
+ }
+ while (idte->OriginalFirstThunk != 0x0) {
+ if (_stricmp((PCHAR)R2VA(importmodule, idte->Name), exportmodulename) == 0) {
+ // Found the IDT entry for the exporting module.
+ break;
+ }
+ idte++;
+ }
+ if (idte->OriginalFirstThunk == 0x0) {
+ // The importing module does not import anything from the exporting
+ // module.
+ return FALSE;
+ }
+
+ // Get the *real* address of the import. If we find this address in the IAT,
+ // then we've found that the module does import the named import.
+ import = GetProcAddress(exportmodule, importname);
+ assert(import != NULL); // Perhaps the named export module does not actually export the named import?
+
+ // Locate the import's IAT entry.
+ iate = (IMAGE_THUNK_DATA*)R2VA(importmodule, idte->FirstThunk);
+ while (iate->u1.Function != 0x0) {
+ if (iate->u1.Function == (DWORD_PTR)import) {
+ // Found the IAT entry. The module imports the named import.
+ return TRUE;
+ }
+ iate++;
+ }
+
+ // The module does not import the named import.
+ return FALSE;
+}
+
+// findpatch - Determines if the specified module has been patched to use the
+// specified replacement.
+//
+// - importmodule (IN): Handle (base address) of the module to be searched to
+// see if it imports the specified replacement export.
+//
+// - exportmodulename (IN): ANSI string containing the name of the module that
+// normally exports that import that would have been patched to use the
+// replacement export.
+//
+// - replacement (IN): Address of the replacement, or destination, function or
+// variable to search for.
+//
+// Return Value:
+//
+// Returns TRUE if the module has been patched to use the specified
+// replacement export.
+//
+BOOL findpatch (HMODULE importmodule, LPCSTR exportmodulename, LPCVOID replacement)
+{
+ IMAGE_THUNK_DATA *iate;
+ IMAGE_IMPORT_DESCRIPTOR *idte;
+ IMAGE_SECTION_HEADER *section;
+ ULONG size;
+
+ // Locate the importing module's Import Directory Table (IDT) entry for the
+ // exporting module. The importing module actually can have several IATs --
+ // one for each export module that it imports something from. The IDT entry
+ // gives us the offset of the IAT for the module we are interested in.
+ EnterCriticalSection(&imagelock);
+ idte = (IMAGE_IMPORT_DESCRIPTOR*)ImageDirectoryEntryToDataEx((PVOID)importmodule, TRUE,
+ IMAGE_DIRECTORY_ENTRY_IMPORT, &size, §ion);
+ LeaveCriticalSection(&imagelock);
+ if (idte == NULL) {
+ // This module has no IDT (i.e. it imports nothing).
+ return FALSE;
+ }
+ while (idte->OriginalFirstThunk != 0x0) {
+ if (_stricmp((PCHAR)R2VA(importmodule, idte->Name), exportmodulename) == 0) {
+ // Found the IDT entry for the exporting module.
+ break;
+ }
+ idte++;
+ }
+ if (idte->OriginalFirstThunk == 0x0) {
+ // The importing module does not import anything from the exporting
+ // module.
+ return FALSE;
+ }
+
+ // Locate the replacement's IAT entry.
+ iate = (IMAGE_THUNK_DATA*)R2VA(importmodule, idte->FirstThunk);
+ while (iate->u1.Function != 0x0) {
+ if (iate->u1.Function == (DWORD_PTR)replacement) {
+ // Found the IAT entry for the replacement. This patch has been
+ // installed.
+ return TRUE;
+ }
+ iate++;
+ }
+
+ // The module does not import the replacement. The patch has not been
+ // installed.
+ return FALSE;
+}
+
+// insertreportdelay - Sets the report function to sleep for a bit after each
+// call to OutputDebugString, in order to allow the debugger to catch up.
+//
+// Return Value:
+//
+// None.
+//
+VOID insertreportdelay ()
+{
+ reportdelay = TRUE;
+}
+
+// moduleispatched - Checks to see if any of the imports listed in the specified
+// patch table have been patched into the specified importmodule.
+//
+// - importmodule (IN): Handle (base address) of the module to be queried to
+// determine if it has been patched.
+//
+// - patchtable (IN): An array of patchentry_t structures specifying all of the
+// import patches to search for.
+//
+// - tablesize (IN): Size, in entries, of the specified patch table.
+//
+// Return Value:
+//
+// Returns TRUE if at least one of the patches listed in the patch table is
+// installed in the importmodule. Otherwise returns FALSE.
+//
+BOOL moduleispatched (HMODULE importmodule, patchentry_t patchtable [], UINT tablesize)
+{
+ patchentry_t *entry;
+ BOOL found = FALSE;
+ UINT index;
+
+ // Loop through the import patch table, individually checking each patch
+ // entry to see if it is installed in the import module. If any patch entry
+ // is installed in the import module, then the module has been patched.
+ for (index = 0; index < tablesize; index++) {
+ entry = &patchtable[index];
+ found = findpatch(importmodule, entry->exportmodulename, entry->replacement);
+ if (found == TRUE) {
+ // Found one of the listed patches installed in the import module.
+ return TRUE;
+ }
+ }
+
+ // No patches listed in the patch table were found in the import module.
+ return FALSE;
+}
+
+// patchimport - Patches all future calls to an imported function, or references
+// to an imported variable, through to a replacement function or variable.
+// Patching is done by replacing the import's address in the specified target
+// module's Import Address Table (IAT) with the address of the replacement
+// function or variable.
+//
+// - importmodule (IN): Handle (base address) of the target module for which
+// calls or references to the import should be patched.
+//
+// - exportmodule (IN): Handle (base address) of the module that exports the
+// the function or variable to be patched.
+//
+// - exportmodulename (IN): ANSI string containing the name of the module that
+// exports the function or variable to be patched.
+//
+// - importname (IN): ANSI string containing the name of the imported function
+// or variable to be patched. May be an integer cast to a string if the
+// import is exported by ordinal.
+//
+// - replacement (IN): Address of the function or variable to which future
+// calls or references should be patched through to. This function or
+// variable can be thought of as effectively replacing the original import
+// from the point of view of the module specified by "importmodule".
+//
+// Return Value:
+//
+// Returns TRUE if the patch was installed into the import module. If the
+// import module does not import the specified export, so nothing changed,
+// then FALSE will be returned.
+//
+BOOL patchimport (HMODULE importmodule, HMODULE exportmodule, LPCSTR exportmodulename, LPCSTR importname,
+ LPCVOID replacement)
+{
+ IMAGE_THUNK_DATA *iate;
+ IMAGE_IMPORT_DESCRIPTOR *idte;
+ FARPROC import;
+ DWORD protect;
+ IMAGE_SECTION_HEADER *section;
+ ULONG size;
+
+ // Locate the importing module's Import Directory Table (IDT) entry for the
+ // exporting module. The importing module actually can have several IATs --
+ // one for each export module that it imports something from. The IDT entry
+ // gives us the offset of the IAT for the module we are interested in.
+ EnterCriticalSection(&imagelock);
+ idte = (IMAGE_IMPORT_DESCRIPTOR*)ImageDirectoryEntryToDataEx((PVOID)importmodule, TRUE,
+ IMAGE_DIRECTORY_ENTRY_IMPORT, &size, §ion);
+ LeaveCriticalSection(&imagelock);
+ if (idte == NULL) {
+ // This module has no IDT (i.e. it imports nothing).
+ return FALSE;
+ }
+ while (idte->OriginalFirstThunk != 0x0) {
+ if (_stricmp((PCHAR)R2VA(importmodule, idte->Name), exportmodulename) == 0) {
+ // Found the IDT entry for the exporting module.
+ break;
+ }
+ idte++;
+ }
+ if (idte->OriginalFirstThunk == 0x0) {
+ // The importing module does not import anything from the exporting
+ // module.
+ return FALSE;
+ }
+
+ // Get the *real* address of the import. If we find this address in the IAT,
+ // then we've found the entry that needs to be patched.
+ import = GetProcAddress(exportmodule, importname);
+ assert(import != NULL); // Perhaps the named export module does not actually export the named import?
+
+ // Locate the import's IAT entry.
+ iate = (IMAGE_THUNK_DATA*)R2VA(importmodule, idte->FirstThunk);
+ while (iate->u1.Function != 0x0) {
+ if (iate->u1.Function == (DWORD_PTR)import) {
+ // Found the IAT entry. Overwrite the address stored in the IAT
+ // entry with the address of the replacement. Note that the IAT
+ // entry may be write-protected, so we must first ensure that it is
+ // writable.
+ VirtualProtect(&iate->u1.Function, sizeof(iate->u1.Function), PAGE_READWRITE, &protect);
+ iate->u1.Function = (DWORD_PTR)replacement;
+ VirtualProtect(&iate->u1.Function, sizeof(iate->u1.Function), protect, &protect);
+
+ // The patch has been installed in the import module.
+ return TRUE;
+ }
+ iate++;
+ }
+
+ // The import's IAT entry was not found. The importing module does not
+ // import the specified import.
+ return FALSE;
+}
+
+// patchmodule - Patches all imports listed in the supplied patch table, and
+// which are imported by the specified module, through to their respective
+// replacement functions.
+//
+// Note: If the specified module does not import any of the functions listed
+// in the patch table, then nothing is changed for the specified module.
+//
+// - importmodule (IN): Handle (base address) of the target module which is to
+// have its imports patched.
+//
+// - patchtable (IN): An array of patchentry_t structures specifying all of the
+// imports to patch for the specified module.
+//
+// - tablesize (IN): Size, in entries, of the specified patch table.
+//
+// Return Value:
+//
+// Returns TRUE if at least one of the patches listed in the patch table was
+// installed in the importmodule. Otherwise returns FALSE.
+//
+BOOL patchmodule (HMODULE importmodule, patchentry_t patchtable [], UINT tablesize)
+{
+ patchentry_t *entry;
+ UINT index;
+ BOOL patched = FALSE;
+
+ // Loop through the import patch table, individually patching each import
+ // listed in the table.
+ for (index = 0; index < tablesize; index++) {
+ entry = &patchtable[index];
+ if (patchimport(importmodule, (HMODULE)entry->modulebase, entry->exportmodulename, entry->importname,
+ entry->replacement) == TRUE) {
+ patched = TRUE;
+ }
+ }
+
+ return patched;
+}
+
+// report - Sends a printf-style formatted message to the debugger for display
+// and/or to a file.
+//
+// Note: A message longer than MAXREPORTLENGTH characters will be truncated
+// to MAXREPORTLENGTH.
+//
+// - format (IN): Specifies a printf-compliant format string containing the
+// message to be sent to the debugger.
+//
+// - ... (IN): Arguments to be formatted using the specified format string.
+//
+// Return Value:
+//
+// None.
+//
+VOID report (LPCWSTR format, ...)
+{
+ va_list args;
+ size_t count;
+ CHAR messagea [MAXREPORTLENGTH + 1];
+ WCHAR messagew [MAXREPORTLENGTH + 1];
+
+ va_start(args, format);
+ _vsnwprintf_s(messagew, MAXREPORTLENGTH + 1, _TRUNCATE, format, args);
+ va_end(args);
+ messagew[MAXREPORTLENGTH] = L'\0';
+
+ if (reportencoding == unicode) {
+ if (reportfile != NULL) {
+ // Send the report to the previously specified file.
+ fwrite(messagew, sizeof(WCHAR), wcslen(messagew), reportfile);
+ }
+ if (reporttodebugger) {
+ OutputDebugStringW(messagew);
+ }
+ }
+ else {
+ if (wcstombs_s(&count, messagea, MAXREPORTLENGTH + 1, messagew, _TRUNCATE) == -1) {
+ // Failed to convert the Unicode message to ASCII.
+ assert(FALSE);
+ return;
+ }
+ messagea[MAXREPORTLENGTH] = '\0';
+ if (reportfile != NULL) {
+ // Send the report to the previously specified file.
+ fwrite(messagea, sizeof(CHAR), strlen(messagea), reportfile);
+ }
+ if (reporttodebugger) {
+ OutputDebugStringA(messagea);
+ }
+ }
+
+ if (reporttodebugger && (reportdelay == TRUE)) {
+ Sleep(10); // Workaround the Visual Studio 6 bug where debug strings are sometimes lost if they're sent too fast.
+ }
+}
+
+// restoreimport - Restores the IAT entry for an import previously patched via
+// a call to "patchimport" to the original address of the import.
+//
+// - importmodule (IN): Handle (base address) of the target module for which
+// calls or references to the import should be restored.
+//
+// - exportmodule (IN): Handle (base address) of the module that exports the
+// function or variable to be patched.
+//
+// - exportmodulename (IN): ANSI string containing the name of the module that
+// exports the function or variable to be patched.
+//
+// - importname (IN): ANSI string containing the name of the imported function
+// or variable to be restored. May be an integer cast to a string if the
+// import is exported by ordinal.
+//
+// - replacement (IN): Address of the function or variable which the import was
+// previously patched through to via a call to "patchimport".
+//
+// Return Value:
+//
+// None.
+//
+VOID restoreimport (HMODULE importmodule, HMODULE exportmodule, LPCSTR exportmodulename, LPCSTR importname,
+ LPCVOID replacement)
+{
+ IMAGE_THUNK_DATA *iate;
+ IMAGE_IMPORT_DESCRIPTOR *idte;
+ FARPROC import;
+ DWORD protect;
+ IMAGE_SECTION_HEADER *section;
+ ULONG size;
+
+ // Locate the importing module's Import Directory Table (IDT) entry for the
+ // exporting module. The importing module actually can have several IATs --
+ // one for each export module that it imports something from. The IDT entry
+ // gives us the offset of the IAT for the module we are interested in.
+ EnterCriticalSection(&imagelock);
+ idte = (IMAGE_IMPORT_DESCRIPTOR*)ImageDirectoryEntryToDataEx((PVOID)importmodule, TRUE,
+ IMAGE_DIRECTORY_ENTRY_IMPORT, &size, §ion);
+ LeaveCriticalSection(&imagelock);
+ if (idte == NULL) {
+ // This module has no IDT (i.e. it imports nothing).
+ return;
+ }
+ while (idte->OriginalFirstThunk != 0x0) {
+ if (_stricmp((PCHAR)R2VA(importmodule, idte->Name), exportmodulename) == 0) {
+ // Found the IDT entry for the exporting module.
+ break;
+ }
+ idte++;
+ }
+ if (idte->OriginalFirstThunk == 0x0) {
+ // The importing module does not import anything from the exporting
+ // module.
+ return;
+ }
+
+ // Get the *real* address of the import.
+ import = GetProcAddress(exportmodule, importname);
+ assert(import != NULL); // Perhaps the named export module does not actually export the named import?
+
+ // Locate the import's original IAT entry (it currently has the replacement
+ // address in it).
+ iate = (IMAGE_THUNK_DATA*)R2VA(importmodule, idte->FirstThunk);
+ while (iate->u1.Function != 0x0) {
+ if (iate->u1.Function == (DWORD_PTR)replacement) {
+ // Found the IAT entry. Overwrite the address stored in the IAT
+ // entry with the import's real address. Note that the IAT entry may
+ // be write-protected, so we must first ensure that it is writable.
+ VirtualProtect(&iate->u1.Function, sizeof(iate->u1.Function), PAGE_READWRITE, &protect);
+ iate->u1.Function = (DWORD_PTR)import;
+ VirtualProtect(&iate->u1.Function, sizeof(iate->u1.Function), protect, &protect);
+ break;
+ }
+ iate++;
+ }
+}
+
+// restoremodule - Restores all imports listed in the supplied patch table, and
+// which are imported by the specified module, to their original functions.
+//
+// Note: If the specified module does not import any of the functions listed
+// in the patch table, then nothing is changed for the specified module.
+//
+// - importmodule (IN): Handle (base address) of the target module which is to
+// have its imports restored.
+//
+// - patchtable (IN): Array of patchentry_t structures specifying all of the
+// imports to restore for the specified module.
+//
+// - tablesize (IN): Size, in entries, of the specified patch table.
+//
+// Return Value:
+//
+// None.
+//
+VOID restoremodule (HMODULE importmodule, patchentry_t patchtable [], UINT tablesize)
+{
+ patchentry_t *entry;
+ UINT index;
+
+ // Loop through the import patch table, individually restoring each import
+ // listed in the table.
+ for (index = 0; index < tablesize; index++) {
+ entry = &patchtable[index];
+ restoreimport(importmodule, (HMODULE)entry->modulebase, entry->exportmodulename, entry->importname,
+ entry->replacement);
+ }
+}
+
+// setreportencoding - Sets the output encoding of report messages to either
+// ASCII (the default) or Unicode.
+//
+// - encoding (IN): Specifies either "ascii" or "unicode".
+//
+// Return Value:
+//
+// None.
+//
+VOID setreportencoding (encoding_e encoding)
+{
+ switch (encoding) {
+ case ascii:
+ case unicode:
+ reportencoding = encoding;
+ break;
+
+ default:
+ assert(FALSE);
+ }
+}
+
+// setreportfile - Sets a destination file to which all report messages should
+// be sent. If this function is not called to set a destination file, then
+// report messages will be sent to the debugger instead of to a file.
+//
+// - file (IN): Pointer to an open file, to which future report messages should
+// be sent.
+//
+// - copydebugger (IN): If true, in addition to sending report messages to
+// the specified file, a copy of each message will also be sent to the
+// debugger.
+//
+// Return Value:
+//
+// None.
+//
+VOID setreportfile (FILE *file, BOOL copydebugger)
+{
+ reportfile = file;
+ reporttodebugger = copydebugger;
+}
+
+// strapp - Appends the specified source string to the specified destination
+// string. Allocates additional space so that the destination string "grows"
+// as new strings are appended to it. This function is fairly infrequently
+// used so efficiency is not a major concern.
+//
+// - dest (IN/OUT): Address of the destination string. Receives the resulting
+// combined string after the append operation.
+//
+// - source (IN): Source string to be appended to the destination string.
+//
+// Return Value:
+//
+// None.
+//
+VOID strapp (LPWSTR *dest, LPCWSTR source)
+{
+ SIZE_T length;
+ LPWSTR temp;
+
+ temp = *dest;
+ length = wcslen(*dest) + wcslen(source);
+ *dest = new WCHAR [length + 1];
+ wcsncpy_s(*dest, length + 1, temp, _TRUNCATE);
+ wcsncat_s(*dest, length + 1, source, _TRUNCATE);
+ delete [] temp;
+}
+
+// strtobool - Converts string values (e.g. "yes", "no", "on", "off") to boolean
+// values.
+//
+// - s (IN): String value to convert.
+//
+// Return Value:
+//
+// Returns TRUE if the string is recognized as a "true" string. Otherwise
+// returns FALSE.
+//
+BOOL strtobool (LPCWSTR s) {
+ WCHAR *end;
+
+ if ((_wcsicmp(s, L"true") == 0) ||
+ (_wcsicmp(s, L"yes") == 0) ||
+ (_wcsicmp(s, L"on") == 0) ||
+ (wcstol(s, &end, 10) == 1)) {
+ return TRUE;
+ }
+ else {
+ return FALSE;
+ }
+}
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////
+// $Id: utility.h,v 1.19 2006/11/18 03:12:35 dmouldin Exp $
+//
+// Visual Leak Detector - Various Utility Definitions
+// Copyright (c) 2005-2006 Dan Moulding
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+//
+// See COPYING.txt for the full terms of the GNU Lesser General Public License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#ifndef VLDBUILD
+#error \
+"This header should only be included by Visual Leak Detector when building it from source. \
+Applications should never include this header."
+#endif
+
+#include <cstdio>
+#include <windows.h>
+
+#ifdef _WIN64
+#define ADDRESSFORMAT L"0x%.16X" // Format string for 64-bit addresses
+#else
+#define ADDRESSFORMAT L"0x%.8X" // Format string for 32-bit addresses
+#endif // _WIN64
+#define BOM 0xFEFF // Unicode byte-order mark.
+#define MAXREPORTLENGTH 511 // Maximum length, in characters, of "report" messages.
+
+// Architecture-specific definitions for x86 and x64
+#if defined(_M_IX86)
+#define SIZEOFPTR 4
+#define X86X64ARCHITECTURE IMAGE_FILE_MACHINE_I386
+#define AXREG Eax
+#define BPREG Ebp
+#define IPREG Eip
+#define SPREG Esp
+#elif defined(_M_X64)
+#define SIZEOFPTR 8
+#define X86X64ARCHITECTURE IMAGE_FILE_MACHINE_AMD64
+#define AXREG Rax
+#define BPREG Rbp
+#define IPREG Rip
+#define SPREG Rsp
+#endif // _M_IX86
+
+#if defined(_M_IX86) || defined (_M_X64)
+#define FRAMEPOINTER(fp) __asm mov fp, BPREG // Copies the current frame pointer to the supplied variable.
+#else
+// If you want to retarget Visual Leak Detector to another processor
+// architecture then you'll need to provide an architecture-specific macro to
+// obtain the frame pointer (or other address) which can be used to obtain the
+// return address and stack pointer of the calling frame.
+#error "Visual Leak Detector is not supported on this architecture."
+#endif // _M_IX86 || _M_X64
+
+// Miscellaneous definitions
+#define R2VA(modulebase, rva) (((PBYTE)modulebase) + rva) // Relative Virtual Address to Virtual Address conversion.
+#define BYTEFORMATBUFFERLENGTH 4
+#define HEXDUMPLINELENGTH 58
+
+// Reports can be encoded as either ASCII or Unicode (UTF-16).
+enum encoding_e {
+ ascii,
+ unicode
+};
+
+// This structure allows us to build a table of APIs which should be patched
+// through to replacement functions provided by VLD.
+typedef struct patchentry_s
+{
+ LPCSTR exportmodulename; // The name of the module exporting the patched API.
+ LPCSTR importname; // The name (or ordinal) of the imported API being patched.
+ SIZE_T modulebase; // The base address of the exporting module (filled in at runtime when the modules are loaded).
+ LPCVOID replacement; // Pointer to the function to which the imported API should be patched through to.
+} patchentry_t;
+
+// Utility functions. See function definitions for details.
+VOID dumpmemorya (LPCVOID address, SIZE_T length);
+VOID dumpmemoryw (LPCVOID address, SIZE_T length);
+BOOL findimport (HMODULE importmodule, HMODULE exportmodule, LPCSTR exportmodulename, LPCSTR importname);
+BOOL findpatch (HMODULE importmodule, LPCSTR exportmodulename, LPCVOID replacement);
+VOID insertreportdelay ();
+BOOL moduleispatched (HMODULE importmodule, patchentry_t patchtable [], UINT tablesize);
+BOOL patchimport (HMODULE importmodule, HMODULE exportmodule, LPCSTR exportmodulename, LPCSTR importname,
+ LPCVOID replacement);
+BOOL patchmodule (HMODULE importmodule, patchentry_t patchtable [], UINT tablesize);
+VOID report (LPCWSTR format, ...);
+VOID restoreimport (HMODULE importmodule, HMODULE exportmodule, LPCSTR exportmodulename, LPCSTR importname,
+ LPCVOID replacement);
+VOID restoremodule (HMODULE importmodule, patchentry_t patchtable [], UINT tablesize);
+VOID setreportencoding (encoding_e encoding);
+VOID setreportfile (FILE *file, BOOL copydebugger);
+VOID strapp (LPWSTR *dest, LPCWSTR source);
+BOOL strtobool (LPCWSTR s);
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////
+// $Id: vld.cpp,v 1.69 2006/11/18 05:07:04 dmouldin Exp $
+//
+// Visual Leak Detector - VisualLeakDetector Class Implementation
+// Copyright (c) 2005-2006 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>
+#define __out_xcount(x) // Workaround for the specstrings.h bug in the Platform SDK.
+#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 "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 symbold handling APIs.
+
+// Function pointer types for explicit dynamic linking with functions listed in
+// the import patch table.
+typedef void* (__cdecl *_calloc_dbg_t) (size_t, size_t, int, const char*, int);
+typedef void* (__cdecl *_malloc_dbg_t) (size_t, int, const char *, int);
+typedef void* (__cdecl *_realloc_dbg_t) (void *, size_t, int, const char *, int);
+typedef void* (__cdecl *calloc_t) (size_t, size_t);
+typedef HRESULT (__stdcall *CoGetMalloc_t) (DWORD, LPMALLOC *);
+typedef LPVOID (__stdcall *CoTaskMemAlloc_t) (ULONG);
+typedef LPVOID (__stdcall *CoTaskMemRealloc_t) (LPVOID, ULONG);
+typedef void* (__cdecl *crt_new_dbg_t) (unsigned int, int, const char *, int);
+typedef void* (__cdecl *malloc_t) (size_t);
+typedef void* (__cdecl *mfc_new_dbg_t) (unsigned int, const char *, int);
+typedef void* (__cdecl *new_t) (unsigned int);
+typedef void* (__cdecl *realloc_t) (void *, size_t);
+
+// 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.
+static CoGetMalloc_t pCoGetMalloc = NULL;
+static CoTaskMemAlloc_t pCoTaskMemAlloc = NULL;
+static CoTaskMemRealloc_t pCoTaskMemRealloc = NULL;
+static _calloc_dbg_t pcrt80d__calloc_dbg = NULL;
+static _malloc_dbg_t pcrt80d__malloc_dbg = NULL;
+static _realloc_dbg_t pcrt80d__realloc_dbg = NULL;
+static crt_new_dbg_t pcrt80d__scalar_new_dbg = NULL;
+static crt_new_dbg_t pcrt80d__vector_new_dbg = NULL;
+static calloc_t pcrt80d_calloc = NULL;
+static malloc_t pcrt80d_malloc = NULL;
+static realloc_t pcrt80d_realloc = NULL;
+static new_t pcrt80d_scalar_new = NULL;
+static new_t pcrt80d_vector_new = NULL;
+static _calloc_dbg_t pcrtd__calloc_dbg = NULL;
+static _malloc_dbg_t pcrtd__malloc_dbg = NULL;
+static _realloc_dbg_t pcrtd__realloc_dbg = NULL;
+static crt_new_dbg_t pcrtd__scalar_new_dbg = NULL;
+static calloc_t pcrtd_calloc = NULL;
+static malloc_t pcrtd_malloc = NULL;
+static realloc_t pcrtd_realloc = NULL;
+static new_t pcrtd_scalar_new = NULL;
+static mfc_new_dbg_t pmfc42d__scalar_new_dbg = NULL;
+static new_t pmfc42d_scalar_new = NULL;
+static mfc_new_dbg_t pmfc80d__scalar_new_dbg = NULL;
+static mfc_new_dbg_t pmfc80d__vector_new_dbg = NULL;
+static new_t pmfc80d_scalar_new = NULL;
+static new_t pmfc80d_vector_new = NULL;
+
+// The one and only VisualLeakDetector object instance.
+__declspec(dllexport) VisualLeakDetector vld;
+
+// 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).
+ "mfc42d.dll", (LPCSTR)714, 0x0, _mfc42d__scalar_new_dbg,
+ "mfc42d.dll", (LPCSTR)711, 0x0, _mfc42d_scalar_new,
+ // XXX MFC 7.x DLL new operators still need to be added to this
+ // table, but I don't know their ordinals.
+ "mfc80d.dll", (LPCSTR)895, 0x0, _mfc80d__scalar_new_dbg,
+ "mfc80d.dll", (LPCSTR)269, 0x0, _mfc80d__vector_new_dbg,
+ "mfc80d.dll", (LPCSTR)893, 0x0, _mfc80d_scalar_new,
+ "mfc80d.dll", (LPCSTR)267, 0x0, _mfc80d_vector_new,
+
+ // CRT new operators and heap APIs.
+ "msvcr80d.dll", "_calloc_dbg", 0x0, _crt80d__calloc_dbg,
+ "msvcr80d.dll", "_malloc_dbg", 0x0, _crt80d__malloc_dbg,
+ "msvcr80d.dll", "_realloc_dbg", 0x0, _crt80d__realloc_dbg,
+ "msvcr80d.dll", "??2@YAPAXIHPBDH@Z", 0x0, _crt80d__scalar_new_dbg,
+ "msvcr80d.dll", "??_U@YAPAXIHPBDH@Z", 0x0, _crt80d__vector_new_dbg,
+ "msvcr80d.dll", "calloc", 0x0, _crt80d_calloc,
+ "msvcr80d.dll", "malloc", 0x0, _crt80d_malloc,
+ "msvcr80d.dll", "realloc", 0x0, _crt80d_realloc,
+ "msvcr80d.dll", "??2@YAPAXI@Z", 0x0, _crt80d_scalar_new,
+ "msvcr80d.dll", "??_U@YAPAXI@Z", 0x0, _crt80d_vector_new,
+ "msvcrtd.dll", "_calloc_dbg", 0x0, _crtd__calloc_dbg,
+ "msvcrtd.dll", "_malloc_dbg", 0x0, _crtd__malloc_dbg,
+ "msvcrtd.dll", "??2@YAPAXIHPBDH@Z", 0x0, _crtd__scalar_new_dbg,
+ "msvcrtd.dll", "_realloc_dbg", 0x0, _crtd__realloc_dbg,
+ "msvcrtd.dll", "calloc", 0x0, _crtd_calloc,
+ "msvcrtd.dll", "malloc", 0x0, _crtd_malloc,
+ "msvcrtd.dll", "realloc", 0x0, _crtd_realloc,
+ "msvcrtd.dll", "??2@YAPAXI@Z", 0x0, _crtd_scalar_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;
+ DWORD exitcode;
+ 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;
+ SIZE_T sleepcount;
+ HANDLE thread;
+ BOOL threadsactive= FALSE;
+ TlsSet::Iterator tlsit;
+
+ 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);
+
+ // 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;
+ }
+
+ sleepcount = 0;
+ thread = OpenThread(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()?
+ }
+ while (GetExitCodeThread(thread, &exitcode) == TRUE) {
+ if (exitcode != STILL_ACTIVE) {
+ // This thread exited.
+ break;
+ }
+ else {
+ // 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.
+ threadsactive = TRUE;
+ Sleep(100);
+ sleepcount++;
+ if ((sleepcount % 100) == 0) {
+ // Just in case this takes a long time, let the human
+ // know we are still here and alive.
+ report(L"Visual Leak Detector: Waiting for threads to terminate...\n");
+ }
+ }
+ }
+ }
+ 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);
+ }
+}
+
+// _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)
+{
+ 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)
+{
+ 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)
+{
+ 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;
+}
+
+// _crt80d__calloc_dbg - Calls to _calloc_dbg from msvcr80d.dll are patched
+// through to this function. 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.
+//
+// - 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 _calloc_dbg.
+//
+void* VisualLeakDetector::_crt80d__calloc_dbg (size_t num, size_t size, int type, const char *file, int line)
+{
+ void *block;
+ SIZE_T fp;
+ HMODULE msvcr80d;
+ 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.
+ FRAMEPOINTER(fp);
+ tls->addrfp = fp;
+ }
+
+ if (pcrt80d__calloc_dbg == NULL) {
+ // This is the first call to this function. Link to the real
+ // _malloc_dbg.
+ msvcr80d = GetModuleHandle(L"msvcr80d.dll");
+ pcrt80d__calloc_dbg = (_calloc_dbg_t)GetProcAddress(msvcr80d, "_calloc_dbg");
+ }
+
+ // Do the allocation. The block will be mapped by _RtlAllocateHeap.
+ block = pcrt80d__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;
+}
+
+// _crt80d__malloc_dbg - Calls to _malloc_dbg from msvcr80d.dll are patched
+// through to this function. 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.
+//
+// - 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 _malloc_dbg.
+//
+void* VisualLeakDetector::_crt80d__malloc_dbg (size_t size, int type, const char *file, int line)
+{
+ void *block;
+ SIZE_T fp;
+ HMODULE msvcr80d;
+ 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.
+ FRAMEPOINTER(fp);
+ tls->addrfp = fp;
+ }
+
+ if (pcrt80d__malloc_dbg == NULL) {
+ // This is the first call to this function. Link to the real
+ // _malloc_dbg.
+ msvcr80d = GetModuleHandle(L"msvcr80d.dll");
+ pcrt80d__malloc_dbg = (_malloc_dbg_t)GetProcAddress(msvcr80d, "_malloc_dbg");
+ }
+
+ // Do the allocation. The block will be mapped by _RtlAllocateHeap.
+ block = pcrt80d__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;
+}
+
+// _crt80d__realloc_dbg - Calls to _realloc_dbg from msvcr80d.dll are patched
+// through to this function. 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.
+//
+// - 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 filel, at which this function is
+// being called.
+//
+// Return Value:
+//
+// Returns the value returned by _realloc_dbg.
+//
+void* VisualLeakDetector::_crt80d__realloc_dbg (void *mem, size_t size, int type, const char *file, int line)
+{
+ void *block;
+ SIZE_T fp;
+ HMODULE msvcr80d;
+ 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.
+ FRAMEPOINTER(fp);
+ tls->addrfp = fp;
+ }
+
+ if (pcrt80d__realloc_dbg == NULL) {
+ // This is the first call to this function. Link to the real
+ // _realloc_dbg.
+ msvcr80d = GetModuleHandle(L"msvcr80d.dll");
+ pcrt80d__realloc_dbg = (_realloc_dbg_t)GetProcAddress(msvcr80d, "_realloc_dbg");
+ }
+
+ // Do the allocation. The block will be mapped by _RtlReAllocateHeap.
+ block = pcrt80d__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;
+}
+
+// _crt80d__scalar_new_dbg - Calls to the CRT's debug scalar new operator from
+// msvcr80d.dll are patched through to this function. This function is just a
+// wrapper around the real CRT debug scalar new operator that sets appropriate
+// flags to be consulted when the memory is actually allocated by
+// RtlAllocateHeap.
+//
+// - 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 CRT debug scalar new operator.
+//
+void* VisualLeakDetector::_crt80d__scalar_new_dbg (unsigned int size, int type, const char *file, int line)
+{
+ void *block;
+ SIZE_T fp;
+ HMODULE msvcr80d;
+ 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.
+ FRAMEPOINTER(fp);
+ tls->addrfp = fp;
+ }
+
+ if (pcrt80d__scalar_new_dbg == NULL) {
+ // This is the first call to this function. Link to the real CRT debug
+ // new operator.
+ msvcr80d = GetModuleHandle(L"msvcr80d.dll");
+ pcrt80d__scalar_new_dbg = (crt_new_dbg_t)GetProcAddress(msvcr80d, "??2@YAPAXIHPBDH@Z");
+ }
+
+ // Do the allocation. The block will be mapped by _RtlAllocateHeap.
+ block = pcrt80d__scalar_new_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;
+}
+
+// _crt80d__vector_new_dbg - Calls to the CRT's debug vector new operator from
+// msvcr80d.dll are patched through to this function. This function is just a
+// wrapper around the real CRT debug vector new operator that sets appropriate
+// flags to be consulted when the memory is actually allocated by
+// RtlAllocateHeap.
+//
+// - 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 CRT debug vector new operator.
+//
+void* VisualLeakDetector::_crt80d__vector_new_dbg (unsigned int size, int type, const char *file, int line)
+{
+ void *block;
+ SIZE_T fp;
+ HMODULE msvcr80d;
+ 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.
+ FRAMEPOINTER(fp);
+ tls->addrfp = fp;
+ }
+
+ if (pcrt80d__vector_new_dbg == NULL) {
+ // This is the first call to this function. Link to the real CRT debug
+ // new operator.
+ msvcr80d = GetModuleHandle(L"msvcr80d.dll");
+ pcrt80d__vector_new_dbg = (crt_new_dbg_t)GetProcAddress(msvcr80d, "??_U@YAPAXIHPBDH@Z");
+ }
+
+ // Do the allocation. The block will be mapped by _RtlAllocateHeap.
+ block = pcrt80d__vector_new_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;
+}
+
+// _crt80d_calloc - Calls to calloc from msvcr80d.dll are patched through to
+// this function. 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.
+//
+// - 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 valued returned from calloc.
+//
+void* VisualLeakDetector::_crt80d_calloc (size_t num, size_t size)
+{
+ void *block;
+ SIZE_T fp;
+ HMODULE msvcr80d;
+ 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.
+ FRAMEPOINTER(fp);
+ tls->addrfp = fp;
+ }
+
+ if (pcrt80d_calloc == NULL) {
+ // This is the first call to this function. Link to the real malloc.
+ msvcr80d = GetModuleHandle(L"msvcr80d.dll");
+ pcrt80d_calloc = (calloc_t)GetProcAddress(msvcr80d, "calloc");
+ }
+
+ // Do the allocation. The block will be mapped by _RtlAllocateHeap.
+ block = pcrt80d_calloc(num, size);
+
+ // Reset thread local flags and variables for the next allocation.
+ tls->addrfp = 0x0;
+ tls->flags &= ~VLD_TLS_CRTALLOC;
+
+ return block;
+}
+
+// _crt80d_malloc - Calls to malloc from msvcr80d.dll are patched through to
+// this function. 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.
+//
+// - size (IN): The size, in bytes, of the memory block to be allocated.
+//
+// Return Value:
+//
+// Returns the valued returned from malloc.
+//
+void* VisualLeakDetector::_crt80d_malloc (size_t size)
+{
+ void *block;
+ SIZE_T fp;
+ HMODULE msvcr80d;
+ 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.
+ FRAMEPOINTER(fp);
+ tls->addrfp = fp;
+ }
+
+ if (pcrt80d_malloc == NULL) {
+ // This is the first call to this function. Link to the real malloc.
+ msvcr80d = GetModuleHandle(L"msvcr80d.dll");
+ pcrt80d_malloc = (malloc_t)GetProcAddress(msvcr80d, "malloc");
+ }
+
+ // Do the allocation. The block will be mapped by _RtlAllocateHeap.
+ block = pcrt80d_malloc(size);
+
+ // Reset thread local flags and variables for the next allocation.
+ tls->addrfp = 0x0;
+ tls->flags &= ~VLD_TLS_CRTALLOC;
+
+ return block;
+}
+
+// _crt80d_realloc - Calls to realloc from msvcr80d.dll are patched through to
+// this function. 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.
+//
+// - 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 realloc.
+//
+void* VisualLeakDetector::_crt80d_realloc (void *mem, size_t size)
+{
+ void *block;
+ SIZE_T fp;
+ HMODULE msvcr80d;
+ 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.
+ FRAMEPOINTER(fp);
+ tls->addrfp = fp;
+ }
+
+ if (pcrt80d_realloc == NULL) {
+ // This is the first call to this function. Link to the real realloc.
+ msvcr80d = GetModuleHandle(L"msvcr80d.dll");
+ pcrt80d_realloc = (realloc_t)GetProcAddress(msvcr80d, "realloc");
+ }
+
+ // Do the allocation. The block will be mapped by _RtlReAllocateHeap.
+ block = pcrt80d_realloc(mem, size);
+
+ // Reset thread local flags and variables for the next allocation.
+ tls->addrfp = 0x0;
+ tls->flags &= ~VLD_TLS_CRTALLOC;
+
+ return block;
+}
+
+// _crt80d_scalar_new - Calls to the CRT's scalar new operator from msvcr80d.dll
+// are patched through to this function. This function is just a wrapper
+// around the real CRT scalar new operator that sets appropriate flags to be
+// consulted when the memory is actually allocated by RtlAllocateHeap.
+//
+// - size (IN): The size, in bytes, of the memory block to be allocated.
+//
+// Return Value:
+//
+// Returns the value returned by the CRT scalar new operator.
+//
+void* VisualLeakDetector::_crt80d_scalar_new (unsigned int size)
+{
+ void *block;
+ SIZE_T fp;
+ HMODULE msvcr80d;
+ 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.
+ FRAMEPOINTER(fp);
+ tls->addrfp = fp;
+ }
+
+ if (pcrt80d_scalar_new == NULL) {
+ // This is the first call to this function. Link to the real CRT new
+ // operator.
+ msvcr80d = GetModuleHandle(L"msvcr80d.dll");
+ pcrt80d_scalar_new = (new_t)GetProcAddress(msvcr80d, "??2@YAPAXI@Z");
+ }
+
+ // Do tha allocation. The block will be mapped by _RtlAllocateHeap.
+ block = pcrt80d_scalar_new(size);
+
+ // Reset thread local flags and variables for the next allocation.
+ tls->addrfp = 0x0;
+ tls->flags &= ~VLD_TLS_CRTALLOC;
+
+ return block;
+}
+
+// _crt80d_vector_new - Calls to the CRT's vector new operator from msvcr80d.dll
+// are patched through to this function. This function is just a wrapper
+// around the real CRT vector new operator that sets appropriate flags to be
+// consulted when the memory is actually allocated by RtlAllocateHeap.
+//
+// - size (IN): The size, in bytes, of the memory block to be allocated.
+//
+// Return Value:
+//
+// Returns the value returned by the CRT vector new operator.
+//
+void* VisualLeakDetector::_crt80d_vector_new (unsigned int size)
+{
+ void *block;
+ SIZE_T fp;
+ HMODULE msvcr80d;
+ 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.
+ FRAMEPOINTER(fp);
+ tls->addrfp = fp;
+ }
+
+ if (pcrt80d_vector_new == NULL) {
+ // This is the first call to this function. Link to the real CRT new
+ // operator.
+ msvcr80d = GetModuleHandle(L"msvcr80d.dll");
+ pcrt80d_vector_new = (new_t)GetProcAddress(msvcr80d, "??_U@YAPAXI@Z");
+ }
+
+ // Do tha allocation. The block will be mapped by _RtlAllocateHeap.
+ block = pcrt80d_vector_new(size);
+
+ // Reset thread local flags and variables for the next allocation.
+ tls->addrfp = 0x0;
+ tls->flags &= ~VLD_TLS_CRTALLOC;
+
+ return block;
+}
+
+// _crtd__calloc_dbg - Calls to _calloc_dbg from msvcrtd.dll are patched through
+// to this function. 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.
+//
+// - 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.
+//
+// - 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 _calloc_dbg.
+//
+void* VisualLeakDetector::_crtd__calloc_dbg (size_t num, size_t size, int type, const char *file, int line)
+{
+ void *block;
+ SIZE_T fp;
+ HMODULE msvcrtd;
+ 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.
+ FRAMEPOINTER(fp);
+ tls->addrfp = fp;
+ }
+
+ if (pcrtd__calloc_dbg == NULL) {
+ // This is the first call to this function. Link to the real
+ // _malloc_dbg.
+ msvcrtd = GetModuleHandle(L"msvcrtd.dll");
+ pcrtd__calloc_dbg = (_calloc_dbg_t)GetProcAddress(msvcrtd, "_calloc_dbg");
+ }
+
+ // Do the allocation. The block will be mapped by _RtlAllocateHeap.
+ block = pcrtd__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;
+}
+
+// _crtd__malloc_dbg - Calls to _malloc_dbg from msvcrtd.dll are patched through
+// to this function. 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.
+//
+// - 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 _malloc_dbg.
+//
+void* VisualLeakDetector::_crtd__malloc_dbg (size_t size, int type, const char *file, int line)
+{
+ void *block;
+ SIZE_T fp;
+ HMODULE msvcrtd;
+ 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.
+ FRAMEPOINTER(fp);
+ tls->addrfp = fp;
+ }
+
+ if (pcrtd__malloc_dbg == NULL) {
+ // This is the first call to this function. Link to the real
+ // _malloc_dbg.
+ msvcrtd = GetModuleHandle(L"msvcrtd.dll");
+ pcrtd__malloc_dbg = (_malloc_dbg_t)GetProcAddress(msvcrtd, "_malloc_dbg");
+ }
+
+ // Do the allocation. The block will be mapped by _RtlAllocateHeap.
+ block = pcrtd__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;
+}
+
+// _crtd__realloc_dbg - Calls to _realloc_dbg from msvcrtd.dll are patched
+// through to this function. 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.
+//
+// - 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 filel, at which this function is
+// being called.
+//
+// Return Value:
+//
+// Returns the value returned by _realloc_dbg.
+//
+void* VisualLeakDetector::_crtd__realloc_dbg (void *mem, size_t size, int type, const char *file, int line)
+{
+ void *block;
+ SIZE_T fp;
+ HMODULE msvcrtd;
+ 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.
+ FRAMEPOINTER(fp);
+ tls->addrfp = fp;
+ }
+
+ if (pcrtd__realloc_dbg == NULL) {
+ // This is the first call to this function. Link to the real
+ // _realloc_dbg.
+ msvcrtd = GetModuleHandle(L"msvcrtd.dll");
+ pcrtd__realloc_dbg = (_realloc_dbg_t)GetProcAddress(msvcrtd, "_realloc_dbg");
+ }
+
+ // Do the allocation. The block will be mapped by _RtlReAllocateHeap.
+ block = pcrtd__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;
+}
+
+// _crtd__scalar_new_dbg - Calls to the CRT's debug scalar new operator from
+// msvcrtd.dll are patched through to this function. This function is just a
+// wrapper around the real CRT debug scalar new operator that sets appropriate
+// flags to be consulted when the memory is actually allocated by
+// RtlAllocateHeap.
+//
+// - 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 CRT debug scalar new operator.
+//
+void* VisualLeakDetector::_crtd__scalar_new_dbg (unsigned int size, int type, const char *file, int line)
+{
+ void *block;
+ SIZE_T fp;
+ HMODULE msvcrtd;
+ 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.
+ FRAMEPOINTER(fp);
+ tls->addrfp = fp;
+ }
+
+ if (pcrtd__scalar_new_dbg == NULL) {
+ // This is the first call to this function. Link to the real CRT debug
+ // new operator.
+ msvcrtd = GetModuleHandle(L"msvcrtd.dll");
+ pcrtd__scalar_new_dbg = (crt_new_dbg_t)GetProcAddress(msvcrtd, "??2@YAPAXIHPBDH@Z");
+ }
+
+ // Do the allocation. The block will be mapped by _RtlAllocateHeap.
+ block = pcrtd__scalar_new_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;
+}
+
+// _crtd_calloc - Calls to calloc from msvcrtd.dll are patched through to this
+// function. 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.
+//
+// - 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 valued returned from calloc.
+//
+void* VisualLeakDetector::_crtd_calloc (size_t num, size_t size)
+{
+ void *block;
+ SIZE_T fp;
+ HMODULE msvcrtd;
+ 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.
+ FRAMEPOINTER(fp);
+ tls->addrfp = fp;
+ }
+
+ if (pcrtd_calloc == NULL) {
+ // This is the first call to this function. Link to the real malloc.
+ msvcrtd = GetModuleHandle(L"msvcrtd.dll");
+ pcrtd_calloc = (calloc_t)GetProcAddress(msvcrtd, "calloc");
+ }
+
+ // Do the allocation. The block will be mapped by _RtlAllocateHeap.
+ block = pcrtd_calloc(num, size);
+
+ // Reset thread local flags and variables for the next allocation.
+ tls->addrfp = 0x0;
+ tls->flags &= ~VLD_TLS_CRTALLOC;
+
+ return block;
+}
+
+// _crtd_malloc - Calls to malloc from msvcrtd.dll are patched through to this
+// function. 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.
+//
+// - size (IN): The size, in bytes, of the memory block to be allocated.
+//
+// Return Value:
+//
+// Returns the valued returned from malloc.
+//
+void* VisualLeakDetector::_crtd_malloc (size_t size)
+{
+ void *block;
+ SIZE_T fp;
+ HMODULE msvcrtd;
+ 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.
+ FRAMEPOINTER(fp);
+ tls->addrfp = fp;
+ }
+
+ if (pcrtd_malloc == NULL) {
+ // This is the first call to this function. Link to the real malloc.
+ msvcrtd = GetModuleHandle(L"msvcrtd.dll");
+ pcrtd_malloc = (malloc_t)GetProcAddress(msvcrtd, "malloc");
+ }
+
+ // Do the allocation. The block will be mapped by _RtlAllocateHeap.
+ block = pcrtd_malloc(size);
+
+ // Reset thread local flags and variables for the next allocation.
+ tls->addrfp = 0x0;
+ tls->flags &= ~VLD_TLS_CRTALLOC;
+
+ return block;
+}
+
+// _crtd_realloc - Calls to realloc from msvcrtd.dll are patched through to this
+// function. 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.
+//
+// - 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 realloc.
+//
+void* VisualLeakDetector::_crtd_realloc (void *mem, size_t size)
+{
+ void *block;
+ SIZE_T fp;
+ HMODULE msvcrtd;
+ 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.
+ FRAMEPOINTER(fp);
+ tls->addrfp = fp;
+ }
+
+ if (pcrtd_realloc == NULL) {
+ // This is the first call to this function. Link to the real realloc.
+ msvcrtd = GetModuleHandle(L"msvcrtd.dll");
+ pcrtd_realloc = (realloc_t)GetProcAddress(msvcrtd, "realloc");
+ }
+
+ // Do the allocation. The block will be mapped by _RtlReAllocateHeap.
+ block = pcrtd_realloc(mem, size);
+
+ // Reset thread local flags and variables for the next allocation.
+ tls->addrfp = 0x0;
+ tls->flags &= ~VLD_TLS_CRTALLOC;
+
+ return block;
+}
+
+// _crtd_scalar_new - Calls to the CRT's scalar new operator from msvcrtd.dll
+// are patched through to this function. This function is just a wrapper
+// around the real CRT scalar new operator that sets appropriate flags to be
+// consulted when the memory is actually allocated by RtlAllocateHeap.
+//
+// - size (IN): The size, in bytes, of the memory block to be allocated.
+//
+// Return Value:
+//
+// Returns the value returned by the CRT scalar new operator.
+//
+void* VisualLeakDetector::_crtd_scalar_new (unsigned int size)
+{
+ void *block;
+ SIZE_T fp;
+ HMODULE msvcrtd;
+ 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.
+ FRAMEPOINTER(fp);
+ tls->addrfp = fp;
+ }
+
+ if (pcrtd_scalar_new == NULL) {
+ // This is the first call to this function. Link to the real CRT new
+ // operator.
+ msvcrtd = GetModuleHandle(L"msvcrtd.dll");
+ pcrtd_scalar_new = (new_t)GetProcAddress(msvcrtd, "??2@YAPAXI@Z");
+ }
+
+ // Do tha allocation. The block will be mapped by _RtlAllocateHeap.
+ block = pcrtd_scalar_new(size);
+
+ // Reset thread local flags and variables for the next allocation.
+ tls->addrfp = 0x0;
+ tls->flags &= ~VLD_TLS_CRTALLOC;
+
+ return block;
+}
+
+// _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;
+
+ // 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);
+ EnterCriticalSection(&vld.m_loaderlock);
+ EnumerateLoadedModulesW64(currentprocess, addloadedmodule, newmodules);
+ LeaveCriticalSection(&vld.m_loaderlock);
+
+ // 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;
+ }
+
+ return status;
+}
+
+// _mfc42d__scalar_new_dbg - Calls to the MFC debug scalar new operator from
+// mfc42d.dll are patched through to this function. This function is just a
+// wrapper around the real MFC debug scalar new operator that sets appropriate
+// flags to be consulted when the memory is actually allocated by
+// RtlAllocateHeap.
+//
+// - 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 MFC debug scalar new operator.
+//
+void* VisualLeakDetector::_mfc42d__scalar_new_dbg (unsigned int size, const char *file, int line)
+{
+ void *block;
+ SIZE_T fp;
+ HMODULE mfc42d;
+ tls_t *tls = vld.gettls();
+
+ // The MFC new operators are CRT-based and allocate 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.
+ FRAMEPOINTER(fp);
+ tls->addrfp = fp;
+ }
+
+ if (pmfc42d__scalar_new_dbg == NULL) {
+ // This is the first call to this function. Link to the real MFC debug
+ // new operator.
+ mfc42d = GetModuleHandle(L"mfc42d.dll");
+ pmfc42d__scalar_new_dbg = (mfc_new_dbg_t)GetProcAddress(mfc42d, (LPCSTR)714);
+ }
+
+ // Do the allocation. The block will be mapped by _RtlAllocateHeap.
+ block = pmfc42d__scalar_new_dbg(size, file, line);
+
+ // Reset thread local flags and variables for the next allocation.
+ tls->addrfp = 0x0;
+ tls->flags &= ~VLD_TLS_CRTALLOC;
+
+ return block;
+}
+
+// _mfc42d_scalar_new - Calls to the MFC scalar new operator from mfc42d.dll are
+// patched through to this function. This function is just a wrapper around
+// the real MFC scalar new operator that sets appropriate flags to be
+// consulted when the memory is actually allocated by RtlAllocateHeap.
+//
+// - size (IN): The size, in bytes, of the memory block to be allocated.
+//
+// Return Value:
+//
+// Returns the value returned by the MFC scalar new operator.
+//
+void* VisualLeakDetector::_mfc42d_scalar_new (unsigned int size)
+{
+ void *block;
+ SIZE_T fp;
+ HMODULE mfc42d;
+ tls_t *tls = vld.gettls();
+
+ // The MFC new operators are CRT-based and allocate 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.
+ FRAMEPOINTER(fp);
+ tls->addrfp = fp;
+ }
+
+ if (pmfc42d_scalar_new == NULL) {
+ // This is the first call to this function. Link to the real MFC new
+ // operator.
+ mfc42d = GetModuleHandle(L"mfc42d.dll");
+ pmfc42d_scalar_new = (new_t)GetProcAddress(mfc42d, (LPCSTR)711);
+ }
+
+ // Do the allocation. The block will be mapped by _RtlAllocateHeap.
+ block = pmfc42d_scalar_new(size);
+
+ // Reset thread local flags and variables for the next allocation.
+ tls->addrfp = 0x0;
+ tls->flags &= ~VLD_TLS_CRTALLOC;
+
+ return block;
+}
+
+// _mfc80d__scalar_new_dbg - Calls to the MFC debug scalar new operator from
+// mfc80d.dll are patched through to this function. This function is just a
+// wrapper around the real MFC debug scalar new operator that sets appropriate
+// flags to be consulted when the memory is actually allocated by
+// RtlAllocateHeap.
+//
+// - 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 MFC debug scalar new operator.
+//
+void* VisualLeakDetector::_mfc80d__scalar_new_dbg (unsigned int size, const char *file, int line)
+{
+ void *block;
+ SIZE_T fp;
+ HMODULE mfc80d;
+ tls_t *tls = vld.gettls();
+
+ // The MFC new operators are CRT-based and allocate 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.
+ FRAMEPOINTER(fp);
+ tls->addrfp = fp;
+ }
+
+ if (pmfc80d__scalar_new_dbg == NULL) {
+ // This is the first call to this function. Link to the real MFC debug
+ // new operator.
+ mfc80d = GetModuleHandle(L"mfc80d.dll");
+ pmfc80d__scalar_new_dbg = (mfc_new_dbg_t)GetProcAddress(mfc80d, (LPCSTR)895);
+ }
+
+ // Do the allocation. The block will be mapped by _RtlAllocateHeap.
+ block = pmfc80d__scalar_new_dbg(size, file, line);
+
+ // Reset thread local flags and variables for the next allocation.
+ tls->addrfp = 0x0;
+ tls->flags &= ~VLD_TLS_CRTALLOC;
+
+ return block;
+}
+
+// _mfc80d__vector_new_dbg - Calls to the MFC debug vector new operator from
+// mfc80d.dll are patched through to this function. This function is just a
+// wrapper around the real MFC debug vector new operator that sets appropriate
+// flags to be consulted when the memory is actually allocated by
+// RtlAllocateHeap.
+//
+// - 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 MFC debug vector new operator.
+//
+void* VisualLeakDetector::_mfc80d__vector_new_dbg (unsigned int size, const char *file, int line)
+{
+ void *block;
+ SIZE_T fp;
+ HMODULE mfc80d;
+ tls_t *tls = vld.gettls();
+
+ // The MFC new operators are CRT-based and allocate 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.
+ FRAMEPOINTER(fp);
+ tls->addrfp = fp;
+ }
+
+ if (pmfc80d__vector_new_dbg == NULL) {
+ // This is the first call to this function. Link to the real MFC debug
+ // new operator.
+ mfc80d = GetModuleHandle(L"mfc80d.dll");
+ pmfc80d__vector_new_dbg = (mfc_new_dbg_t)GetProcAddress(mfc80d, (LPCSTR)269);
+ }
+
+ // Do the allocation. The block will be mapped by _RtlAllocateHeap.
+ block = pmfc80d__vector_new_dbg(size, file, line);
+
+ // Reset thread local flags and variables for the next allocation.
+ tls->addrfp = 0x0;
+ tls->flags &= ~VLD_TLS_CRTALLOC;
+
+ return block;
+}
+
+// _mfc80d_scalar_new - Calls to the MFC scalar new operator from mfc80d.dll are
+// patched through to this function. This function is just a wrapper around
+// the real MFC scalar new operator that sets appropriate flags to be
+// consulted when the memory is actually allocated by RtlAllocateHeap.
+//
+// - size (IN): The size, in bytes, of the memory block to be allocated.
+//
+// Return Value:
+//
+// Returns the value returned by the MFC scalar new operator.
+//
+void* VisualLeakDetector::_mfc80d_scalar_new (unsigned int size)
+{
+ void *block;
+ SIZE_T fp;
+ HMODULE mfc80d;
+ tls_t *tls = vld.gettls();
+
+ // The MFC new operators are CRT-based and allocate 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.
+ FRAMEPOINTER(fp);
+ tls->addrfp = fp;
+ }
+
+ if (pmfc80d_scalar_new == NULL) {
+ // This is the first call to this function. Link to the real MFC 8.0 new
+ // operator.
+ mfc80d = GetModuleHandle(L"mfc80d.dll");
+ pmfc80d_scalar_new = (new_t)GetProcAddress(mfc80d, (LPCSTR)893);
+ }
+
+ // Do the allocation. The block will be mapped by _RtlAllocateHeap.
+ block = pmfc80d_scalar_new(size);
+
+ // Reset thread local flags and variables for the next allocation.
+ tls->addrfp = 0x0;
+ tls->flags &= ~VLD_TLS_CRTALLOC;
+
+ return block;
+}
+
+// _mfc80d_vector_new - Calls to the MFC vector new operator from mfc80d.dll are
+// patched through to this function. This function is just a wrapper around
+// the real MFC vector new operator that sets appropriate flags to be
+// consulted when the memory is actually allocated by RtlAllocateHeap.
+//
+// - size (IN): The size, in bytes, of the memory block to be allocated.
+//
+// Return Value:
+//
+// Returns the value returned by the MFC vector new operator.
+//
+void* VisualLeakDetector::_mfc80d_vector_new (unsigned int size)
+{
+ void *block;
+ SIZE_T fp;
+ HMODULE mfc80d;
+ tls_t *tls = vld.gettls();
+
+ // The MFC new operators are CRT-based and allocate 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.
+ FRAMEPOINTER(fp);
+ tls->addrfp = fp;
+ }
+
+ if (pmfc80d_vector_new == NULL) {
+ // This is the first call to this function. Link to the real MFC 8.0 new
+ // operator.
+ mfc80d = GetModuleHandle(L"mfc80d.dll");
+ pmfc80d_vector_new = (new_t)GetProcAddress(mfc80d, (LPCSTR)267);
+ }
+
+ // Do the allocation. The block will be mapped by _RtlAllocateHeap.
+ block = pmfc80d_vector_new(size);
+
+ // Reset thread local flags and variables for the next allocation.
+ tls->addrfp = 0x0;
+ tls->flags &= ~VLD_TLS_CRTALLOC;
+
+ return block;
+}
+
+// _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;
+}
+
+// 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;
+}
+
+// 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;
+}
+
+// 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;
+ }
+}
+
+// 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 inlcude 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;
+}
+
+// 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);
+}
+
+// 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;
+}
+
+// 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);
+}
+
+// gettls - Obtains the thread local strorage 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;
+}
+
+// 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();
+}
+
+// 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);
+}
+
+// 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();
+}
+
+// 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);
+}
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////
+// $Id: vldapi.cpp,v 1.19 2006/11/18 03:12:35 dmouldin Exp $
+//
+// Visual Leak Detector - Exported APIs
+// Copyright (c) 2005-2006 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.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#define VLDBUILD // Declares that we are building Visual Leak Detector.
+#include "vldint.h" // Provides access to the Visual Leak Detector internals.
+#include "vldheap.h" // Provides internal new and delete operators.
+
+// Imported global variables.
+extern VisualLeakDetector vld;
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Visual Leak Detector APIs - see vldapi.h for each function's details.
+//
+
+extern "C" __declspec(dllexport) void VLDDisable ()
+{
+ tls_t *tls;
+
+ if (vld.m_options & VLD_OPT_VLDOFF) {
+ // VLD has been turned off.
+ return;
+ }
+
+ // Disable memory leak detection for the current thread. There are two flags
+ // because if neither flag is set, it means that we are in the default or
+ // "starting" state, which could be either enabled or disabled depending on
+ // the configuration.
+ tls = vld.gettls();
+ tls->flags &= ~VLD_TLS_ENABLED;
+ tls->flags |= VLD_TLS_DISABLED;
+}
+
+extern "C" __declspec(dllexport) void VLDEnable ()
+{
+ tls_t *tls;
+
+ if (vld.m_options & VLD_OPT_VLDOFF) {
+ // VLD has been turned off.
+ return;
+ }
+
+ // Enable memory leak detection for the current thread.
+ tls = vld.gettls();
+ tls->flags &= ~VLD_TLS_DISABLED;
+ tls->flags |= VLD_TLS_ENABLED;
+ vld.m_status &= ~VLD_STATUS_NEVER_ENABLED;
+}
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////
+// $Id: vldheap.cpp,v 1.13 2006/11/18 03:12:35 dmouldin Exp $
+//
+// Visual Leak Detector - Internal C++ Heap Management
+// Copyright (c) 2006 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.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include <cassert>
+#define VLDBUILD // Declares that we are building Visual Leak Detector.
+#include "ntapi.h" // Provides access to NT APIs.
+#include "vldheap.h" // Provides access to VLD's internal heap data structures.
+#undef new // Do not map "new" to VLD's new operator in this file
+
+// Global variables.
+vldblockheader_t *vldblocklist = NULL; // List of internally allocated blocks on VLD's private heap.
+HANDLE vldheap; // VLD's private heap.
+CRITICAL_SECTION vldheaplock; // Serializes access to VLD's private heap.
+
+// Local helper functions.
+static inline void vlddelete (void *block);
+static inline void* vldnew (unsigned int size, const char *file, int line);
+
+// scalar delete operator - Delete operator used to free internally used memory
+// back to VLD's private heap.
+//
+// - block (IN): Pointer to the scalar memory block to free.
+//
+// Return Value:
+//
+// None.
+//
+void operator delete (void *block)
+{
+ vlddelete(block);
+}
+
+// vector delete operator - Delete operator used to free internally used memory
+// back to VLD's private heap.
+//
+// - block (IN): Pointer to the vector memory block to free.
+//
+// Return Value:
+//
+// None.
+//
+void operator delete [] (void *block)
+{
+ vlddelete(block);
+}
+
+// scalar delete operator - Delete operator used to free memory partially
+// allocated by new in the event that the corresponding new operator throws
+// an exception.
+//
+// Note: This version of the delete operator should never be called directly.
+// The compiler automatically generates calls to this function as needed.
+//
+void operator delete (void *block, const char *, int)
+{
+ vlddelete(block);
+}
+
+// vector delete operator - Delete operator used to free memory partially
+// allocated by new in the event that the corresponding new operator throws
+// an exception.
+//
+// Note: This version of the delete operator should never be called directly.
+// The compiler automatically generates calls to this function as needed.
+//
+void operator delete [] (void *block, const char *, int)
+{
+ vlddelete(block);
+}
+
+// scalar new operator - New operator used to allocate a scalar memory block
+// from VLD's private heap.
+//
+// - size (IN): Size 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:
+//
+// If the allocation succeeds, a pointer to the allocated memory block is
+// returned. If the allocation fails, NULL is returned.
+//
+void* operator new (unsigned int size, const char *file, int line)
+{
+ return vldnew(size, file, line);
+}
+
+// vector new operator - New operator used to allocate a vector memory block
+// from VLD's private heap.
+//
+// - size (IN): Size 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:
+//
+// If the allocation succeeds, a pointer to the allocated memory block is
+// returned. If the allocation fails, NULL is returned.
+//
+void* operator new [] (unsigned int size, const char *file, int line)
+{
+ return vldnew(size, file, line);
+}
+
+// vlddelete - Local helper function that actually frees memory back to VLD's
+// private heap.
+//
+// - block (IN): Pointer to a memory block being freed.
+//
+// Return Value:
+//
+// None.
+//
+void vlddelete (void *block)
+{
+ BOOL freed;
+ vldblockheader_t *header = VLDBLOCKHEADER((LPVOID)block);
+
+ // Unlink the block from the block list.
+ EnterCriticalSection(&vldheaplock);
+ if (header->prev) {
+ header->prev->next = header->next;
+ }
+ else {
+ vldblocklist = header->next;
+ }
+
+ if (header->next) {
+ header->next->prev = header->prev;
+ }
+ LeaveCriticalSection(&vldheaplock);
+
+ // Free the block.
+ freed = RtlFreeHeap(vldheap, 0x0, header);
+ assert(freed != FALSE);
+}
+
+// vldnew - Local helper function that actually allocates memory from VLD's
+// private heap. Prepends a header, which is used for bookeeping information
+// that allows VLD to detect and report internal memory leaks, to the returned
+// block, but the header is transparent to the caller because the returned
+// pointer points to the useable section of memory requested by the caller, it
+// does not point to the block header.
+//
+// - size (IN): Size of the memory block to be allocated.
+//
+// - file (IN): Name of the file that called the new operator.
+//
+// - line (IN): Line, in the above file, at which the new operator was called.
+//
+// Return Value:
+//
+// If the memory allocation succeeds, a pointer to the allocated memory
+// block is returned. If the allocation fails, NULL is returned.
+//
+void* vldnew (unsigned int size, const char *file, int line)
+{
+ vldblockheader_t *header = (vldblockheader_t*)RtlAllocateHeap(vldheap, 0x0, size + sizeof(vldblockheader_t));
+ static SIZE_T serialnumber = 0;
+
+ if (header == NULL) {
+ // Out of memory.
+ return NULL;
+ }
+
+ // Fill in the block's header information.
+ header->file = file;
+ header->line = line;
+ header->serialnumber = serialnumber++;
+ header->size = size;
+
+ // Link the block into the block list.
+ EnterCriticalSection(&vldheaplock);
+ header->next = vldblocklist;
+ if (header->next != NULL) {
+ header->next->prev = header;
+ }
+ header->prev = NULL;
+ vldblocklist = header;
+ LeaveCriticalSection(&vldheaplock);
+
+ // Return a pointer to the beginning of the data section of the block.
+ return (void*)VLDBLOCKDATA(header);
+}
\ No newline at end of file
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////
+// $Id: vldheap.h,v 1.11 2006/11/18 03:12:35 dmouldin Exp $
+//
+// Visual Leak Detector - Internal C++ Heap Management Definitions
+// Copyright (c) 2006 Dan Moulding
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+//
+// See COPYING.txt for the full terms of the GNU Lesser General Public License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#ifndef VLDBUILD
+#error \
+"This header should only be included by Visual Leak Detector when building it from source. \
+Applications should never include this header."
+#endif
+
+#include <windows.h>
+
+#define GAPSIZE 4
+
+// Memory block header structure used internally by the debug CRT. All blocks
+// allocated by the CRT are allocated from the CRT heap and, in debug mode, they
+// have this header prepended to them (there's also a trailer appended at the
+// end, but we're not interested in that).
+typedef struct crtdbgblockheader_s
+{
+ struct crtblockheader_s *next; // Pointer to the next block in the list of blocks allocated from the CRT heap.
+ struct crtblockheader_s *prev; // Pointer to the previous block in the list of blocks allocated from the CRT heap.
+ char *file; // Source file where this block was allocated.
+ int line; // Line of code, within the above file, where this block was allocated.
+#ifdef _WIN64
+ int use; // This block's "use type": see below.
+ size_t size; // Size of the data portion of the block.
+#else
+ size_t size; // Size of the data portion of the block.
+ int use; // This block's "use type":
+#endif // _WIN64
+#define CRT_USE_FREE 0 // This block has been freed.
+#define CRT_USE_NORMAL 1 // This is a normal (user) block.
+#define CRT_USE_INTERNAL 2 // This block is used internally by the CRT.
+#define CRT_USE_IGNORE 3 // This block is a specially tagged block that is ignored during some debug error checking.
+#define CRT_USE_CLIENT 4 // This block is a specially tagged block with special use defined by the user application.
+ long request; // This block's "request" number. Basically a serial number.
+ unsigned char gap [GAPSIZE]; // No-man's land buffer zone, for buffer overrun/underrun checking.
+} crtdbgblockheader_t;
+
+// Macro to strip off any sub-type information stored in a block's "use type".
+#define CRT_USE_TYPE(use) (use & 0xFFFF)
+
+// Memory block header structure used internally by VLD. All internally
+// allocated blocks are allocated from VLD's private heap and have this header
+// prepended to them.
+typedef struct vldblockheader_s
+{
+ struct vldblockheader_s *next; // Pointer to the next block in the list of internally allocated blocks.
+ struct vldblockheader_s *prev; // Pointer to the preceding block in the list of internally allocated blocks.
+ const char *file; // Name of the file where this block was allocated.
+ int line; // Line number within the above file where this block was allocated.
+ unsigned int size; // The size of this memory block, not including this header.
+ SIZE_T serialnumber; // Each block is assigned a unique serial number, starting from zero.
+} vldblockheader_t;
+
+// Data-to-Header and Header-to-Data conversion
+#define CRTDBGBLOCKHEADER(d) (crtdbgblockheader_t*)(((PBYTE)d) - sizeof(crtdbgblockheader_t))
+#define CRTDBGBLOCKDATA(h) (LPVOID)(((PBYTE)h) + sizeof(crtdbgblockheader_t))
+#define VLDBLOCKHEADER(d) (vldblockheader_t*)(((PBYTE)d) - sizeof(vldblockheader_t))
+#define VLDBLOCKDATA(h) (LPVOID)(((PBYTE)h) + sizeof(vldblockheader_t))
+
+// new and delete operators for allocating from VLD's private heap.
+void operator delete (void *block);
+void operator delete [] (void *block);
+void operator delete (void *block, const char *file, int line);
+void operator delete [] (void *block, const char *file, int line);
+void* operator new (unsigned int size, const char *file, int line);
+void* operator new [] (unsigned int size, const char *file, int line);
+
+// All calls to the new operator from within VLD are mapped to the version of
+// new that allocates from VLD's private heap.
+#define new new(__FILE__, __LINE__)
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////
+// $Id: vldint.h,v 1.45 2006/11/18 05:17:09 dmouldin Exp $
+//
+// Visual Leak Detector - VisualLeakDetector Class Definition
+// Copyright (c) 2005-2006 Dan Moulding
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+//
+// See COPYING.txt for the full terms of the GNU Lesser General Public License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#ifndef VLDBUILD
+#error \
+"This header should only be included by Visual Leak Detector when building it from source. \
+Applications should never include this header."
+#endif
+
+#include <cstdio>
+#include <windows.h>
+#include "callstack.h" // Provides a custom class for handling call stacks.
+#include "map.h" // Provides a custom STL-like map template.
+#include "ntapi.h" // Provides access to NT APIs.
+#include "set.h" // Provides a custom STL-like set template.
+#include "utility.h" // Provides miscellaneous utility functions.
+
+#define MAXMODULELISTLENGTH 512 // Maximum module list length, in characters.
+#define SELFTESTTEXTA "Memory Leak Self-Test"
+#define SELFTESTTEXTW L"Memory Leak Self-Test"
+#define VLDREGKEYPRODUCT L"Software\\Visual Leak Detector"
+#define VLDVERSION L"1.9f"
+
+// The Visual Leak Detector APIs.
+extern "C" __declspec(dllexport) void VLDDisable ();
+extern "C" __declspec(dllexport) void VLDEnable ();
+
+// Data is collected for every block allocated from any heap in the process.
+// The data is stored in this structure and these structures are stored in
+// a BlockMap which maps each of these structures to its corresponding memory
+// block.
+typedef struct blockinfo_s {
+ CallStack *callstack;
+ SIZE_T serialnumber;
+ SIZE_T size;
+} blockinfo_t;
+
+// BlockMaps map memory blocks (via their addresses) to blockinfo_t structures.
+typedef Map<LPCVOID, blockinfo_t*> BlockMap;
+
+// Information about each heap in the process is kept in this map. Primarily
+// this is used for mapping heaps to all of the blocks allocated from those
+// heaps.
+typedef struct heapinfo_s {
+ BlockMap blockmap; // Map of all blocks allocated from this heap.
+ UINT32 flags; // Heap status flags:
+#define VLD_HEAP_CRT 0x1 // If set, this heap is a CRT heap (i.e. the CRT uses it for new/malloc).
+} heapinfo_t;
+
+// HeapMaps map heaps (via their handles) to BlockMaps.
+typedef Map<HANDLE, heapinfo_t*> HeapMap;
+
+// This structure stores information, primarily the virtual address range, about
+// a given module and can be used with the Set template because it supports the
+// '<' operator (sorts by virtual address range).
+typedef struct moduleinfo_s {
+ BOOL operator < (const struct moduleinfo_s &other) const
+ {
+ if (addrhigh < other.addrlow) {
+ return TRUE;
+ }
+ else {
+ return FALSE;
+ }
+ }
+
+ SIZE_T addrhigh; // Highest address within the module's virtual address space (i.e. base + size).
+ SIZE_T addrlow; // Lowest address within the module's virtual address space (i.e. base address).
+ UINT32 flags; // Module flags:
+#define VLD_MODULE_EXCLUDED 0x1 // If set, this module is excluded from leak detection.
+#define VLD_MODULE_SYMBOLSLOADED 0x2 // If set, this module's debug symbols have been loaded.
+ LPCSTR name; // The module's name (e.g. "kernel32.dll").
+ LPCSTR path; // The fully qualified path from where the module was loaded.
+} moduleinfo_t;
+
+// ModuleSets store information about modules loaded in the process.
+typedef Set<moduleinfo_t> ModuleSet;
+
+// Thread local storage structure. Every thread in the process gets its own copy
+// of this structure. Thread specific information, such as the currentl leak
+// detection status (enabled or disabled) and the address that initiated the
+// current allocation is stored here.
+typedef struct tls_s {
+ SIZE_T addrfp; // Frame pointer at the first call that entered VLD's code for the current allocation.
+ UINT32 flags; // Thread-local status flags:
+#define VLD_TLS_CRTALLOC 0x1 // If set, the current allocation is a CRT allocation.
+#define VLD_TLS_DISABLED 0x2 // If set, memory leak detection is disabled for the current thread.
+#define VLD_TLS_ENABLED 0x4 // If set, memory leak detection is enabled for the current thread.
+ DWORD threadid; // Thread ID of the thread that owns this TLS structure.
+} tls_t;
+
+// The TlsSet allows VLD to keep track of all thread local storage structures
+// allocated in the process.
+typedef Set<tls_t*> TlsSet;
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// The VisualLeakDetector Class
+//
+// One global instance of this class is instantiated. Upon construction it
+// patches the import address table (IAT) of every other module loaded in the
+// process (see the "patchimport" utility function) to allow key Windows heap
+// APIs to be patched through to, or redirected to, functions provided by VLD.
+// Patching the IATs in this manner allows VLD to be made aware of all
+// relevant heap activity, making it possible for VLD to detect and trace
+// memory leaks.
+//
+// The one global instance of this class is constructed within the context of
+// the process' main thread during process initialization and is destroyed in
+// the same context during process termination.
+//
+// When the VisualLeakDetector object is destroyed, it consults its internal
+// datastructures, looking for any memory that has not been freed. A memory
+// leak report is then generated, indicating any memory leaks that may have
+// been identified.
+//
+// This class is derived from IMalloc so that it can provide an implementation
+// of the IMalloc COM interface in order to support detection of COM-based
+// memory leaks. However, this implementation of IMalloc is actually just a
+// thin wrapper around the system's implementation of IMalloc.
+//
+class VisualLeakDetector : public IMalloc
+{
+public:
+ VisualLeakDetector();
+ ~VisualLeakDetector();
+
+ // Public IMalloc methods - for support of COM-based memory leak detection.
+ ULONG __stdcall AddRef ();
+ LPVOID __stdcall Alloc (ULONG size);
+ INT __stdcall DidAlloc (LPVOID mem);
+ VOID __stdcall Free (LPVOID mem);
+ ULONG __stdcall GetSize (LPVOID mem);
+ VOID __stdcall HeapMinimize ();
+ HRESULT __stdcall QueryInterface (REFIID iid, LPVOID *object);
+ LPVOID __stdcall Realloc (LPVOID mem, ULONG size);
+ ULONG __stdcall Release ();
+
+private:
+ // Import patching replacement functions - see each function definition for details.
+ static HRESULT __stdcall _CoGetMalloc (DWORD context, LPMALLOC *imalloc);
+ static LPVOID __stdcall _CoTaskMemAlloc (ULONG size);
+ static LPVOID __stdcall _CoTaskMemRealloc (LPVOID mem, ULONG size);
+ static void* __cdecl _crt80d__calloc_dbg (size_t num, size_t size, int type, const char *file, int line);
+ static void* __cdecl _crt80d__malloc_dbg (size_t size, int type, const char *file, int line);
+ static void* __cdecl _crt80d__realloc_dbg (void *mem, size_t size, int type, const char *file, int line);
+ static void* __cdecl _crt80d__scalar_new_dbg (unsigned int size, int type, const char *file, int line);
+ static void* __cdecl _crt80d__vector_new_dbg (unsigned int size, int type, const char *file, int line);
+ static void* __cdecl _crt80d_calloc (size_t num, size_t size);
+ static void* __cdecl _crt80d_malloc (size_t size);
+ static void* __cdecl _crt80d_realloc (void *mem, size_t size);
+ static void* __cdecl _crt80d_scalar_new (unsigned int size);
+ static void* __cdecl _crt80d_vector_new (unsigned int size);
+ static void* __cdecl _crtd__calloc_dbg (size_t num, size_t size, int type, const char *file, int line);
+ static void* __cdecl _crtd__malloc_dbg (size_t size, int type, const char *file, int line);
+ static void* __cdecl _crtd__realloc_dbg (void *mem, size_t size, int type, const char *file, int line);
+ static void* __cdecl _crtd__scalar_new_dbg (unsigned int size, int type, const char *file, int line);
+ static void* __cdecl _crtd_calloc (size_t num, size_t size);
+ static void* __cdecl _crtd_malloc (size_t size);
+ static void* __cdecl _crtd_realloc (void *mem, size_t size);
+ static void* __cdecl _crtd_scalar_new (unsigned int size);
+ static FARPROC __stdcall _GetProcAddress(HMODULE module, LPCSTR procname);
+ static HANDLE __stdcall _HeapCreate (DWORD options, SIZE_T initsize, SIZE_T maxsize);
+ static BOOL __stdcall _HeapDestroy (HANDLE heap);
+ static NTSTATUS __stdcall _LdrLoadDll (LPWSTR searchpath, PDWORD flags, unicodestring_t *modulename,
+ PHANDLE modulehandle);
+ static void* __cdecl _mfc42d__scalar_new_dbg (unsigned int size, const char *file, int line);
+ static void* __cdecl _mfc42d_scalar_new (unsigned int size);
+ static void* __cdecl _mfc80d__scalar_new_dbg (unsigned int size, const char *file, int line);
+ static void* __cdecl _mfc80d__vector_new_dbg (unsigned int size, const char *file, int line);
+ static void* __cdecl _mfc80d_scalar_new (unsigned int size);
+ static void* __cdecl _mfc80d_vector_new (unsigned int size);
+ static LPVOID __stdcall _RtlAllocateHeap (HANDLE heap, DWORD flags, SIZE_T size);
+ static BOOL __stdcall _RtlFreeHeap (HANDLE heap, DWORD flags, LPVOID mem);
+ static LPVOID __stdcall _RtlReAllocateHeap (HANDLE heap, DWORD flags, LPVOID mem, SIZE_T size);
+
+ // Private functions - see each function definition for details.
+ static BOOL __stdcall addloadedmodule (PCWSTR modulepath, DWORD64 modulebase, ULONG modulesize, PVOID context);
+ VOID attachtoloadedmodules (ModuleSet *newmodules);
+ LPWSTR buildsymbolsearchpath ();
+ VOID configure ();
+ static BOOL __stdcall detachfrommodule (PCWSTR modulepath, DWORD64 modulebase, ULONG modulesize, PVOID context);
+ BOOL enabled ();
+ SIZE_T eraseduplicates (const BlockMap::Iterator &element);
+ tls_t* gettls ();
+ VOID mapblock (HANDLE heap, LPCVOID mem, SIZE_T size, SIZE_T framepointer, BOOL crtalloc);
+ VOID mapheap (HANDLE heap);
+ VOID remapblock (HANDLE heap, LPCVOID mem, LPCVOID newmem, SIZE_T size, SIZE_T framepointer, BOOL crtalloc);
+ VOID reportconfig ();
+ VOID reportleaks (HANDLE heap);
+ VOID unmapblock (HANDLE heap, LPCVOID mem);
+ VOID unmapheap (HANDLE heap);
+
+ // Private data.
+ WCHAR m_forcedmodulelist [MAXMODULELISTLENGTH]; // List of modules to be forcefully included in leak detection.
+ HeapMap *m_heapmap; // Map of all active heaps in the process.
+ IMalloc *m_imalloc; // Pointer to the system implementation of IMalloc.
+ SIZE_T m_leaksfound; // Total number of leaks found.
+ ModuleSet *m_loadedmodules; // Contains information about all modules loaded in the process.
+ CRITICAL_SECTION m_loaderlock; // Serializes the attachment of newly loaded modules.
+ CRITICAL_SECTION m_maplock; // Serializes access to the heap and block maps.
+ SIZE_T m_maxdatadump; // Maximum number of user-data bytes to dump for each leaked block.
+ UINT32 m_maxtraceframes; // Maximum number of frames per stack trace for each leaked block.
+ CRITICAL_SECTION m_moduleslock; // Protects accesses to the "loaded modules" ModuleSet.
+ UINT32 m_options; // Configuration options:
+#define VLD_OPT_AGGREGATE_DUPLICATES 0x1 // If set, aggregate duplicate leaks in the leak report.
+#define VLD_OPT_MODULE_LIST_INCLUDE 0x2 // If set, modules in the module list are included, all others are excluded.
+#define VLD_OPT_REPORT_TO_DEBUGGER 0x4 // If set, the memory leak report is sent to the debugger.
+#define VLD_OPT_REPORT_TO_FILE 0x8 // If set, the memory leak report is sent to a file.
+#define VLD_OPT_SAFE_STACK_WALK 0x10 // If set, the stack is walked using the "safe" method (StackWalk64).
+#define VLD_OPT_SELF_TEST 0x20 // If set, peform a self-test to verify memory leak self-checking.
+#define VLD_OPT_SLOW_DEBUGGER_DUMP 0x40 // If set, inserts a slight delay between sending output to the debugger.
+#define VLD_OPT_START_DISABLED 0x80 // If set, memory leak detection will initially disabled.
+#define VLD_OPT_TRACE_INTERNAL_FRAMES 0x100 // If set, include useless frames (e.g. internal to VLD) in call stacks.
+#define VLD_OPT_UNICODE_REPORT 0x200 // If set, the leak report will be encoded UTF-16 instead of ASCII.
+#define VLD_OPT_VLDOFF 0x400 // If set, VLD will be completely deactivated. It will not attach to any modules.
+ static patchentry_t m_patchtable []; // Table of imports patched for attaching VLD to other modules.
+ FILE *m_reportfile; // File where the memory leak report may be sent to.
+ WCHAR m_reportfilepath [MAX_PATH]; // Full path and name of file to send memory leak report to.
+ const char *m_selftestfile; // Filename where the memory leak self-test block is leaked.
+ int m_selftestline; // Line number where the memory leak self-test block is leaked.
+ UINT32 m_status; // Status flags:
+#define VLD_STATUS_DBGHELPLINKED 0x1 // If set, the explicit dynamic link to the Debug Help Library succeeded.
+#define VLD_STATUS_INSTALLED 0x2 // If set, VLD was successfully installed.
+#define VLD_STATUS_NEVER_ENABLED 0x4 // If set, VLD started disabled, and has not yet been manually enabled.
+#define VLD_STATUS_FORCE_REPORT_TO_FILE 0x8 // If set, the leak report is being forced to a file.
+ DWORD m_tlsindex; // Thread-local storage index.
+ CRITICAL_SECTION m_tlslock; // Protects accesses to the Set of TLS structures.
+ TlsSet *m_tlsset; // Set of all all thread-local storage structres for the process.
+ HMODULE m_vldbase; // Visual Leak Detector's own module handle (base address).
+
+ // The Visual Leak Detector APIs are our friends.
+ friend __declspec(dllexport) void VLDDisable ();
+ friend __declspec(dllexport) void VLDEnable ();
+};
+
+// Configuration option default values
+#define VLD_DEFAULT_MAX_DATA_DUMP 0xffffffff
+#define VLD_DEFAULT_MAX_TRACE_FRAMES 0xffffffff
+#define VLD_DEFAULT_REPORT_FILE_NAME L".\\memory_leak_report.txt"
--- /dev/null
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\r
+;; $Id: vld.ini,v 1.7 2006/11/18 03:12:35 dmouldin Exp $\r
+;;\r
+;; Visual Leak Detector - Initialization/Configuration File\r
+;; Copyright (c) 2006 Dan Moulding\r
+;;\r
+;; This library is free software; you can redistribute it and/or\r
+;; modify it under the terms of the GNU Lesser General Public\r
+;; License as published by the Free Software Foundation; either\r
+;; version 2.1 of the License, or (at your option) any later version.\r
+;;\r
+;; This library is distributed in the hope that it will be useful,\r
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+;; Lesser General Public License for more details.\r
+;;\r
+;; You should have received a copy of the GNU Lesser General Public\r
+;; License along with this library; if not, write to the Free Software\r
+;; Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\r
+;;\r
+;; See COPYING.txt for the full terms of the GNU Lesser General Public License.\r
+;;\r
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\r
+\r
+; Any options left blank or not present will revert to their default values.\r
+[Options]\r
+\r
+; The main on/off switch. If off, Visual Leak Detector will be completely\r
+; disabled. It will do nothing but print a message to the debugger indicating\r
+; that it has been turned off.\r
+;\r
+; Valid Values: on, off\r
+; Default: on\r
+;\r
+VLD = on\r
+\r
+; If yes, duplicate leaks (those that are identical) are not shown individually.\r
+; Only the first such leak is shown, along with a number indicating the total\r
+; number of duplicate leaks.\r
+;\r
+; Valid Values: yes, no\r
+; Default: no\r
+;\r
+AggregateDuplicates = no\r
+\r
+; Lists any additional modules to be included in memory leak detection. This can\r
+; be useful for checking for memory leaks in debug builds of 3rd party modules\r
+; which can not be easily rebuilt with '#include "vld.h"'. This option should be\r
+; used only if absolutely necessary and only if you really know what you are\r
+; doing.\r
+;\r
+; CAUTION: Avoid listing any modules that link with the release CRT libraries.\r
+; Only modules that link with the debug CRT libraries should be listed here.\r
+; Doing otherwise might result in false memory leak reports or even crashes.\r
+;\r
+; Valid Values: Any list containing module names (i.e. names of EXEs or DLLs).\r
+; Default: None.\r
+;\r
+ForceIncludeModules =\r
+\r
+; Maximum number of data bytes to display for each leaked block. If zero, then\r
+; the data dump is completely suppressed and only call stacks are shown.\r
+; Limiting this to a low number can be useful if any of the leaked blocks are\r
+; very large and cause unnecessary clutter in the memory leak report.\r
+;\r
+; Value Values: 0 - 4294967295\r
+; Default: 4294967295\r
+;\r
+MaxDataDump = \r
+\r
+; Maximum number of call stack frames to trace back during leak detection.\r
+; Limiting this to a low number can reduce the CPU utilization overhead imposed\r
+; by memory leak detection, especially when using the slower "safe" stack\r
+; walking method (see StackWalkMethod below).\r
+;\r
+; Valid Values: 1 - 4294967295\r
+; Default: 4294967295\r
+;\r
+MaxTraceFrames = \r
+\r
+; Sets the type of encoding to use for the generated memory leak report. This\r
+; option is really only useful in conjuction with sending the report to a file.\r
+; Sending a Unicode encoded report to the debugger is not useful because the\r
+; debugger cannot display Unicode characters. Using Unicode encoding might be\r
+; useful if the data contained in leaked blocks is likely to consist of Unicode\r
+; text.\r
+;\r
+; Valid Values: ascii, unicode\r
+; Default: ascii\r
+;\r
+ReportEncoding = ascii\r
+\r
+; Sets the report file destination, if reporting to file is enabled. A relative\r
+; path may be specified and is considered relative to the process' working\r
+; directory.\r
+;\r
+; Valid Values: Any valid path and filename.\r
+; Default: .\memory_leak_report.txt\r
+;\r
+ReportFile = \r
+\r
+; Sets the report destination to either a file, the debugger, or both. If\r
+; reporting to file is enabled, the report is sent to the file specified by the\r
+; ReportFile option.\r
+;\r
+; Valid Values: debugger, file, both\r
+; Default: debugger\r
+;\r
+ReportTo = debugger\r
+\r
+; Turns on or off a self-test mode which is used to verify that VLD is able to\r
+; detect memory leaks in itself. Intended to be used for debugging VLD itself,\r
+; not for debugging other programs.\r
+;\r
+; Valid Values: on, off\r
+; Default: off\r
+;\r
+SelfTest = off\r
+\r
+; Selects the method to be used for walking the stack to obtain stack traces for\r
+; allocated memory blocks. The "fast" method may not always be able to\r
+; successfully trace completely through all call stacks. In such cases, the\r
+; "safe" method may prove to more reliably obtain the full stack trace. The\r
+; disadvantage is that the "safe" method is significantly slower than the "fast"\r
+; method and will probably result in very noticeable performance degradation of\r
+; the program being debugged.\r
+;\r
+; Valid Values: fast, safe\r
+; Default: fast\r
+; \r
+StackWalkMethod = fast\r
+\r
+; Determines whether memory leak detection should be initially enabled for all\r
+; threads, or whether it should be initially disabled for all threads. If set\r
+; to "yes", then any threads requiring memory leak detection to be enabled will\r
+; need to call VLDEnable at some point to enable leak detection for those\r
+; threads.\r
+;\r
+; Valid Values: yes, no\r
+; Default: no\r
+;\r
+StartDisabled = no\r
+\r
+; Determines whether or not all frames, including frames internal to the heap,\r
+; are traced. There will always be a number of frames internal to Visual Leak\r
+; Detector and C/C++ or Win32 heap APIs that aren't generally useful for\r
+; determining the cause of a leak. Normally these frames are skipped during the\r
+; stack trace, which somewhat reduces the time spent tracing and amount of data\r
+; collected and stored in memory. Including all frames in the stack trace, all\r
+; the way down into VLD's own code can, however, be useful for debugging VLD\r
+; itself.\r
+;\r
+; Valid Values: yes, no\r
+; Default: no\r
+;\r
+TraceInternalFrames = no\r