add leak tool for msvc 'Visual Leak Detection' 1.9f: original files

git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@21911 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Peter Kümmel 2007-12-02 11:05:21 +00:00
parent a66d9c825b
commit c0708a5c5e
19 changed files with 8802 additions and 0 deletions

View File

@ -0,0 +1,344 @@
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

View File

@ -0,0 +1,458 @@
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.
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.
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.
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.
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.
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.
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.
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.
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

View File

@ -0,0 +1,747 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr">
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
<style title="Visual Leak Detector" type="text/css" media="screen,print">
body {
margin: 0;
font-family: verdana, sans-serif;
}
#masthead {
border-width: 0 0 1px 0;
border-style: solid;
border-color: #808080;
color: #ffffff;
background-color: #3569cc;
}
#content {
margin: 1em 1em 1em 1em;
font-size: 10pt;
}
#toc {
float: right;
color: #000000;
background-color: #ffeda5;
}
h1 {
margin: 0 0 0 0;
padding: 0.5em 1em 0 1em;
text-align: right;
font-size: 24pt;
font-family: arial, sans-serif;
}
h2 {
margin-top: 0;
border-width: 2px;
border-style: solid;
border-color: #3569cc;
padding-left: 1em;
font-size: 16pt;
font-family: "trebuchet ms", sans-serif;
letter-spacing: -1pt;
color: #000000;
background-color: #6599fc;
}
h3 {
font-size: 11pt;
}
li {
margin-bottom: 1em;
}
#toc h2 {
margin: 0;
border-width: 2px 2px 2px 0;
border-style: solid;
border-color: #6599fc;
text-align: center;
color: #ffffff;
background-color: #3569cc;
}
#toc ul {
margin-left: 0;
padding: 0;
list-style: none;
}
#toc li {
margin: 1em;
}
a {
color: #0000ff;
background-color: inherit;
text-decoration:none;
}
a:hover {
text-decoration: underline;
}
a:visited {
color: #0000ff;
background-color: inherit;
}
.api {
font-size: 12pt;
font-weight: bold;
}
.code {
font-family: "courier new", monospace;
color: #000000;
background-color: #e0e0e0;
}
.filename {
font-style: italic;
}
.function {
font-style: italic;
}
.note {
margin-left: 2em;
}
.operator {
font-style: italic;
}
.option {
font-size: 10pt;
font-weight: bold;
}
ul.vcsearchpath {
border-width: 1px;
border-style: dashed;
border-color: #000000;
color: #000000;
background-color: #ffeda5;
list-style: none;
}
ul.vcsearchpath li {
margin-bottom: 0;
}
#slogan {
margin-bottom: 0;
padding: 0 1em 1em 1em;
border-width: 0 0 1px 0;
border-style: solid;
border-color: #404040;
text-align: right;
font-size: larger;
font-style: italic;
color: #6599fc;
background-color: inherit;
}
#copyright {
text-align: right;
font-family: georgia, serif;
color: #808080;
background-color: inherit;
}
#compliance {
text-align: right;
}
#compliance img {
border: 0;
}
blockquote {
font-style: italic;
}
</style>
<title>Visual Leak Detector (Beta)</title>
</head>
<body>
<div id="masthead">
<h1>Visual&nbsp;Leak&nbsp;Detector&nbsp;1.9f (Beta)</h1>
<p id="slogan">Enhanced Memory Leak Detection for Visual&nbsp;C++</p>
</div> <!-- #masthead -->
<div id="content">
<div id="toc">
<h2>Table of Contents</h2>
<ul>
<li><a href="#intro">Introduction</a></li>
<li><a href="#use">Using Visual&nbsp;Leak&nbsp;Detector</a></li>
<li><a href="#configure">Configuration Options</a></li>
<li><a href="#control">Controlling Leak Detection at Runtime</a></li>
<li><a href="#build">Building Visual&nbsp;Leak&nbsp;Detector from Source</a></li>
<li><a href="#x64">Windows x64 Support</a></li>
<li><a href="#faq">Frequently Asked Questions</a></li>
<li><a href="#restrictions">Known Restrictions</a></li>
<li><a href="#license">License</a></li>
<li><a href="#contact">Contacting the Author</a></li>
</ul>
</div> <!-- #toc -->
<h2 id="intro">Introduction</h2>
<p>Visual&nbsp;C++ provides built-in memory leak detection, but its capabilities are minimal at best. This memory leak
detector was created as a free alternative to the built-in memory leak detector provided with Visual&nbsp;C++. Here
are some of Visual&nbsp;Leak&nbsp;Detector's features, none of which exist in the built-in detector:</p>
<ul>
<li>Provides a complete stack trace for each leaked block, including source file and line number information when
available.</li>
<li>Detects most, if not all, types of in-process memory leaks including COM-based leaks, and pure Win32 heap-based
leaks.</li>
<li>Selected modules (DLLs or even the main EXE) can be excluded from leak detection.</li>
<li>Provides complete data dumps (in hex and ASCII) of leaked blocks.</li>
<li>Customizable memory leak report: can be saved to a file or sent to the debugger and can include a variable level
of detail.</li>
</ul>
<p>Other after-market leak detectors for Visual&nbsp;C++ are already available. But most of the really popular ones,
like Purify and BoundsChecker, are very expensive. A few free alternatives exist, but they're often too intrusive,
restrictive, or unreliable. Visual&nbsp;Leak&nbsp;Detector is currently the only freely available memory leak
detector for Visual C++ that provides all of the above professional-level features packaged neatly in an easy-to-use
library.</p>
<p>Visual Leak Detector is <a href="#license">licensed</a> free of charge as a service to the Windows developer
community. If you find it to be useful and would like to just say "Thanks!", or you think it stinks and would like to
say "This thing sucks!", please feel free to <a href="mailto:dmoulding@gmail.com">drop me a note</a>. Or, if you'd
prefer, you can <a href="#contact">contribute a small donation</a>. Both are very appreciated.</p>
<h2 id="use">Using Visual&nbsp;Leak&nbsp;Detector</h2>
<p>This section briefly describes the basics of using Visual&nbsp;Leak&nbsp;Detector (VLD).</p>
<p><strong>Important! :</strong> Before using VLD with any Visual C++ project, you must first add the Visual Leak
Detector include and library directories to the Visual C++ include and library directory search paths:</p>
<ul>
<li><strong>Visual&nbsp;C++ 8</strong>: Go to Tools -> Options -> Projects and Solutions -> VC++ Directories.
Select "Include files" from the "Show Directories For" drop-down menu. Add the
<span class="filename">include</span> subdirectory from the Visual Leak Detector installation directory. Move it
to the bottom of the list. Then select "Library files" from the drop-down menu and add the
<span class="filename">lib</span> subdirectory from the Visual Leak Detector installation directory. Again, move
it to the bottom of the list.</li>
<li><strong>Visual&nbsp;C++ 7</strong>: Go to Project Properties -> C/C++ -> General -> Additional Include
Directories and add the <span class="filename">include</span> subdirectory from the Visual Leak Detector
installation directory. Move it to the bottom of the list. Then select Additional Library Directories and add
the <span class="filename">lib</span> subdirectory from the Visual Leak Detector installation directory. Again,
move it to the bottom of the list.</li>
<li><strong>Visual&nbsp;C++ 6</strong>: Go to Tools -> Options -> Directories. Select "Include files" from
the "Show Directories For" drop-down menu. Add the <span class="filename">include</span> subdirectory
from the Visual Leak Detector installation directory. Move it to the bottom of the list. Then select "Library
files" from the drop-down menu and add the <span class="filename">lib</span> subdirectory from the Visual Leak
Detector installation directory. Again, move it to the bottom of the list.</li>
</ul>
<p>To use VLD with your project, follow these simple steps:</p>
<ol>
<li>In at least one C/C++ source file from your program, include the <span class="filename">vld.h</span> header
file. It should not matter which file you add the include statement to. It also should not matter in what order
the header is included in relation to other headers. The only exception is
<span class="filename">stdafx.h</span> (or any other precompiled header). A precompiled header, such as
<span class="filename">stdafx.h</span>, must always be the first header included in a source file, so
<span class="filename">vld.h</span> must be included after any precompiled headers.</li>
<li>If your program contains one or more DLLs that you would also like to check for memory leaks, then also include
<span class="filename">vld.h</span> in at least one source file from each DLL to be included in leak
detection.</li>
<li>Build the debug version of your program.</li>
</ol>
<p class="note"><strong>Note:</strong> Unlike earlier (pre-1.9) versions of VLD, it is now acceptable to include
<span class="filename">vld.h</span> in every source file, or to include it in a common header that is included by
many or all source files. Only one copy of the VLD code will be loaded into the process, regardless of how many
source files include <span class="filename">vld.h</span>.</p>
<p>VLD will detect memory leaks in your program whenever you run the debug version. When you run the program under the
Visual&nbsp;C++ debugger, a report of all the memory leaks detected will be displayed in the debugger's output window
when your program exits (the report can optionally be saved to a file instead, see
<span class="option">ReportFile</span> under <a href="#configure">Configuration Options</a>). Double-clicking on a
source file's line number in the memory leak report will take you to that file and line in the editor window,
allowing easy navigation of the code path leading up to the allocation that resulted in the memory leak.</p>
<p class="note"><strong>Note:</strong> When you build release versions of your program, VLD will not be linked into the
executable. So it is safe to leave <span class="filename">vld.h</span> included in your source files when doing
release builds. Doing so will not result in any performance degradation or any other undesirable overhead.</p>
<h2 id="configure">Configuration Options</h2>
<p>There are a several configuration options that control specific aspects of VLD's operation. These configuration
options are stored in the <span class="filename">vld.ini</span> configuration file. By default, the configuration
file should be in the Visual Leak Detector installation directory. However, the configuration file can be copied to
the program's working directory, in which case the configuration settings in that copy of
<span class="filename">vld.ini</span> will apply only when debugging that one program.</p>
<dl>
<dt class="option">VLD</dt>
<dd>
<p>This option acts as a master on/off switch. By default, this option is set to "on". To <em>completely
disable</em> Visual Leak Detector at runtime, set this option to "off". When VLD is turned off using this
option, it will do nothing but print a message to the debugger indicating that it has been turned off.</p>
</dd>
<dt class="option">AggregateDuplicates</dt>
<dd>
<p>Normally, VLD displays each individual leaked block in detail. Setting this option to "yes" will make VLD
aggregate all leaks that share the same size and call stack under a single entry in the memory leak report.
Only the first leaked block will be reported in detail. No other identical leaks will be displayed. Instead,
a tally showing the total number of leaks matching that size and call stack will be shown. This can be useful
if there are only a few sources of leaks, but those few sources are repeatedly leaking a very large number of
memory blocks.</p>
</dd>
<dt class="option">ForceIncludeModules</dt>
<dd>
<p>In some rare cases, it may be necessary to include a module in leak detection, but it may not be possible to
include <span class="filename">vld.h</span> in any of the module's sources. In such cases, this option can be
used to force VLD to include those modules in leak detection. List the names of the modules (DLLs) to be
forcefully included in leak detection. If you do use this option, it's advisable to also add
<span class="filename">vld.lib</span> to the list of library modules in the linker options of your project's
settings.</p>
<p class="note"><strong>Caution:</strong> Use this option only when absolutely necessary. In some situations,
use of this option may result in unpredictable behavior including false leak reports and/or crashes. It's
best to stay away from this option unless you are sure you understand what you are doing.</p>
</dd>
<dt class="option">MaxDataDump</dt>
<dd>
<p>Set this option to an integer value to limit the amount of data displayed in memory block data dumps. When
this number of bytes of data have been dumped, the dump will stop. This can be useful if any of the leaked
blocks are very large and the debugger's output window becomes too cluttered. You can set this option to 0
(zero) if you want to suppress data dumps altogether.</p>
</dd>
<dt class="option">MaxTraceFrames</dt>
<dd>
<p>By default, VLD will trace the call stack for each allocated block as far back as possible. Each frame traced
adds additional overhead (in both CPU time and memory usage) to your debug executable. If you'd like to limit
this overhead, you can define this macro to an integer value. The stack trace will stop when it has traced
this number of frames. The frame count may include some of the "internal" frames which, by default, are not
displayed in the debugger's output window (see <span class="option">TraceInternalFrames</span> below). In
some cases there may be about three or four "internal" frames at the beginning of the call stack. Keep this
in mind when using this macro, or you may not see the number of frames you expect.</p>
</dd>
<dt class="option">ReportEncoding</dt>
<dd>
<p>When the memory leak report is saved to a file, the report may optionally be Unicode encoded instead of using
the default ASCII encoding. This might be useful if the data contained in leaked blocks is likely to consist
of Unicode text. Set this option to "unicode" to generate a Unicode encoded report.</p>
</dd>
<dt class="option">ReportFile</dt>
<dd>
<p>Use this option to specify the name and location of the file in which to save the memory leak report when
using a file as the report destination, as specified by the <span class="option">ReportTo</span> option. If
no file is specified here, then VLD will save the report in a file named "memory_leak_report.txt" in the
working directory of the program.</p>
</dd>
<dt class="option">ReportTo</dt>
<dd>
<p>The memory leak report may be sent to a file in addition to, or instead of, the debugger. Use this option to
specify which type of destination to use. Specify one of "debugger" (the default), "file", or "both".</p>
</dd>
<dt class="option">SelfTest</dt>
<dd>
<p>VLD has the ability to check itself for memory leaks. This feature is always active. Every time you run VLD,
in addition to checking your own program for memory leaks, it is also checking itself for leaks. Setting this
option to "on" forces VLD to intentionally leak a small amount of memory: a 21-character block filled with
the text "Memory Leak Self-Test". This provides a way to test VLD's ability to check itself for memory leaks
and verify that this capability is working correctly. This option is usually only useful for debugging VLD
itself.</p>
</dd>
<dt class="option">SlowDebuggerDump</dt>
<dd>
<p>If enabled, this option causes Visual Leak Detector to write the memory leak report to the debugger's output
window at a slower than normal rate. This option is specifically designed to work around a known issue with
some older versions of Visual Studio where some data sent to the output window might be lost if it is sent
too quickly. If you notice that some information seems to be missing from the memory leak report, try turning
this on.</p>
</dd>
<dt class="option">StackWalkMethod</dt>
<dd>
<p>Selects the method to be used for walking the stack to obtain call stacks for allocated memory blocks. The
default "fast" method may not always be able to successfully trace completely through all call stacks. In
such cases, the "safe" method may prove to be more reliable in obtaining the full stack trace. The
disadvantage with the "safe" method is that it is significantly slower than the "fast" method and will
probably result in very noticeable performance degradation of the program being debugged. In most cases it
should be okay to leave this option set to "fast". If you experience problems getting VLD to show call
stacks, you can try setting this option to "safe".</p>
<p>If you do use the "safe" method, and notice a significant performance decrease, you may want to consider
using the <span class="option">MaxTraceFrames</span> option to limit the number of frames traced to a
relatively small number. This can reduce the amount of time spent tracing the stack by a very large
amount.</p>
</dd>
<dt class="option">StartDisabled</dt>
<dd>
<p>Set this option to "yes" to disable memory leak detection initially. This can be useful if you need to be
able to selectively enable memory leak detection from runtime, without needing to rebuild the executable;
however, this option should be used with caution. Any memory leaks that may occur before memory leak
detection is enabled at runtime will go undetected. For example, if the constructor of some global variable
allocates memory before execution reaches a subsequent call to <span class="function">VLDEnable</span>, then
VLD will not be able to detect if the memory allocated by the global variable is never freed. Refer to the
following section on <a href="#control">controlling leak detection at runtime</a> for details on using the
runtime APIs which can be useful in conjunction with this option.</p>
</dd>
<dt class="option">TraceInternalFrames</dt>
<dd>
<p>This option determines whether or not all frames of the call stack, including frames internal to the heap,
are traced. There will always be a number of frames on the call stack which are internal to Visual Leak
Detector and C/C++ or Win32 heap APIs that aren't generally useful for determining the cause of a leak.
Normally these frames are skipped during the stack trace, which somewhat reduces the time spent tracing and
amount of data collected and stored in memory. Including all frames in the stack trace, all the way down into
VLD's own code can, however, be useful for debugging VLD itself.</p>
</dd>
</dl>
<h2 id="control">Controlling Leak Detection at Runtime</h2>
<p>Using the default configuration, VLD's memory leak detection will be enabled during the entire run of your program.
In certain scenarios it may be desirable to selectively disable memory leak detection in certain segments of your
code. VLD provides simple APIs for controlling the state of memory leak detection at runtime. To access these APIs,
include <span class="filename">vld.h</span> in the source file that needs to use them.</p>
<dl>
<dt class="api">VLDDisable</dt>
<dd>
<p>This function disables memory leak detection. After calling this function, memory leak detection will remain
disabled until it is explicitly re-enabled via a call to VLDEnable.</p>
<pre class="code">void VLDDisable (void);</pre>
<h3>Arguments:</h3>
<p>This function accepts no arguments.</p>
<h3>Return Value:</h3>
<p>None (this function always succeeds).</p>
<h3>Notes:</h3>
<p>This function controls memory leak detection on a per-thread basis. In other words, calling this function
disables memory leak detection for only the thread that called the function. Memory leak detection will
remain enabled for any other threads in the same process. This insulates the programmer from having to
synchronize multiple threads that disable and enable memory leak detection. However, note also that this
means that in order to disable memory leak detection process-wide, this function must be called from every
thread in the process.</p>
</dd>
<dt class="api">VLDEnable</dt>
<dd>
<p>This function enables memory leak detection if it was previously disabled. After calling this function,
memory leak detection will remain enabled unless it is explicitly disabled again via a call to
VLDDisable().</p>
<pre class="code">void VLDEnable (void);</pre>
<h3>Arguments:</h3>
<p>This function accepts no arguments.</p>
<h3>Return Value:</h3>
<p>None (this function always succeeds).</p>
<h3>Notes:</h3>
<p>This function controls memory leak detection on a per-thread basis. See the remarks for
<span class="function">VLDDisable</span> regarding multithreading and memory leak detection for details.
Those same concepts also apply to this function.</p>
</dd>
</dl>
<h2 id="build">Building Visual&nbsp;Leak&nbsp;Detector from Source</h2>
<p>Because Visual&nbsp;Leak&nbsp;Detector is open source, it can be built from source if you want to tweak it to your
liking. The most difficult part about building VLD from source is getting your build environment correctly set up.
But if you follow these instructions carefully, the process should be fairly painless.</p>
<ol>
<li>VLD depends on the Debug Help Library. This library is part of
<a href="http://www.microsoft.com/whdc/devtools/debugging/default.mspx">Debugging Tools for Windows</a> (DTfW).
Download and install DTfW in order to install the required headers and libraries. I recommend installing version
6.5 of DTfW. Newer versions may also work, but older versions will probably not work. Be sure to manually select
to install the SDK files during the DTfW installation or the headers and libraries will not be installed (they
are not installed with a default installation).</li>
<li>Visual&nbsp;C++ will need to be made aware of where it can find the Debug Help Library header and library files.
Add the <span class="filename">sdk\inc</span> and <span class="filename">sdk\lib</span> subdirectories from the
DTfW installation directory to the include and library search paths in Visual&nbsp;C++. (See the section above
on <a href="#use">using Visual Leak Detector</a> on instructions for adding to these search paths).
</li>
<li>VLD also requires a reasonably up-to-date Platform&nbsp;SDK. It is known to work with the latest SDK (as of this
writing) which is the Windows Server 2003 R2 SDK. It should also work with earlier SDKs, such as the Windows XP
SP2 SDK or may even work with SDKs as old as the February 2003 SDK. If in doubt,
<a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=A55B6B43-E24F-4EA3-A93E-40C0EC4F68E5&amp;displaylang=en">update
your Platform&nbsp;SDK</a> to the latest version.</li>
<li>Again, Visual&nbsp;C++ will need to know where to find the Platform&nbsp;SDK headers and libraries. Add the
<span class="filename">Include</span> and <span class="filename">Lib</span> subdirectories from the
Platform&nbsp;SDK installation directory to the Include and Library search paths, respectively. The
Platform&nbsp;SDK directories should be placed just after the DTfW directories.</li>
</ol>
<p>To summarize, your Visual&nbsp;C++ include search path should look something like this:</p>
<ul class="vcsearchpath">
<li>C:\Program&nbsp;Files\Debugging&nbsp;Tools&nbsp;for&nbsp;Windows\sdk\inc</li>
<li>C:\Program&nbsp;Files\Microsoft&nbsp;Platform&nbsp;SDK\Include</li>
<li>C:\Program&nbsp;Files\Microsoft&nbsp;Visual&nbsp;Studio\VCx\Include</li>
<li>...</li>
</ul>
<p>And your Visual&nbsp;C++ library search path should look like this:</p>
<ul class="vcsearchpath">
<li>C:\Program&nbsp;Files\Debugging&nbsp;Tools&nbsp;for&nbsp;Windows\sdk\lib</li>
<li>C:\Program&nbsp;Files\Microsoft&nbsp;Platform&nbsp;SDK\Lib</li>
<li>C:\Program&nbsp;Files\Microsoft&nbsp;Visual&nbsp;Studio\VCx\Lib</li>
<li>...</li>
</ul>
<p>In the above examples, "VCx" could be "VC", "VC7", or "VC98" (or possibly other values) depending on which version of
Visual Studio you have installed. Also, the name of your Platform&nbsp;SDK directory will probably be different from
the example depending on which version of the Platform&nbsp;SDK you have installed.</p>
<p>Once you have completed all of the above steps, your build environment should be ready. To build VLD, just open the
<span class="filename">vld.sln</span> solution file and do a full build.</p>
<p>When actually running the built project, <span class="filename">vld.dll</span> will expect to find the Debug Help
Library as a private assembly. The private assembly must be located in the same directory as
<span class="filename">vld.dll</span> (either the <span class="filename">Release</span> or
<span class="filename">Debug</span> directory by default). Otherwise, when VLD is loaded, an error message will pop
up indicating that the program failed to initialize, and you will see a message similar to the following in the
debugger's output window:</p>
<blockquote><p>LDR: LdrpWalkImportDescriptor() failed to probe C:\Projects\vld\Release\vld.dll for its manifest,
ntstatus 0xc0150002</p></blockquote>
<p>To ensure that <span class="filename">vld.dll</span> finds the required private assembly, you need to copy
<span class="filename">dbghelp.dll</span> and <span class="filename">Microsoft.DTfW.DHL.manifest</span> to the
same directory that <span class="filename">vld.dll</span> is in.</p>
<h2 id="x64">Windows x64 Support</h2>
<p>The VLD source code has been modified to add support for x64-based 64-bit Windows. However, the binary contained in
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
version of VLD from source. To build the 64-bit version, follow the instructions for <a href="#build">building VLD
from source</a>. So long as it is built using a x64-compatible compiler in 64-bit mode, the resulting DLL will be a
64-bit binary.</p>
<p class="note"><strong>Note:</strong> I have not personally tested the 64-bit extensions so they are not absolutely
guaranteed to work out-of-the-box. There may be a few lingering 64-bit compiler errors that still need to be worked
out. If you need 64-bit support and run into problems trying to build the source in 64-bit mode, please
<a href="mailto:dmoulding@gmail.com">let me know</a>. I'll be glad to assist in getting the 64-bit code working
properly.</p>
<h2 id="faq">Frequently Asked Questions</h2>
<dl>
<dt>When I try to compile my program with VLD, it fails and the compiler gives this error: <strong>Cannot open include file:
'vld.h': No such file or directory</strong>.</dt>
<dd>
<p>The compiler can't find the header file that VLD installed. This probably means that VLD's include
subdirectory has not been added to the Visual C++ include search path. See the section above about
<a href="#use">Using Visual Leak Detector</a> for instructions on how to add VLD's directories to the search
path.</p>
</dd>
<dt>In the memory leak report, the callstack contains many lines that say
<strong>"File and line number unvailable"</strong> or <strong>"Function name unavailable"</strong>.</dt>
<dd>
<p>This may mean that VLD couldn't find the symbol database for your program. The symbol database is ususally in
a file named <span class="filename">[my-program-name].pdb</span>. If this file is not located in the same
directory as the program itself, then VLD will probably not find it and can't show any file or function
names.</p>
</dd>
</dl>
<h2 id="restrictions">Known Restrictions</h2>
<p>Known restrictions/limitations in this version of VLD include:</p>
<ul>
<li>Memory allocations made through calls to functions loaded from a DLL using delayed loading may not be
detected.</li>
<li>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. A possible workaround for this restriction is to try forcefully including the MFC
DLLs in memory leak detection, by setting the <span class="option">ForceIncludeModules</span> configuration
option to: "mfc70d.dll mfc71d.dll" and explicitly adding <span class="filename">vld.lib</span> 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 or MFC 8.0 which are both fully
supported.</li>
<li>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.</li>
<li>On Windows 2000 and earlier operating systems, you may need to manually add the
<span class="filename">bin\Microsoft.VC80.CRT</span> subdirectory from the Visual Leak Detector installation
directory to the system PATH environment variable. Also, <span class="filename">dbghelp.dll</span> will probably
need to be manually copied to the directory where the program being debugged resides. Otherwise the system may
not find the required DLLs when running VLD.</li>
<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
go undetected (note that loading more than one copy of the C Runtime DLL at the same time is probably a bad idea
to begin with).</li>
</ul>
<h2 id="license">License</h2>
<p>Visual&nbsp;Leak&nbsp;Detector is distributed under the terms of the
<a href="http://www.gnu.org/copyleft/lesser.html">GNU Lesser General Public License</a>. This license allows you to
use the VLD library with your own programs without restriction. However, if you build a program (or another library)
that is <em>based</em> on the VLD source code, or uses parts of the VLD source code in it, then some restrictions
will apply. What this means is that you are free to ship and use the distributed version of the VLD DLL with regular
commercial programs. But if you create a modified version of VLD, that modified version must remain "free software".
See the <span class="filename"><a href="COPYING.txt">COPYING.txt</a></span> file for details.</p>
<p>The Debug Help Library (<span class="filename">dbghelp.dll</span>) and Microsoft C Runtime Library
(<span class="filename">msvcr80.dll</span>) distributed with this software are not part of
Visual&nbsp;Leak&nbsp;Detector and are not covered under the terms of the GNU Lesser General Public License. They are
separately copyrighted works of Microsoft Corporation. Microsoft reserves all its rights to its copyrights in the
Debug Help Library and Microsoft C Runtime Library. Neither your use of the Visual&nbsp;Leak&nbsp;Detector software,
nor your license under the GNU Lesser General Public license grant you any rights to use the Debug Help Library or
Microsoft C Runtime Library in <strong>ANY WAY</strong> (for example, redistributing them) that would infringe upon
Microsoft Corporation's copyright in the Debug Help Library or Microsoft C Runtime Library.</p>
<h3>NO WARRANTY</h3>
<p>BECAUSE VISUAL LEAK DETECTOR ("THE SOFTWARE") IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE SOFTWARE, TO
THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER
PARTIES PROVIDE THE SOFTWARE "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 SOFTWARE IS WITH YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
NECESSARY SERVICING, REPAIR OR CORRECTION.</p>
<p>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 SOFTWARE AS PERMITTED BY THE LICENSING TERMS SET FORTH 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 SOFTWARE (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 SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR
OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</p>
<h2 id="contact">Contacting the Author</h2>
<p>Please forward any bug reports, questions, comments or suggestions to me at
<a href="mailto:dmoulding@gmail.com">dmoulding@gmail.com.</a></p>
<p>Donations to help support ongoing development of Visual Leak Detector are very appreciated!</p>
<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
<div>
<input type="hidden" name="cmd" value="_s-xclick" />
<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!" />
<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
BWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb20CAQAwCQYFKw4DAhoFAKBdMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTA1MDgwMTE5NDQ0NlowIwYJKoZIhvcNAQkEMRYEFKLDwHJFsU6L329159saLBrfszYcMA0GCSqGSIb3DQEBAQUABIGAe4Mjshnc1RvJU9zF6nL8zPJ+nHO2ct1CbS1WFkQMWvh2NTwlIVSZFWSLJQZ32kNoyseoxUvE587qdBKyMOATXjchDeMr1y815+GWE6Ffqw3rWw/ytfVEtEJd4yUUq0gHqFACul4nWM5zP5A3zkLZEVN3gAmX1eLbMIcSCKuVafM=-----END PKCS7-----" />
</div>
</form>
<p id="compliance">
<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>
<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>
</p>
<p id="copyright">Copyright &copy; 2005-2006 Dan Moulding</p>
</div> <!-- #content -->
</body>
</html>

View File

@ -0,0 +1,98 @@
////////////////////////////////////////////////////////////////////////////////
// $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

View File

@ -0,0 +1,441 @@
////////////////////////////////////////////////////////////////////////////////
// $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);
}

View File

@ -0,0 +1,117 @@
////////////////////////////////////////////////////////////////////////////////
// $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);
};

View File

@ -0,0 +1,358 @@
////////////////////////////////////////////////////////////////////////////////
// $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.
};

View File

@ -0,0 +1,33 @@
////////////////////////////////////////////////////////////////////////////////
// $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;

View File

@ -0,0 +1,58 @@
////////////////////////////////////////////////////////////////////////////////
// $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;

View File

@ -0,0 +1,338 @@
////////////////////////////////////////////////////////////////////////////////
// $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.
};

View File

@ -0,0 +1,786 @@
////////////////////////////////////////////////////////////////////////////////
// $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.
};

View File

@ -0,0 +1,781 @@
////////////////////////////////////////////////////////////////////////////////
// $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, &section);
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, &section);
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, &section);
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, &section);
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;
}
}

View File

@ -0,0 +1,109 @@
////////////////////////////////////////////////////////////////////////////////
// $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);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,69 @@
////////////////////////////////////////////////////////////////////////////////
// $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;
}

View File

@ -0,0 +1,213 @@
////////////////////////////////////////////////////////////////////////////////
// $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);
}

View File

@ -0,0 +1,95 @@
////////////////////////////////////////////////////////////////////////////////
// $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__)

View File

@ -0,0 +1,263 @@
////////////////////////////////////////////////////////////////////////////////
// $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"

View File

@ -0,0 +1,156 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; $Id: vld.ini,v 1.7 2006/11/18 03:12:35 dmouldin Exp $
;;
;; Visual Leak Detector - Initialization/Configuration File
;; 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.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Any options left blank or not present will revert to their default values.
[Options]
; The main on/off switch. If off, Visual Leak Detector will be completely
; disabled. It will do nothing but print a message to the debugger indicating
; that it has been turned off.
;
; Valid Values: on, off
; Default: on
;
VLD = on
; If yes, duplicate leaks (those that are identical) are not shown individually.
; Only the first such leak is shown, along with a number indicating the total
; number of duplicate leaks.
;
; Valid Values: yes, no
; Default: no
;
AggregateDuplicates = no
; Lists any additional modules to be included in memory leak detection. This can
; be useful for checking for memory leaks in debug builds of 3rd party modules
; which can not be easily rebuilt with '#include "vld.h"'. This option should be
; used only if absolutely necessary and only if you really know what you are
; doing.
;
; CAUTION: Avoid listing any modules that link with the release CRT libraries.
; Only modules that link with the debug CRT libraries should be listed here.
; Doing otherwise might result in false memory leak reports or even crashes.
;
; Valid Values: Any list containing module names (i.e. names of EXEs or DLLs).
; Default: None.
;
ForceIncludeModules =
; Maximum number of data bytes to display for each leaked block. If zero, then
; the data dump is completely suppressed and only call stacks are shown.
; Limiting this to a low number can be useful if any of the leaked blocks are
; very large and cause unnecessary clutter in the memory leak report.
;
; Value Values: 0 - 4294967295
; Default: 4294967295
;
MaxDataDump =
; Maximum number of call stack frames to trace back during leak detection.
; Limiting this to a low number can reduce the CPU utilization overhead imposed
; by memory leak detection, especially when using the slower "safe" stack
; walking method (see StackWalkMethod below).
;
; Valid Values: 1 - 4294967295
; Default: 4294967295
;
MaxTraceFrames =
; Sets the type of encoding to use for the generated memory leak report. This
; option is really only useful in conjuction with sending the report to a file.
; Sending a Unicode encoded report to the debugger is not useful because the
; debugger cannot display Unicode characters. Using Unicode encoding might be
; useful if the data contained in leaked blocks is likely to consist of Unicode
; text.
;
; Valid Values: ascii, unicode
; Default: ascii
;
ReportEncoding = ascii
; Sets the report file destination, if reporting to file is enabled. A relative
; path may be specified and is considered relative to the process' working
; directory.
;
; Valid Values: Any valid path and filename.
; Default: .\memory_leak_report.txt
;
ReportFile =
; Sets the report destination to either a file, the debugger, or both. If
; reporting to file is enabled, the report is sent to the file specified by the
; ReportFile option.
;
; Valid Values: debugger, file, both
; Default: debugger
;
ReportTo = debugger
; Turns on or off a self-test mode which is used to verify that VLD is able to
; detect memory leaks in itself. Intended to be used for debugging VLD itself,
; not for debugging other programs.
;
; Valid Values: on, off
; Default: off
;
SelfTest = off
; Selects the method to be used for walking the stack to obtain stack traces for
; allocated memory blocks. The "fast" method may not always be able to
; successfully trace completely through all call stacks. In such cases, the
; "safe" method may prove to more reliably obtain the full stack trace. The
; disadvantage is that the "safe" method is significantly slower than the "fast"
; method and will probably result in very noticeable performance degradation of
; the program being debugged.
;
; Valid Values: fast, safe
; Default: fast
;
StackWalkMethod = fast
; Determines whether memory leak detection should be initially enabled for all
; threads, or whether it should be initially disabled for all threads. If set
; to "yes", then any threads requiring memory leak detection to be enabled will
; need to call VLDEnable at some point to enable leak detection for those
; threads.
;
; Valid Values: yes, no
; Default: no
;
StartDisabled = no
; Determines whether or not all frames, including frames internal to the heap,
; are traced. There will always be a number of frames internal to Visual Leak
; Detector and C/C++ or Win32 heap APIs that aren't generally useful for
; determining the cause of a leak. Normally these frames are skipped during the
; stack trace, which somewhat reduces the time spent tracing and amount of data
; collected and stored in memory. Including all frames in the stack trace, all
; the way down into VLD's own code can, however, be useful for debugging VLD
; itself.
;
; Valid Values: yes, no
; Default: no
;
TraceInternalFrames = no