mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-12-22 05:16:21 +00:00
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:
parent
a66d9c825b
commit
c0708a5c5e
344
development/Win32/vld/CHANGES.txt
Normal file
344
development/Win32/vld/CHANGES.txt
Normal 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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
458
development/Win32/vld/COPYING.txt
Normal file
458
development/Win32/vld/COPYING.txt
Normal 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
|
747
development/Win32/vld/README.html
Normal file
747
development/Win32/vld/README.html
Normal 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 Leak Detector 1.9f (Beta)</h1>
|
||||
|
||||
<p id="slogan">Enhanced Memory Leak Detection for Visual 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 Leak 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 Leak 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 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 C++. Here
|
||||
are some of Visual Leak 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 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 Leak 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 Leak Detector</h2>
|
||||
|
||||
<p>This section briefly describes the basics of using Visual Leak 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 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 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 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 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 Leak Detector from Source</h2>
|
||||
|
||||
<p>Because Visual Leak 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 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 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 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&displaylang=en">update
|
||||
your Platform SDK</a> to the latest version.</li>
|
||||
|
||||
<li>Again, Visual C++ will need to know where to find the Platform SDK headers and libraries. Add the
|
||||
<span class="filename">Include</span> and <span class="filename">Lib</span> subdirectories from the
|
||||
Platform SDK installation directory to the Include and Library search paths, respectively. The
|
||||
Platform SDK directories should be placed just after the DTfW directories.</li>
|
||||
</ol>
|
||||
|
||||
<p>To summarize, your Visual C++ include search path should look something like this:</p>
|
||||
|
||||
<ul class="vcsearchpath">
|
||||
<li>C:\Program Files\Debugging Tools for Windows\sdk\inc</li>
|
||||
|
||||
<li>C:\Program Files\Microsoft Platform SDK\Include</li>
|
||||
|
||||
<li>C:\Program Files\Microsoft Visual Studio\VCx\Include</li>
|
||||
|
||||
<li>...</li>
|
||||
</ul>
|
||||
|
||||
<p>And your Visual C++ library search path should look like this:</p>
|
||||
|
||||
<ul class="vcsearchpath">
|
||||
<li>C:\Program Files\Debugging Tools for Windows\sdk\lib</li>
|
||||
|
||||
<li>C:\Program Files\Microsoft Platform SDK\Lib</li>
|
||||
|
||||
<li>C:\Program Files\Microsoft Visual 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 SDK directory will probably be different from
|
||||
the example depending on which version of the Platform 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 Leak 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 Leak 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 Leak 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 © 2005-2006 Dan Moulding</p>
|
||||
|
||||
</div> <!-- #content -->
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
98
development/Win32/vld/include/vld.h
Normal file
98
development/Win32/vld/include/vld.h
Normal 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
|
441
development/Win32/vld/src/callstack.cpp
Normal file
441
development/Win32/vld/src/callstack.cpp
Normal 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);
|
||||
}
|
117
development/Win32/vld/src/callstack.h
Normal file
117
development/Win32/vld/src/callstack.h
Normal 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);
|
||||
};
|
358
development/Win32/vld/src/map.h
Normal file
358
development/Win32/vld/src/map.h
Normal 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.
|
||||
};
|
33
development/Win32/vld/src/ntapi.cpp
Normal file
33
development/Win32/vld/src/ntapi.cpp
Normal 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;
|
58
development/Win32/vld/src/ntapi.h
Normal file
58
development/Win32/vld/src/ntapi.h
Normal 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;
|
338
development/Win32/vld/src/set.h
Normal file
338
development/Win32/vld/src/set.h
Normal 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.
|
||||
};
|
786
development/Win32/vld/src/tree.h
Normal file
786
development/Win32/vld/src/tree.h
Normal 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.
|
||||
};
|
781
development/Win32/vld/src/utility.cpp
Normal file
781
development/Win32/vld/src/utility.cpp
Normal 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, §ion);
|
||||
LeaveCriticalSection(&imagelock);
|
||||
if (idte == NULL) {
|
||||
// This module has no IDT (i.e. it imports nothing).
|
||||
return FALSE;
|
||||
}
|
||||
while (idte->OriginalFirstThunk != 0x0) {
|
||||
if (_stricmp((PCHAR)R2VA(importmodule, idte->Name), exportmodulename) == 0) {
|
||||
// Found the IDT entry for the exporting module.
|
||||
break;
|
||||
}
|
||||
idte++;
|
||||
}
|
||||
if (idte->OriginalFirstThunk == 0x0) {
|
||||
// The importing module does not import anything from the exporting
|
||||
// module.
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Get the *real* address of the import. If we find this address in the IAT,
|
||||
// then we've found that the module does import the named import.
|
||||
import = GetProcAddress(exportmodule, importname);
|
||||
assert(import != NULL); // Perhaps the named export module does not actually export the named import?
|
||||
|
||||
// Locate the import's IAT entry.
|
||||
iate = (IMAGE_THUNK_DATA*)R2VA(importmodule, idte->FirstThunk);
|
||||
while (iate->u1.Function != 0x0) {
|
||||
if (iate->u1.Function == (DWORD_PTR)import) {
|
||||
// Found the IAT entry. The module imports the named import.
|
||||
return TRUE;
|
||||
}
|
||||
iate++;
|
||||
}
|
||||
|
||||
// The module does not import the named import.
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// findpatch - Determines if the specified module has been patched to use the
|
||||
// specified replacement.
|
||||
//
|
||||
// - importmodule (IN): Handle (base address) of the module to be searched to
|
||||
// see if it imports the specified replacement export.
|
||||
//
|
||||
// - exportmodulename (IN): ANSI string containing the name of the module that
|
||||
// normally exports that import that would have been patched to use the
|
||||
// replacement export.
|
||||
//
|
||||
// - replacement (IN): Address of the replacement, or destination, function or
|
||||
// variable to search for.
|
||||
//
|
||||
// Return Value:
|
||||
//
|
||||
// Returns TRUE if the module has been patched to use the specified
|
||||
// replacement export.
|
||||
//
|
||||
BOOL findpatch (HMODULE importmodule, LPCSTR exportmodulename, LPCVOID replacement)
|
||||
{
|
||||
IMAGE_THUNK_DATA *iate;
|
||||
IMAGE_IMPORT_DESCRIPTOR *idte;
|
||||
IMAGE_SECTION_HEADER *section;
|
||||
ULONG size;
|
||||
|
||||
// Locate the importing module's Import Directory Table (IDT) entry for the
|
||||
// exporting module. The importing module actually can have several IATs --
|
||||
// one for each export module that it imports something from. The IDT entry
|
||||
// gives us the offset of the IAT for the module we are interested in.
|
||||
EnterCriticalSection(&imagelock);
|
||||
idte = (IMAGE_IMPORT_DESCRIPTOR*)ImageDirectoryEntryToDataEx((PVOID)importmodule, TRUE,
|
||||
IMAGE_DIRECTORY_ENTRY_IMPORT, &size, §ion);
|
||||
LeaveCriticalSection(&imagelock);
|
||||
if (idte == NULL) {
|
||||
// This module has no IDT (i.e. it imports nothing).
|
||||
return FALSE;
|
||||
}
|
||||
while (idte->OriginalFirstThunk != 0x0) {
|
||||
if (_stricmp((PCHAR)R2VA(importmodule, idte->Name), exportmodulename) == 0) {
|
||||
// Found the IDT entry for the exporting module.
|
||||
break;
|
||||
}
|
||||
idte++;
|
||||
}
|
||||
if (idte->OriginalFirstThunk == 0x0) {
|
||||
// The importing module does not import anything from the exporting
|
||||
// module.
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Locate the replacement's IAT entry.
|
||||
iate = (IMAGE_THUNK_DATA*)R2VA(importmodule, idte->FirstThunk);
|
||||
while (iate->u1.Function != 0x0) {
|
||||
if (iate->u1.Function == (DWORD_PTR)replacement) {
|
||||
// Found the IAT entry for the replacement. This patch has been
|
||||
// installed.
|
||||
return TRUE;
|
||||
}
|
||||
iate++;
|
||||
}
|
||||
|
||||
// The module does not import the replacement. The patch has not been
|
||||
// installed.
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// insertreportdelay - Sets the report function to sleep for a bit after each
|
||||
// call to OutputDebugString, in order to allow the debugger to catch up.
|
||||
//
|
||||
// Return Value:
|
||||
//
|
||||
// None.
|
||||
//
|
||||
VOID insertreportdelay ()
|
||||
{
|
||||
reportdelay = TRUE;
|
||||
}
|
||||
|
||||
// moduleispatched - Checks to see if any of the imports listed in the specified
|
||||
// patch table have been patched into the specified importmodule.
|
||||
//
|
||||
// - importmodule (IN): Handle (base address) of the module to be queried to
|
||||
// determine if it has been patched.
|
||||
//
|
||||
// - patchtable (IN): An array of patchentry_t structures specifying all of the
|
||||
// import patches to search for.
|
||||
//
|
||||
// - tablesize (IN): Size, in entries, of the specified patch table.
|
||||
//
|
||||
// Return Value:
|
||||
//
|
||||
// Returns TRUE if at least one of the patches listed in the patch table is
|
||||
// installed in the importmodule. Otherwise returns FALSE.
|
||||
//
|
||||
BOOL moduleispatched (HMODULE importmodule, patchentry_t patchtable [], UINT tablesize)
|
||||
{
|
||||
patchentry_t *entry;
|
||||
BOOL found = FALSE;
|
||||
UINT index;
|
||||
|
||||
// Loop through the import patch table, individually checking each patch
|
||||
// entry to see if it is installed in the import module. If any patch entry
|
||||
// is installed in the import module, then the module has been patched.
|
||||
for (index = 0; index < tablesize; index++) {
|
||||
entry = &patchtable[index];
|
||||
found = findpatch(importmodule, entry->exportmodulename, entry->replacement);
|
||||
if (found == TRUE) {
|
||||
// Found one of the listed patches installed in the import module.
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
// No patches listed in the patch table were found in the import module.
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// patchimport - Patches all future calls to an imported function, or references
|
||||
// to an imported variable, through to a replacement function or variable.
|
||||
// Patching is done by replacing the import's address in the specified target
|
||||
// module's Import Address Table (IAT) with the address of the replacement
|
||||
// function or variable.
|
||||
//
|
||||
// - importmodule (IN): Handle (base address) of the target module for which
|
||||
// calls or references to the import should be patched.
|
||||
//
|
||||
// - exportmodule (IN): Handle (base address) of the module that exports the
|
||||
// the function or variable to be patched.
|
||||
//
|
||||
// - exportmodulename (IN): ANSI string containing the name of the module that
|
||||
// exports the function or variable to be patched.
|
||||
//
|
||||
// - importname (IN): ANSI string containing the name of the imported function
|
||||
// or variable to be patched. May be an integer cast to a string if the
|
||||
// import is exported by ordinal.
|
||||
//
|
||||
// - replacement (IN): Address of the function or variable to which future
|
||||
// calls or references should be patched through to. This function or
|
||||
// variable can be thought of as effectively replacing the original import
|
||||
// from the point of view of the module specified by "importmodule".
|
||||
//
|
||||
// Return Value:
|
||||
//
|
||||
// Returns TRUE if the patch was installed into the import module. If the
|
||||
// import module does not import the specified export, so nothing changed,
|
||||
// then FALSE will be returned.
|
||||
//
|
||||
BOOL patchimport (HMODULE importmodule, HMODULE exportmodule, LPCSTR exportmodulename, LPCSTR importname,
|
||||
LPCVOID replacement)
|
||||
{
|
||||
IMAGE_THUNK_DATA *iate;
|
||||
IMAGE_IMPORT_DESCRIPTOR *idte;
|
||||
FARPROC import;
|
||||
DWORD protect;
|
||||
IMAGE_SECTION_HEADER *section;
|
||||
ULONG size;
|
||||
|
||||
// Locate the importing module's Import Directory Table (IDT) entry for the
|
||||
// exporting module. The importing module actually can have several IATs --
|
||||
// one for each export module that it imports something from. The IDT entry
|
||||
// gives us the offset of the IAT for the module we are interested in.
|
||||
EnterCriticalSection(&imagelock);
|
||||
idte = (IMAGE_IMPORT_DESCRIPTOR*)ImageDirectoryEntryToDataEx((PVOID)importmodule, TRUE,
|
||||
IMAGE_DIRECTORY_ENTRY_IMPORT, &size, §ion);
|
||||
LeaveCriticalSection(&imagelock);
|
||||
if (idte == NULL) {
|
||||
// This module has no IDT (i.e. it imports nothing).
|
||||
return FALSE;
|
||||
}
|
||||
while (idte->OriginalFirstThunk != 0x0) {
|
||||
if (_stricmp((PCHAR)R2VA(importmodule, idte->Name), exportmodulename) == 0) {
|
||||
// Found the IDT entry for the exporting module.
|
||||
break;
|
||||
}
|
||||
idte++;
|
||||
}
|
||||
if (idte->OriginalFirstThunk == 0x0) {
|
||||
// The importing module does not import anything from the exporting
|
||||
// module.
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Get the *real* address of the import. If we find this address in the IAT,
|
||||
// then we've found the entry that needs to be patched.
|
||||
import = GetProcAddress(exportmodule, importname);
|
||||
assert(import != NULL); // Perhaps the named export module does not actually export the named import?
|
||||
|
||||
// Locate the import's IAT entry.
|
||||
iate = (IMAGE_THUNK_DATA*)R2VA(importmodule, idte->FirstThunk);
|
||||
while (iate->u1.Function != 0x0) {
|
||||
if (iate->u1.Function == (DWORD_PTR)import) {
|
||||
// Found the IAT entry. Overwrite the address stored in the IAT
|
||||
// entry with the address of the replacement. Note that the IAT
|
||||
// entry may be write-protected, so we must first ensure that it is
|
||||
// writable.
|
||||
VirtualProtect(&iate->u1.Function, sizeof(iate->u1.Function), PAGE_READWRITE, &protect);
|
||||
iate->u1.Function = (DWORD_PTR)replacement;
|
||||
VirtualProtect(&iate->u1.Function, sizeof(iate->u1.Function), protect, &protect);
|
||||
|
||||
// The patch has been installed in the import module.
|
||||
return TRUE;
|
||||
}
|
||||
iate++;
|
||||
}
|
||||
|
||||
// The import's IAT entry was not found. The importing module does not
|
||||
// import the specified import.
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// patchmodule - Patches all imports listed in the supplied patch table, and
|
||||
// which are imported by the specified module, through to their respective
|
||||
// replacement functions.
|
||||
//
|
||||
// Note: If the specified module does not import any of the functions listed
|
||||
// in the patch table, then nothing is changed for the specified module.
|
||||
//
|
||||
// - importmodule (IN): Handle (base address) of the target module which is to
|
||||
// have its imports patched.
|
||||
//
|
||||
// - patchtable (IN): An array of patchentry_t structures specifying all of the
|
||||
// imports to patch for the specified module.
|
||||
//
|
||||
// - tablesize (IN): Size, in entries, of the specified patch table.
|
||||
//
|
||||
// Return Value:
|
||||
//
|
||||
// Returns TRUE if at least one of the patches listed in the patch table was
|
||||
// installed in the importmodule. Otherwise returns FALSE.
|
||||
//
|
||||
BOOL patchmodule (HMODULE importmodule, patchentry_t patchtable [], UINT tablesize)
|
||||
{
|
||||
patchentry_t *entry;
|
||||
UINT index;
|
||||
BOOL patched = FALSE;
|
||||
|
||||
// Loop through the import patch table, individually patching each import
|
||||
// listed in the table.
|
||||
for (index = 0; index < tablesize; index++) {
|
||||
entry = &patchtable[index];
|
||||
if (patchimport(importmodule, (HMODULE)entry->modulebase, entry->exportmodulename, entry->importname,
|
||||
entry->replacement) == TRUE) {
|
||||
patched = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return patched;
|
||||
}
|
||||
|
||||
// report - Sends a printf-style formatted message to the debugger for display
|
||||
// and/or to a file.
|
||||
//
|
||||
// Note: A message longer than MAXREPORTLENGTH characters will be truncated
|
||||
// to MAXREPORTLENGTH.
|
||||
//
|
||||
// - format (IN): Specifies a printf-compliant format string containing the
|
||||
// message to be sent to the debugger.
|
||||
//
|
||||
// - ... (IN): Arguments to be formatted using the specified format string.
|
||||
//
|
||||
// Return Value:
|
||||
//
|
||||
// None.
|
||||
//
|
||||
VOID report (LPCWSTR format, ...)
|
||||
{
|
||||
va_list args;
|
||||
size_t count;
|
||||
CHAR messagea [MAXREPORTLENGTH + 1];
|
||||
WCHAR messagew [MAXREPORTLENGTH + 1];
|
||||
|
||||
va_start(args, format);
|
||||
_vsnwprintf_s(messagew, MAXREPORTLENGTH + 1, _TRUNCATE, format, args);
|
||||
va_end(args);
|
||||
messagew[MAXREPORTLENGTH] = L'\0';
|
||||
|
||||
if (reportencoding == unicode) {
|
||||
if (reportfile != NULL) {
|
||||
// Send the report to the previously specified file.
|
||||
fwrite(messagew, sizeof(WCHAR), wcslen(messagew), reportfile);
|
||||
}
|
||||
if (reporttodebugger) {
|
||||
OutputDebugStringW(messagew);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (wcstombs_s(&count, messagea, MAXREPORTLENGTH + 1, messagew, _TRUNCATE) == -1) {
|
||||
// Failed to convert the Unicode message to ASCII.
|
||||
assert(FALSE);
|
||||
return;
|
||||
}
|
||||
messagea[MAXREPORTLENGTH] = '\0';
|
||||
if (reportfile != NULL) {
|
||||
// Send the report to the previously specified file.
|
||||
fwrite(messagea, sizeof(CHAR), strlen(messagea), reportfile);
|
||||
}
|
||||
if (reporttodebugger) {
|
||||
OutputDebugStringA(messagea);
|
||||
}
|
||||
}
|
||||
|
||||
if (reporttodebugger && (reportdelay == TRUE)) {
|
||||
Sleep(10); // Workaround the Visual Studio 6 bug where debug strings are sometimes lost if they're sent too fast.
|
||||
}
|
||||
}
|
||||
|
||||
// restoreimport - Restores the IAT entry for an import previously patched via
|
||||
// a call to "patchimport" to the original address of the import.
|
||||
//
|
||||
// - importmodule (IN): Handle (base address) of the target module for which
|
||||
// calls or references to the import should be restored.
|
||||
//
|
||||
// - exportmodule (IN): Handle (base address) of the module that exports the
|
||||
// function or variable to be patched.
|
||||
//
|
||||
// - exportmodulename (IN): ANSI string containing the name of the module that
|
||||
// exports the function or variable to be patched.
|
||||
//
|
||||
// - importname (IN): ANSI string containing the name of the imported function
|
||||
// or variable to be restored. May be an integer cast to a string if the
|
||||
// import is exported by ordinal.
|
||||
//
|
||||
// - replacement (IN): Address of the function or variable which the import was
|
||||
// previously patched through to via a call to "patchimport".
|
||||
//
|
||||
// Return Value:
|
||||
//
|
||||
// None.
|
||||
//
|
||||
VOID restoreimport (HMODULE importmodule, HMODULE exportmodule, LPCSTR exportmodulename, LPCSTR importname,
|
||||
LPCVOID replacement)
|
||||
{
|
||||
IMAGE_THUNK_DATA *iate;
|
||||
IMAGE_IMPORT_DESCRIPTOR *idte;
|
||||
FARPROC import;
|
||||
DWORD protect;
|
||||
IMAGE_SECTION_HEADER *section;
|
||||
ULONG size;
|
||||
|
||||
// Locate the importing module's Import Directory Table (IDT) entry for the
|
||||
// exporting module. The importing module actually can have several IATs --
|
||||
// one for each export module that it imports something from. The IDT entry
|
||||
// gives us the offset of the IAT for the module we are interested in.
|
||||
EnterCriticalSection(&imagelock);
|
||||
idte = (IMAGE_IMPORT_DESCRIPTOR*)ImageDirectoryEntryToDataEx((PVOID)importmodule, TRUE,
|
||||
IMAGE_DIRECTORY_ENTRY_IMPORT, &size, §ion);
|
||||
LeaveCriticalSection(&imagelock);
|
||||
if (idte == NULL) {
|
||||
// This module has no IDT (i.e. it imports nothing).
|
||||
return;
|
||||
}
|
||||
while (idte->OriginalFirstThunk != 0x0) {
|
||||
if (_stricmp((PCHAR)R2VA(importmodule, idte->Name), exportmodulename) == 0) {
|
||||
// Found the IDT entry for the exporting module.
|
||||
break;
|
||||
}
|
||||
idte++;
|
||||
}
|
||||
if (idte->OriginalFirstThunk == 0x0) {
|
||||
// The importing module does not import anything from the exporting
|
||||
// module.
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the *real* address of the import.
|
||||
import = GetProcAddress(exportmodule, importname);
|
||||
assert(import != NULL); // Perhaps the named export module does not actually export the named import?
|
||||
|
||||
// Locate the import's original IAT entry (it currently has the replacement
|
||||
// address in it).
|
||||
iate = (IMAGE_THUNK_DATA*)R2VA(importmodule, idte->FirstThunk);
|
||||
while (iate->u1.Function != 0x0) {
|
||||
if (iate->u1.Function == (DWORD_PTR)replacement) {
|
||||
// Found the IAT entry. Overwrite the address stored in the IAT
|
||||
// entry with the import's real address. Note that the IAT entry may
|
||||
// be write-protected, so we must first ensure that it is writable.
|
||||
VirtualProtect(&iate->u1.Function, sizeof(iate->u1.Function), PAGE_READWRITE, &protect);
|
||||
iate->u1.Function = (DWORD_PTR)import;
|
||||
VirtualProtect(&iate->u1.Function, sizeof(iate->u1.Function), protect, &protect);
|
||||
break;
|
||||
}
|
||||
iate++;
|
||||
}
|
||||
}
|
||||
|
||||
// restoremodule - Restores all imports listed in the supplied patch table, and
|
||||
// which are imported by the specified module, to their original functions.
|
||||
//
|
||||
// Note: If the specified module does not import any of the functions listed
|
||||
// in the patch table, then nothing is changed for the specified module.
|
||||
//
|
||||
// - importmodule (IN): Handle (base address) of the target module which is to
|
||||
// have its imports restored.
|
||||
//
|
||||
// - patchtable (IN): Array of patchentry_t structures specifying all of the
|
||||
// imports to restore for the specified module.
|
||||
//
|
||||
// - tablesize (IN): Size, in entries, of the specified patch table.
|
||||
//
|
||||
// Return Value:
|
||||
//
|
||||
// None.
|
||||
//
|
||||
VOID restoremodule (HMODULE importmodule, patchentry_t patchtable [], UINT tablesize)
|
||||
{
|
||||
patchentry_t *entry;
|
||||
UINT index;
|
||||
|
||||
// Loop through the import patch table, individually restoring each import
|
||||
// listed in the table.
|
||||
for (index = 0; index < tablesize; index++) {
|
||||
entry = &patchtable[index];
|
||||
restoreimport(importmodule, (HMODULE)entry->modulebase, entry->exportmodulename, entry->importname,
|
||||
entry->replacement);
|
||||
}
|
||||
}
|
||||
|
||||
// setreportencoding - Sets the output encoding of report messages to either
|
||||
// ASCII (the default) or Unicode.
|
||||
//
|
||||
// - encoding (IN): Specifies either "ascii" or "unicode".
|
||||
//
|
||||
// Return Value:
|
||||
//
|
||||
// None.
|
||||
//
|
||||
VOID setreportencoding (encoding_e encoding)
|
||||
{
|
||||
switch (encoding) {
|
||||
case ascii:
|
||||
case unicode:
|
||||
reportencoding = encoding;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
// setreportfile - Sets a destination file to which all report messages should
|
||||
// be sent. If this function is not called to set a destination file, then
|
||||
// report messages will be sent to the debugger instead of to a file.
|
||||
//
|
||||
// - file (IN): Pointer to an open file, to which future report messages should
|
||||
// be sent.
|
||||
//
|
||||
// - copydebugger (IN): If true, in addition to sending report messages to
|
||||
// the specified file, a copy of each message will also be sent to the
|
||||
// debugger.
|
||||
//
|
||||
// Return Value:
|
||||
//
|
||||
// None.
|
||||
//
|
||||
VOID setreportfile (FILE *file, BOOL copydebugger)
|
||||
{
|
||||
reportfile = file;
|
||||
reporttodebugger = copydebugger;
|
||||
}
|
||||
|
||||
// strapp - Appends the specified source string to the specified destination
|
||||
// string. Allocates additional space so that the destination string "grows"
|
||||
// as new strings are appended to it. This function is fairly infrequently
|
||||
// used so efficiency is not a major concern.
|
||||
//
|
||||
// - dest (IN/OUT): Address of the destination string. Receives the resulting
|
||||
// combined string after the append operation.
|
||||
//
|
||||
// - source (IN): Source string to be appended to the destination string.
|
||||
//
|
||||
// Return Value:
|
||||
//
|
||||
// None.
|
||||
//
|
||||
VOID strapp (LPWSTR *dest, LPCWSTR source)
|
||||
{
|
||||
SIZE_T length;
|
||||
LPWSTR temp;
|
||||
|
||||
temp = *dest;
|
||||
length = wcslen(*dest) + wcslen(source);
|
||||
*dest = new WCHAR [length + 1];
|
||||
wcsncpy_s(*dest, length + 1, temp, _TRUNCATE);
|
||||
wcsncat_s(*dest, length + 1, source, _TRUNCATE);
|
||||
delete [] temp;
|
||||
}
|
||||
|
||||
// strtobool - Converts string values (e.g. "yes", "no", "on", "off") to boolean
|
||||
// values.
|
||||
//
|
||||
// - s (IN): String value to convert.
|
||||
//
|
||||
// Return Value:
|
||||
//
|
||||
// Returns TRUE if the string is recognized as a "true" string. Otherwise
|
||||
// returns FALSE.
|
||||
//
|
||||
BOOL strtobool (LPCWSTR s) {
|
||||
WCHAR *end;
|
||||
|
||||
if ((_wcsicmp(s, L"true") == 0) ||
|
||||
(_wcsicmp(s, L"yes") == 0) ||
|
||||
(_wcsicmp(s, L"on") == 0) ||
|
||||
(wcstol(s, &end, 10) == 1)) {
|
||||
return TRUE;
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
109
development/Win32/vld/src/utility.h
Normal file
109
development/Win32/vld/src/utility.h
Normal 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);
|
3338
development/Win32/vld/src/vld.cpp
Normal file
3338
development/Win32/vld/src/vld.cpp
Normal file
File diff suppressed because it is too large
Load Diff
69
development/Win32/vld/src/vldapi.cpp
Normal file
69
development/Win32/vld/src/vldapi.cpp
Normal 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;
|
||||
}
|
213
development/Win32/vld/src/vldheap.cpp
Normal file
213
development/Win32/vld/src/vldheap.cpp
Normal 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);
|
||||
}
|
95
development/Win32/vld/src/vldheap.h
Normal file
95
development/Win32/vld/src/vldheap.h
Normal 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__)
|
263
development/Win32/vld/src/vldint.h
Normal file
263
development/Win32/vld/src/vldint.h
Normal 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"
|
156
development/Win32/vld/vld.ini
Normal file
156
development/Win32/vld/vld.ini
Normal 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
|
Loading…
Reference in New Issue
Block a user