mirror of https://github.com/BOINC/boinc.git
*** empty log message ***
svn path=/trunk/boinc/; revision=5340
This commit is contained in:
parent
00f174a89e
commit
75226074d3
|
@ -1,86 +0,0 @@
|
|||
/*
|
||||
* HeapCheck - a heap debugging library
|
||||
* Copyright (C) 2001 Thanassis Tsiodras (ttsiod@softlab.ntua.gr)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
// We only exist in debug builds...
|
||||
#ifdef _DEBUG
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "HeapCheckPrototypes.h"
|
||||
|
||||
// Checks for underuns...
|
||||
#ifdef PRE_CHECK
|
||||
|
||||
void *operator new(size_t size)
|
||||
{
|
||||
return HeapCheckPreFenceMalloc(size);
|
||||
}
|
||||
|
||||
void *operator new[](size_t size)
|
||||
{
|
||||
return HeapCheckPreFenceMalloc(size);
|
||||
}
|
||||
|
||||
void operator delete(void *p)
|
||||
{
|
||||
if (p)
|
||||
HeapCheckPreFenceFree(p);
|
||||
}
|
||||
|
||||
void operator delete[](void *p)
|
||||
{
|
||||
if (p)
|
||||
HeapCheckPreFenceFree(p);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// Checks for overuns...
|
||||
void *operator new(size_t size)
|
||||
{
|
||||
return HeapCheckPostFenceMalloc(size);
|
||||
}
|
||||
|
||||
void *operator new[](size_t size)
|
||||
{
|
||||
return HeapCheckPostFenceMalloc(size);
|
||||
}
|
||||
|
||||
void operator delete(void *p)
|
||||
{
|
||||
if (p)
|
||||
HeapCheckPostFenceFree(p);
|
||||
}
|
||||
|
||||
void operator delete[](void *p)
|
||||
{
|
||||
if (p)
|
||||
HeapCheckPostFenceFree(p);
|
||||
}
|
||||
|
||||
#endif /* PRE_CHECK */
|
||||
|
||||
#endif /* _DEBUG */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
|
||||
const char *BOINC_RCSID_f7faa1da5e = "$Id$";
|
|
@ -1,340 +0,0 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 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.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, 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 or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
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 give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
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 Program or any portion
|
||||
of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
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 Program, 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 Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) 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; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, 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 executable. However, as a
|
||||
special exception, the source code 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.
|
||||
|
||||
If distribution of executable or 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 counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program 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.
|
||||
|
||||
5. 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 Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program 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 to
|
||||
this License.
|
||||
|
||||
7. 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 Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program 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 Program.
|
||||
|
||||
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.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program 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.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the 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 Program
|
||||
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 Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, 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
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. 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 PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
|
@ -1,956 +0,0 @@
|
|||
/***************************************************************************
|
||||
* HeapCheck - a heap debugging library
|
||||
* Copyright (C) 2001 Thanassis Tsiodras (ttsiod@softlab.ntua.gr)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
**************************************************************************
|
||||
*
|
||||
* HeapCheck 1.2
|
||||
* =============
|
||||
*
|
||||
* A simple debugging allocator, designed to help heap bug-hunting.
|
||||
* Like most debugging heap allocators, it helps you find memory leaks.
|
||||
* It also helps you where others can't: in catching invalid accesses.
|
||||
* It uses the paging system to create inaccessible pages by the side
|
||||
* of your normal allocations. This way, accesses outside the heap-
|
||||
* allocated space cause an exception (even READ accesses). This is much
|
||||
* better than heap debugging done with:
|
||||
*
|
||||
* 1. Visual C++ 6.0 Runtime Heap Debugging:
|
||||
* This only checks for heap corruption (i.e. only WRITINGS outside
|
||||
* the allocations) and even then, it only catches writings in the
|
||||
* NO_MANS_LAND_SIZE (default:4 bytes) on either side of the blocks.
|
||||
* The detection of these errors is done whenever the user (or the system)
|
||||
* calls _CrtCheckMemory(). HeapCheck catches READ accesses as well,
|
||||
* at the EXACT place they are made, and in a much larger
|
||||
* block (a page in i386 systems is 4096 bytes).
|
||||
*
|
||||
* 2. BoundsChecker:
|
||||
* This is a very good debugging tool, capable of catching almost
|
||||
* every bug. However, in order to perform all these checks, a lot
|
||||
* of CPU cycles are used, especially in instrumentation mode and
|
||||
* maximum memory checking (some programs won't work correctly when
|
||||
* they run so slowly, e.g. protocol stacks). HeapCheck catches only
|
||||
* heap-related errors, but it uses the paging hardware to do the
|
||||
* checking. The net result is that the HeapCheck debug versions of
|
||||
* programs run at almost the same speed as normal debug versions.
|
||||
*
|
||||
* I hope (but can't guarantee) that it will help you in your heap
|
||||
* bug hunting. It has definitely helped me with my projects.
|
||||
* Many thanks for the original idea go to the creator of UNIX's
|
||||
* Electric Fence, Bruce Perens. Oh, and make sure you use the
|
||||
* correct (Win2000) versions of the debugging libraries. I used:
|
||||
*
|
||||
* dbghelp.dll : 5.0.2195.1
|
||||
* imagehlp.dll : 5.0.2195.1
|
||||
*
|
||||
* Maybe SymGetLineFromAddr works with other combinations, but I used
|
||||
* these successfully under both NT 4.0sp6 and Win2000.
|
||||
*
|
||||
* Happy coding!
|
||||
* Thanassis Tsiodras
|
||||
* ttsiod@softlab.ntua.gr
|
||||
*
|
||||
**************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
* Remember, all of this code gets called only in _DEBUG builds!
|
||||
* Check swaps.h to see why...
|
||||
*/
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
#include <windows.h>
|
||||
#include <crtdbg.h>
|
||||
#include <imagehlp.h>
|
||||
|
||||
/* Include prototypes for HeapCheck functions */
|
||||
#include "HeapCheckPrototypes.h"
|
||||
|
||||
/*
|
||||
* It is possible to write code that bypasses the allocation mechanisms of
|
||||
* the library, and allocates from the standard VC-heap. An example inside
|
||||
* the runtime library is the use of an enhanced 'new' operator in
|
||||
* iostrini.cpp (line 21) and cerrinit.cpp (line 21) where _new_crt is used.
|
||||
* _new_crt maps through a #define to a 'new' operator that takes extra
|
||||
* parameters. HeapCheck can't catch this call, so when the time comes for
|
||||
* the deletion of these blocks, the library's delete operator doesn't find
|
||||
* them in it's tables. It is capable though to understand that these are
|
||||
* VC-heap blocks, through the use of _CrtIsValidHeapPointer.
|
||||
*
|
||||
* If you #define NO_VC_HEAP_ERRS, the library won't complain for such
|
||||
* situations. This is the default, but if you use inside your code direct
|
||||
* calls to _malloc_dbg, _calloc_dbg, etc, you should disable this.
|
||||
*/
|
||||
|
||||
#define NO_VC_HEAP_ERRS
|
||||
|
||||
/*
|
||||
* Modify this for Alpha, PowerPC, etc. It is the page size used by
|
||||
* the virtual memory hardware. For Intel architectures, this is 4096
|
||||
* bytes. For others, place a breakpoint in the call to HeapCheckStartup's
|
||||
* GetSystemInfo, and read the 'dwPageSize' field of the 'si' variable.
|
||||
*/
|
||||
|
||||
#define PAGE_SIZE 4096
|
||||
|
||||
/*
|
||||
* Total concurrent allocations possible. If your program needs more,
|
||||
* you'll get an assertion telling you to increase this.
|
||||
*/
|
||||
|
||||
#define MAX_ALLOCATIONS 16384
|
||||
|
||||
/*
|
||||
* Total heap available to the application. If your program needs more,
|
||||
* you'll get an assertion telling you to increase this.
|
||||
*/
|
||||
|
||||
#define MAX_ALLOCATABLE_BLOCK 8*1048576
|
||||
|
||||
/*
|
||||
* Max depth of call stack looked up when our functions are called
|
||||
*/
|
||||
|
||||
#define MAX_STACK_DEPTH 30
|
||||
|
||||
/*
|
||||
* Define PRINT_NUMERIC_EIP to get stack traces that boldly go
|
||||
* where no imagehlp.dll has gone before... Hope you have SoftIce...
|
||||
*/
|
||||
|
||||
//#define PRINT_NUMERIC_EIP
|
||||
|
||||
/*
|
||||
* Variables
|
||||
*/
|
||||
|
||||
static DWORD dwAllocationGranularity = 0;
|
||||
|
||||
static PCHAR pMemoryBase;
|
||||
static DWORD dwTotalPages;
|
||||
static DWORD dwFreePages;
|
||||
|
||||
static struct tag_allocations {
|
||||
DWORD isFree;
|
||||
PCHAR pData;
|
||||
DWORD dwPages;
|
||||
DWORD dwLength;
|
||||
DWORD EIPs[MAX_STACK_DEPTH];
|
||||
} allocations[MAX_ALLOCATIONS];
|
||||
|
||||
static BYTE pagesState[MAX_ALLOCATABLE_BLOCK/PAGE_SIZE];
|
||||
|
||||
static DWORD dwTotalPeakMemory = 0, dwTotalAllocated = 0;
|
||||
|
||||
static CRITICAL_SECTION section;
|
||||
|
||||
/*
|
||||
* Function prototypes.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Weird hack, in order to support 5 and 6 argument passing to _CrtDbgReport.
|
||||
* Unforunately, with VC 5.0/6.0, RPT macros go up until _RPT4!
|
||||
*/
|
||||
|
||||
#ifndef _RPT5
|
||||
#define _RPT5(rptno, msg, arg1, arg2, arg3, arg4, arg5) \
|
||||
do { if ((1 == _CrtDbgReport(rptno, NULL, 0, NULL, msg, arg1, arg2, arg3, arg4, arg5))) \
|
||||
_CrtDbgBreak(); } while (0)
|
||||
#endif
|
||||
|
||||
#ifndef _RPT6
|
||||
#define _RPT6(rptno, msg, arg1, arg2, arg3, arg4, arg5, arg6) \
|
||||
do { if ((1 == _CrtDbgReport(rptno, NULL, 0, NULL, msg, arg1, arg2, arg3, arg4, arg5, arg6))) \
|
||||
_CrtDbgBreak(); } while (0)
|
||||
#endif
|
||||
|
||||
static void HeapCheckStartup(void);
|
||||
static void HeapCheckShutDown(void);
|
||||
|
||||
/*
|
||||
* Simple allocator of pages that never frees.
|
||||
*/
|
||||
|
||||
static void *
|
||||
FindConsecutiveFreePagesSimple(DWORD dwPages)
|
||||
{
|
||||
return pMemoryBase + PAGE_SIZE*(dwTotalPages - dwFreePages);
|
||||
}
|
||||
|
||||
/*
|
||||
* Page allocator that searches for free pages.
|
||||
* Can be improved with better algorithms, but it's good enough for
|
||||
* most projects...
|
||||
*/
|
||||
|
||||
static void *
|
||||
FindConsecutiveFreePages(DWORD dwPages)
|
||||
{
|
||||
DWORD i;
|
||||
PVOID pv;
|
||||
|
||||
for(i=0; i<sizeof(pagesState); i++) {
|
||||
if (!pagesState[i]) {
|
||||
// Found a free page. Make sure there's enough free pages after it...
|
||||
|
||||
PVOID test;
|
||||
|
||||
// If you land here after an assertion, stop debugging
|
||||
// and increase MAX_ALLOCATABLE_BLOCK
|
||||
_ASSERTE ((i + dwPages - 1) < sizeof(pagesState));
|
||||
|
||||
// Search for used-up page in our searching range...
|
||||
test = memchr(&pagesState[i], 1, dwPages);
|
||||
|
||||
if (!test) // We found enough pages.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If you land here after an assertion 'Retry', stop debugging
|
||||
// and increase MAX_ALLOCATABLE_BLOCK
|
||||
_ASSERTE(i<sizeof(pagesState));
|
||||
|
||||
// Set 1 to these pages's slots to reflect NON-FREE state
|
||||
FillMemory(&pagesState[i], dwPages, 1);
|
||||
|
||||
pv = pMemoryBase + i*PAGE_SIZE;
|
||||
return pv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Utility function for VC-heap blocks.
|
||||
* Should be using binary search, but hey...I'm lazy.
|
||||
*
|
||||
* NOT TESTED YET - Who cares about VC-blocks?
|
||||
*/
|
||||
|
||||
static DWORD
|
||||
GetSize(PVOID pData)
|
||||
{
|
||||
// Search for block length....
|
||||
DWORD dwTest;
|
||||
|
||||
for(dwTest=0; dwTest<MAX_ALLOCATABLE_BLOCK; dwTest++)
|
||||
if (_CrtIsMemoryBlock(pData, dwTest, NULL, NULL, NULL))
|
||||
break;
|
||||
|
||||
if (dwTest == MAX_ALLOCATABLE_BLOCK)
|
||||
return -1;
|
||||
else
|
||||
return dwTest;
|
||||
}
|
||||
|
||||
static void FillCallStack(
|
||||
DWORD EIPs[])
|
||||
{
|
||||
DWORD LevelOneFrame;
|
||||
DWORD dwFrame = 0;
|
||||
|
||||
__asm {
|
||||
push eax
|
||||
push ebx
|
||||
mov eax, [ebp] // return to the frame of the caller
|
||||
mov LevelOneFrame, eax
|
||||
pop ebx
|
||||
pop eax
|
||||
}
|
||||
|
||||
while(1) {
|
||||
DWORD _eip;
|
||||
|
||||
if (IsBadReadPtr((VOID*)LevelOneFrame, 8))
|
||||
break;
|
||||
if (LevelOneFrame & 3)
|
||||
break;
|
||||
|
||||
_eip = ((PULONG) LevelOneFrame)[1];
|
||||
if (!_eip)
|
||||
break;
|
||||
|
||||
// If you end up in this assertion, stop debugging and re-compile
|
||||
// with an increased value for the MAX_STACK_DEPTH constant.
|
||||
_ASSERTE(dwFrame < MAX_STACK_DEPTH);
|
||||
|
||||
EIPs[dwFrame++] = _eip;
|
||||
LevelOneFrame = ((PULONG) LevelOneFrame)[0];
|
||||
}
|
||||
EIPs[dwFrame] = 0;
|
||||
}
|
||||
|
||||
static void PrintCaller()
|
||||
{
|
||||
DWORD LevelOneFrame;
|
||||
IMAGEHLP_LINE dbgLine;
|
||||
DWORD dwTemp;
|
||||
HANDLE hProcess = GetCurrentProcess();
|
||||
__asm {
|
||||
push eax
|
||||
push ebx
|
||||
mov eax, [ebp] // return to the frame of the caller
|
||||
mov LevelOneFrame, eax
|
||||
pop ebx
|
||||
pop eax
|
||||
}
|
||||
|
||||
while(1) {
|
||||
DWORD _eip;
|
||||
|
||||
if (IsBadReadPtr((VOID*)LevelOneFrame, 8))
|
||||
break;
|
||||
if (LevelOneFrame & 3)
|
||||
break;
|
||||
|
||||
_eip = ((PULONG) LevelOneFrame)[1];
|
||||
if (!_eip)
|
||||
break;
|
||||
|
||||
ZeroMemory(&dbgLine, sizeof(IMAGEHLP_LINE));
|
||||
dbgLine.SizeOfStruct = sizeof(IMAGEHLP_LINE);
|
||||
if(!SymGetLineFromAddr(hProcess, _eip, &dwTemp, &dbgLine)) {
|
||||
//_RPT1(_CRT_WARN, "Called from EIP = %x\n", _eip);
|
||||
break;
|
||||
} else {
|
||||
_RPT3(
|
||||
_CRT_WARN,
|
||||
"\tCalled from line %d(+%d bytes) of %s\n",
|
||||
dbgLine.LineNumber,
|
||||
dwTemp,
|
||||
dbgLine.FileName);
|
||||
}
|
||||
|
||||
LevelOneFrame = ((PULONG) LevelOneFrame)[0];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Post-allocation fence versions of malloc, calloc, realloc and free
|
||||
*/
|
||||
void *
|
||||
HeapCheckPostFenceMalloc(
|
||||
size_t blockSize)
|
||||
{
|
||||
DWORD dwSlot;
|
||||
DWORD dwPages;
|
||||
DWORD dwOldProtection;
|
||||
PCHAR data = NULL;
|
||||
BOOL bResult = FALSE;
|
||||
LPVOID lpvResult = NULL;
|
||||
static DWORD dwFirstTime = 1;
|
||||
|
||||
if (dwFirstTime) {
|
||||
dwFirstTime = 0;
|
||||
HeapCheckStartup();
|
||||
}
|
||||
|
||||
if (!blockSize)
|
||||
return NULL;
|
||||
|
||||
EnterCriticalSection(§ion);
|
||||
|
||||
for(dwSlot = 0; dwSlot<MAX_ALLOCATIONS; dwSlot++)
|
||||
if (allocations[dwSlot].isFree) {
|
||||
allocations[dwSlot].isFree = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
// If you end up in this assertion, stop debugging and re-compile
|
||||
// with an increased value for the MAX_ALLOCATIONS constant.
|
||||
_ASSERTE(dwSlot != MAX_ALLOCATIONS);
|
||||
|
||||
// Calculate number of requires pages
|
||||
dwPages = ((blockSize - 1) / PAGE_SIZE) + 2;
|
||||
|
||||
//_RPT2(_CRT_WARN, "Requested %7d bytes, granted %2d pages\n", blockSize, dwPages);
|
||||
|
||||
// Make sure we have enough room
|
||||
if (dwFreePages < dwPages) {
|
||||
_RPT1(
|
||||
_CRT_WARN,
|
||||
"Your application requires more free memory...\n"
|
||||
"Increase MAX_ALLOCATABLE_BLOCK in %s.", __FILE__);
|
||||
_ASSERTE(dwFreePages >= dwPages);
|
||||
}
|
||||
|
||||
data = (char*)FindConsecutiveFreePages(dwPages);
|
||||
|
||||
// OK, now make data-pages available...
|
||||
lpvResult = VirtualAlloc(
|
||||
(LPVOID) data,
|
||||
(dwPages-1)*PAGE_SIZE,
|
||||
MEM_COMMIT,
|
||||
PAGE_READWRITE);
|
||||
_ASSERTE(lpvResult != NULL );
|
||||
|
||||
VirtualProtect(
|
||||
(LPVOID) data,
|
||||
(dwPages-1)*PAGE_SIZE,
|
||||
PAGE_READWRITE,
|
||||
&dwOldProtection);
|
||||
|
||||
// and fence-page untouchable!
|
||||
bResult = VirtualFree(
|
||||
(LPVOID) (data + (dwPages-1)*PAGE_SIZE),
|
||||
PAGE_SIZE,
|
||||
MEM_DECOMMIT);
|
||||
_ASSERTE(bResult == TRUE);
|
||||
|
||||
data += (PAGE_SIZE - (blockSize % PAGE_SIZE)) % PAGE_SIZE;
|
||||
|
||||
dwFreePages -= dwPages;
|
||||
|
||||
allocations[dwSlot].pData = data;
|
||||
allocations[dwSlot].dwPages = dwPages;
|
||||
allocations[dwSlot].dwLength = blockSize;
|
||||
|
||||
FillCallStack(allocations[dwSlot].EIPs);
|
||||
|
||||
// Cause problems to users who think malloc zeroes block memory...
|
||||
FillMemory(data, blockSize, 0xCD);
|
||||
|
||||
dwTotalAllocated += blockSize;
|
||||
if (dwTotalPeakMemory<dwTotalAllocated)
|
||||
dwTotalPeakMemory = dwTotalAllocated;
|
||||
|
||||
LeaveCriticalSection(§ion);
|
||||
|
||||
return (void *)data;
|
||||
}
|
||||
|
||||
void *
|
||||
HeapCheckPostFenceCalloc(
|
||||
size_t blockSize)
|
||||
{
|
||||
PVOID *data = (PVOID*) HeapCheckPostFenceMalloc(blockSize);
|
||||
if (data)
|
||||
FillMemory(data, blockSize, 0);
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
HeapCheckPostFenceRealloc(
|
||||
void *ptr,
|
||||
size_t size)
|
||||
{
|
||||
void *tmpData;
|
||||
DWORD dw;
|
||||
|
||||
EnterCriticalSection(§ion);
|
||||
|
||||
for(dw=0; dw<MAX_ALLOCATIONS; dw++)
|
||||
if(!allocations[dw].isFree)
|
||||
if(allocations[dw].pData == ptr)
|
||||
break;
|
||||
|
||||
if(dw == MAX_ALLOCATIONS) {
|
||||
_RPT0(
|
||||
_CRT_WARN,
|
||||
"### ERROR ### Attempt to realloc unallocated block!...\n");
|
||||
PrintCaller();
|
||||
_ASSERTE(dw != MAX_ALLOCATIONS);
|
||||
}
|
||||
|
||||
LeaveCriticalSection(§ion);
|
||||
|
||||
tmpData = HeapCheckPostFenceMalloc(size);
|
||||
if (!tmpData)
|
||||
return NULL;
|
||||
|
||||
if (size < allocations[dw].dwLength)
|
||||
CopyMemory(tmpData, allocations[dw].pData, size);
|
||||
else
|
||||
CopyMemory(tmpData, allocations[dw].pData, allocations[dw].dwLength);
|
||||
|
||||
HeapCheckPostFenceFree(ptr);
|
||||
|
||||
return tmpData;
|
||||
}
|
||||
|
||||
void
|
||||
HeapCheckPostFenceFree(
|
||||
void *pData)
|
||||
{
|
||||
PCHAR pTmp = (PCHAR) pData;
|
||||
DWORD dw;
|
||||
|
||||
EnterCriticalSection(§ion);
|
||||
|
||||
for(dw=0; dw<MAX_ALLOCATIONS; dw++)
|
||||
if(!allocations[dw].isFree)
|
||||
if(allocations[dw].pData == pData)
|
||||
break;
|
||||
|
||||
if(dw == MAX_ALLOCATIONS) {
|
||||
// This is a block not allocated from us...
|
||||
// Check first to see if it was allocated from
|
||||
// the normal VC heap through any direct calls
|
||||
// (brain-dead coding, that is)
|
||||
|
||||
if (_CrtIsValidHeapPointer(pData)) {
|
||||
#ifndef NO_VC_HEAP_ERRS
|
||||
char *origFileName;
|
||||
DWORD origLineNo, origBlockSize;
|
||||
|
||||
if (_CrtIsMemoryBlock(
|
||||
pData,
|
||||
origBlockSize = GetSize(pData),
|
||||
NULL,
|
||||
&origFileName,
|
||||
&origLineNo))
|
||||
{
|
||||
_RPT6(
|
||||
_CRT_WARN,
|
||||
"Freeing VC-heap allocated block (%d bytes from line %d of %s)\n",
|
||||
origBlockSize, origLineNo, origFileName);
|
||||
PrintCaller();
|
||||
}
|
||||
else {
|
||||
_RPT0(
|
||||
_CRT_WARN,
|
||||
"Freeing unknown VC-heap allocated block\n");
|
||||
PrintCaller();
|
||||
_CrtDbgBreak();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
_RPT0(
|
||||
_CRT_WARN,
|
||||
"### ERROR ### Attempt to free unallocated block!... \n");
|
||||
PrintCaller();
|
||||
_CrtDbgBreak();
|
||||
}
|
||||
LeaveCriticalSection(§ion);
|
||||
return;
|
||||
}
|
||||
|
||||
// Make data pages inaccessible, since they are freed!
|
||||
pTmp -= (((DWORD)pTmp) % PAGE_SIZE);
|
||||
VirtualFree(
|
||||
pTmp,
|
||||
(allocations[dw].dwPages - 1)*PAGE_SIZE,
|
||||
MEM_DECOMMIT);
|
||||
|
||||
// Set these pages to 'available' again.
|
||||
ZeroMemory(
|
||||
&pagesState[ (pTmp - pMemoryBase)/PAGE_SIZE ],
|
||||
allocations[dw].dwPages);
|
||||
dwFreePages += allocations[dw].dwPages;
|
||||
|
||||
dwTotalAllocated -= allocations[dw].dwLength;
|
||||
|
||||
allocations[dw].isFree = 1;
|
||||
allocations[dw].pData = NULL;
|
||||
allocations[dw].dwPages = 0;
|
||||
allocations[dw].dwLength = 0;
|
||||
allocations[dw].EIPs[0] = 0;
|
||||
|
||||
LeaveCriticalSection(§ion);
|
||||
}
|
||||
|
||||
/*
|
||||
* Pre-allocation fence versions of malloc, calloc, realloc and free
|
||||
*
|
||||
*/
|
||||
|
||||
void *
|
||||
HeapCheckPreFenceMalloc(
|
||||
size_t blockSize)
|
||||
{
|
||||
DWORD dwSlot;
|
||||
DWORD dwPages, dwOldProtection;
|
||||
PCHAR data = NULL;
|
||||
BOOL bResult = FALSE;
|
||||
LPVOID lpvResult = NULL;
|
||||
static DWORD dwFirstTime = 1;
|
||||
|
||||
if (dwFirstTime) {
|
||||
dwFirstTime = 0;
|
||||
HeapCheckStartup();
|
||||
}
|
||||
|
||||
if (!blockSize)
|
||||
return NULL;
|
||||
|
||||
EnterCriticalSection(§ion);
|
||||
|
||||
for(dwSlot = 0; dwSlot<MAX_ALLOCATIONS; dwSlot++)
|
||||
if (allocations[dwSlot].isFree) {
|
||||
allocations[dwSlot].isFree = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
// If you end up in this assertion, stop debugging and re-compile
|
||||
// with an increased value for the MAX_ALLOCATIONS constant.
|
||||
_ASSERTE(dwSlot != MAX_ALLOCATIONS);
|
||||
|
||||
// Calculate number of requires pages
|
||||
dwPages = ((blockSize - 1) / PAGE_SIZE) + 2;
|
||||
|
||||
//_RPT2(_CRT_WARN, "Requested %7d bytes, granted %2d pages\n", blockSize, dwPages);
|
||||
|
||||
// Make sure we have enough room
|
||||
if (dwFreePages < dwPages) {
|
||||
_RPT1(
|
||||
_CRT_WARN,
|
||||
"Your application requires more free memory...\n"
|
||||
"Change MAX_ALLOCATABLE_BLOCK in %s.", __FILE__);
|
||||
_ASSERTE(dwFreePages >= dwPages);
|
||||
}
|
||||
|
||||
data = (char*) FindConsecutiveFreePages(dwPages);
|
||||
|
||||
// OK, now make fence-page untouchable...
|
||||
bResult = VirtualFree(
|
||||
(LPVOID) data,
|
||||
PAGE_SIZE,
|
||||
MEM_DECOMMIT);
|
||||
_ASSERTE(bResult == TRUE);
|
||||
|
||||
// and data-pages available!
|
||||
lpvResult = VirtualAlloc(
|
||||
(LPVOID) (data+PAGE_SIZE),
|
||||
(dwPages-1)*PAGE_SIZE,
|
||||
MEM_COMMIT,
|
||||
PAGE_READWRITE);
|
||||
_ASSERTE(lpvResult != NULL );
|
||||
|
||||
VirtualProtect(
|
||||
(LPVOID) (data+PAGE_SIZE),
|
||||
(dwPages-1)*PAGE_SIZE,
|
||||
PAGE_READWRITE,
|
||||
&dwOldProtection);
|
||||
|
||||
data += PAGE_SIZE;
|
||||
|
||||
dwFreePages -= dwPages;
|
||||
|
||||
allocations[dwSlot].pData = data;
|
||||
allocations[dwSlot].dwPages = dwPages;
|
||||
allocations[dwSlot].dwLength = blockSize;
|
||||
|
||||
FillCallStack(allocations[dwSlot].EIPs);
|
||||
|
||||
// Cause problems to users who think malloc zeroes block memory...
|
||||
FillMemory(data, blockSize, 0xCD);
|
||||
|
||||
dwTotalAllocated += blockSize;
|
||||
if (dwTotalPeakMemory<dwTotalAllocated)
|
||||
dwTotalPeakMemory = dwTotalAllocated;
|
||||
|
||||
LeaveCriticalSection(§ion);
|
||||
|
||||
return (void *)data;
|
||||
}
|
||||
|
||||
void *
|
||||
HeapCheckPreFenceCalloc(
|
||||
size_t blockSize)
|
||||
{
|
||||
PVOID *data = (PVOID*) HeapCheckPreFenceMalloc(blockSize);
|
||||
if (data)
|
||||
FillMemory(data, blockSize, 0);
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
HeapCheckPreFenceRealloc(
|
||||
void *ptr,
|
||||
size_t size)
|
||||
{
|
||||
void *tmpData;
|
||||
DWORD dw;
|
||||
|
||||
EnterCriticalSection(§ion);
|
||||
|
||||
for(dw=0; dw<MAX_ALLOCATIONS; dw++)
|
||||
if(!allocations[dw].isFree)
|
||||
if(allocations[dw].pData == ptr)
|
||||
break;
|
||||
if(dw == MAX_ALLOCATIONS) {
|
||||
_RPT0(
|
||||
_CRT_WARN,
|
||||
"### ERROR ### Attempt to realloc unallocated block!...\n");
|
||||
PrintCaller();
|
||||
_ASSERTE(dw != MAX_ALLOCATIONS);
|
||||
}
|
||||
|
||||
LeaveCriticalSection(§ion);
|
||||
|
||||
tmpData = HeapCheckPreFenceMalloc(size);
|
||||
if (!tmpData)
|
||||
return NULL;
|
||||
|
||||
if (size < allocations[dw].dwLength)
|
||||
CopyMemory(tmpData, allocations[dw].pData, size);
|
||||
else
|
||||
CopyMemory(tmpData, allocations[dw].pData, allocations[dw].dwLength);
|
||||
|
||||
HeapCheckPreFenceFree(ptr);
|
||||
|
||||
return tmpData;
|
||||
}
|
||||
|
||||
void
|
||||
HeapCheckPreFenceFree(
|
||||
void *pData)
|
||||
{
|
||||
PCHAR pTmp;
|
||||
DWORD dw;
|
||||
|
||||
EnterCriticalSection(§ion);
|
||||
|
||||
for(dw=0; dw<MAX_ALLOCATIONS; dw++)
|
||||
if(!allocations[dw].isFree)
|
||||
if(allocations[dw].pData == pData)
|
||||
break;
|
||||
|
||||
if(dw == MAX_ALLOCATIONS) {
|
||||
// This is a block not allocated from us...
|
||||
// Check first to see if it was allocated from
|
||||
// the normal VC heap through any direct calls
|
||||
// (brain-dead coding, that is)
|
||||
|
||||
if (_CrtIsValidHeapPointer(pData)) {
|
||||
#ifndef NO_VC_HEAP_ERRS
|
||||
char *origFileName;
|
||||
DWORD origLineNo, origBlockSize;
|
||||
|
||||
if (_CrtIsMemoryBlock(
|
||||
pData,
|
||||
origBlockSize = GetSize(pData),
|
||||
NULL,
|
||||
&origFileName,
|
||||
&origLineNo))
|
||||
{
|
||||
_RPT6(
|
||||
_CRT_WARN,
|
||||
"Freeing VC-heap allocated block (%d bytes from line %d of %s)\n",
|
||||
origBlockSize, origLineNo, origFileName);
|
||||
PrintCaller();
|
||||
}
|
||||
else {
|
||||
_RPT0(
|
||||
_CRT_WARN,
|
||||
"Freeing unknown VC-heap allocated block\n");
|
||||
PrintCaller();
|
||||
_CrtDbgBreak();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
_RPT0(
|
||||
_CRT_WARN,
|
||||
"### ERROR ### Attempt to free unallocated block!... \n");
|
||||
PrintCaller();
|
||||
_CrtDbgBreak();
|
||||
}
|
||||
LeaveCriticalSection(§ion);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Make data pages inaccessible, since they are freed!
|
||||
VirtualFree(
|
||||
pData,
|
||||
(allocations[dw].dwPages - 1)*PAGE_SIZE,
|
||||
MEM_DECOMMIT);
|
||||
|
||||
// Set these pages to 'available' again.
|
||||
pTmp = (PCHAR) pData;
|
||||
pTmp -= PAGE_SIZE;
|
||||
ZeroMemory(
|
||||
&pagesState[ (pTmp - pMemoryBase)/PAGE_SIZE ],
|
||||
allocations[dw].dwPages);
|
||||
dwFreePages += allocations[dw].dwPages;
|
||||
|
||||
dwTotalAllocated -= allocations[dw].dwLength;
|
||||
|
||||
allocations[dw].isFree = 1;
|
||||
allocations[dw].pData = NULL;
|
||||
allocations[dw].dwPages = 0;
|
||||
allocations[dw].dwLength = 0;
|
||||
allocations[dw].EIPs[0] = 0;
|
||||
|
||||
LeaveCriticalSection(§ion);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Startup and shutdown functions
|
||||
*/
|
||||
|
||||
static void
|
||||
HeapCheckStartup()
|
||||
{
|
||||
SYSTEM_INFO si;
|
||||
DWORD dw;
|
||||
CHAR dbgPath[MAX_PATH], *pEnd;
|
||||
|
||||
SymSetOptions(SymGetOptions() | SYMOPT_LOAD_LINES );
|
||||
|
||||
// Try to read the symbols from the path of the .exe file
|
||||
if (!GetModuleFileName(
|
||||
NULL,
|
||||
dbgPath,
|
||||
sizeof(dbgPath))) {
|
||||
|
||||
// if we failed, do your best
|
||||
if(!SymInitialize(GetCurrentProcess(), NULL, TRUE)) {
|
||||
_RPT0(
|
||||
_CRT_WARN,
|
||||
"HEAPCHECK: Won't be able to read file/line information...:(\n");
|
||||
}
|
||||
} else {
|
||||
pEnd = strrchr(dbgPath, '\\');
|
||||
if (!pEnd) {
|
||||
// if we failed, do your best
|
||||
if(!SymInitialize(GetCurrentProcess(), NULL, TRUE)) {
|
||||
_RPT0(
|
||||
_CRT_WARN,
|
||||
"HEAPCHECK: Won't be able to read file/line information...:(\n");
|
||||
}
|
||||
} else {
|
||||
// 99% probability of success with file/line info...!
|
||||
*pEnd = 0;
|
||||
if(!SymInitialize(GetCurrentProcess(), dbgPath, TRUE)) {
|
||||
_RPT0(
|
||||
_CRT_WARN,
|
||||
"HEAPCHECK: Won't be able to read file/line information...:(\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
InitializeCriticalSection(§ion);
|
||||
|
||||
GetSystemInfo(&si);
|
||||
|
||||
_ASSERTE(si.dwPageSize == PAGE_SIZE);
|
||||
dwAllocationGranularity = si.dwAllocationGranularity;
|
||||
|
||||
_ASSERTE(dwAllocationGranularity <= MAX_ALLOCATABLE_BLOCK);
|
||||
|
||||
pMemoryBase = (PCHAR) VirtualAlloc(
|
||||
NULL, // Place memory base wherever
|
||||
MAX_ALLOCATABLE_BLOCK, // Total heap memory available
|
||||
MEM_RESERVE, // For now, just reserve it
|
||||
PAGE_NOACCESS); // and make it no-touch.
|
||||
|
||||
_ASSERTE(pMemoryBase != NULL);
|
||||
|
||||
dwTotalPages = MAX_ALLOCATABLE_BLOCK / PAGE_SIZE;
|
||||
dwFreePages = dwTotalPages;
|
||||
|
||||
if(atexit(HeapCheckShutDown)) {
|
||||
_RPT0(_CRT_WARN, "### WARNING ### Can't check for memory leaks automatically!\n");
|
||||
_RPT0(_CRT_WARN, "### WARNING ### Call HeapCheckShutDown at the end of your app,\n");
|
||||
}
|
||||
|
||||
for(dw=0; dw<MAX_ALLOCATIONS; dw++)
|
||||
allocations[dw].isFree = 1;
|
||||
|
||||
ZeroMemory(pagesState, sizeof(pagesState));
|
||||
}
|
||||
|
||||
static void
|
||||
HeapCheckShutDown()
|
||||
{
|
||||
BOOL bSuccess;
|
||||
DWORD dw;
|
||||
HANDLE hProcess = GetCurrentProcess();
|
||||
|
||||
EnterCriticalSection(§ion);
|
||||
|
||||
_RPT0(_CRT_WARN, "\n##################################\n");
|
||||
_RPT0(_CRT_WARN, "####### HeapCheck report ######\n");
|
||||
_RPT0(_CRT_WARN, "##################################\n\n");
|
||||
|
||||
for(dw=0; dw<MAX_ALLOCATIONS; dw++) {
|
||||
if (!allocations[dw].isFree) {
|
||||
|
||||
// We have to use IMAGEHLP.DLL. God help us...
|
||||
IMAGEHLP_LINE dbgLine;
|
||||
DWORD dwTemp, dwCodePlaces = 0;
|
||||
|
||||
_RPT1(
|
||||
_CRT_WARN,
|
||||
"### WARNING ### Memory leak (%d bytes) found... Allocated:\n",
|
||||
allocations[dw].dwLength);
|
||||
|
||||
while(allocations[dw].EIPs[dwCodePlaces]) {
|
||||
|
||||
ZeroMemory(&dbgLine, sizeof(IMAGEHLP_LINE));
|
||||
dbgLine.SizeOfStruct = sizeof(IMAGEHLP_LINE);
|
||||
if(!SymGetLineFromAddr(
|
||||
hProcess,
|
||||
allocations[dw].EIPs[dwCodePlaces],
|
||||
&dwTemp,
|
||||
&dbgLine))
|
||||
{
|
||||
#ifdef PRINT_NUMERIC_EIP
|
||||
_RPT1(
|
||||
_CRT_WARN,
|
||||
"\tfrom EIP = %x\n",
|
||||
allocations[dw].EIPs[dwCodePlaces]);
|
||||
#endif
|
||||
} else {
|
||||
_RPT3(
|
||||
_CRT_WARN,
|
||||
"\tfrom line %d(+%d bytes) of %s\n",
|
||||
dbgLine.LineNumber,
|
||||
dwTemp,
|
||||
dbgLine.FileName);
|
||||
}
|
||||
dwCodePlaces++;
|
||||
|
||||
// If you land here after an assertion, stop debugging
|
||||
// and increase MAX_STACK_DEPTH
|
||||
_ASSERTE(dwCodePlaces < MAX_STACK_DEPTH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Decommit the entire block. */
|
||||
bSuccess = VirtualFree(
|
||||
pMemoryBase, /* base address of block */
|
||||
MAX_ALLOCATABLE_BLOCK, /* bytes of committed pages */
|
||||
MEM_DECOMMIT); /* decommit the pages */
|
||||
_ASSERTE(bSuccess);
|
||||
|
||||
/* Release the entire block. */
|
||||
if (bSuccess)
|
||||
bSuccess = VirtualFree(
|
||||
pMemoryBase, /* base address of block */
|
||||
0, /* releases the entire block */
|
||||
MEM_RELEASE); /* releases the pages */
|
||||
_ASSERTE(bSuccess);
|
||||
|
||||
_RPT1(_CRT_WARN, "HeapCheck Statistics:\n\tMaximum memory allocated = %d\n\n", dwTotalPeakMemory);
|
||||
|
||||
SymCleanup(hProcess);
|
||||
|
||||
LeaveCriticalSection(§ion);
|
||||
DeleteCriticalSection(§ion);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
const char *BOINC_RCSID_972eaf72ca = "$Id$";
|
|
@ -1,47 +0,0 @@
|
|||
/***************************************************************************
|
||||
* HeapCheck - a heap debugging library
|
||||
* Copyright (C) 2001 Thanassis Tsiodras (ttsiod@softlab.ntua.gr)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __PROTOTYP_H__
|
||||
#define __PROTOTYP_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
extern "C" {
|
||||
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void *HeapCheckPostFenceMalloc(size_t s);
|
||||
void *HeapCheckPreFenceMalloc(size_t s);
|
||||
void *HeapCheckPostFenceCalloc(size_t s);
|
||||
void *HeapCheckPreFenceCalloc(size_t s);
|
||||
void *HeapCheckPostFenceRealloc(void *p, size_t s);
|
||||
void *HeapCheckPreFenceRealloc(void *p, size_t s);
|
||||
void HeapCheckPostFenceFree(void *p);
|
||||
void HeapCheckPreFenceFree(void *p);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
/*void *operator new(size_t size);
|
||||
void *operator new[](size_t size);
|
||||
void operator delete(void *p);
|
||||
void operator delete[](void *p);*/
|
||||
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __PROTOTYP_H__ */
|
|
@ -1,12 +0,0 @@
|
|||
September 2001: HeapCheck v1.2
|
||||
|
||||
- Incorporated suggested changes for stack-trace capabilities
|
||||
(Works for Intel CPUs and compatibles - AMD, Cyrix,...)
|
||||
- Handles multi-threading issues with a CRITICAL_SECTION
|
||||
- C++ Handling cleaned up
|
||||
- Up to 50% more memory available (guard pages are no longer physical)
|
||||
- Minor bugs removed
|
||||
|
||||
1999: HeapCheck v1.0
|
||||
|
||||
- First version released to the public
|
|
@ -1,398 +0,0 @@
|
|||
HeapCheck 1.2
|
||||
Thanassis Tsiodras, Dr.-Ing
|
||||
|
||||
|
||||
HeapCheck is a Debugging Library for Win32 environments. What sets it
|
||||
apart from other heap-debugging libraries is its ability to pinpoint
|
||||
invalid read accesses to the heap, not just heap corruptions. It also
|
||||
detects memory leaks and reports memory usage statistics. Access
|
||||
checks are done through the paging hardware of your CPU, and don't
|
||||
introduce any CPU overhead. HeapCheck debug versions run at almost the
|
||||
same speed as normal debug versions - with performance hits noticeable
|
||||
only when allocating and deallocating.
|
||||
|
||||
1. Disclaimer
|
||||
|
||||
|
||||
I am NOT responsible for any damages this causes to your computer,
|
||||
company, fame, payroll, etc. I am releasing my humble efforts to the
|
||||
public so that some programmer's life gets a little easier. If it
|
||||
leads you on a wild goose chase and you waste two weeks debugging
|
||||
something, too bad. If you can't deal with the above, please don't
|
||||
use the software! I've written this in an attempt to help other
|
||||
people, not to get myself sued or prosecuted.
|
||||
|
||||
|
||||
2. Features
|
||||
|
||||
|
||||
HeapCheck is a Win32 Debugging Allocator with the following features:
|
||||
|
||||
1. Detection of invalid read/write accesses to memory allocated with
|
||||
heap functions.
|
||||
|
||||
Let me stress this out: READ as well as write accesses!
|
||||
|
||||
2. Detection of memory leaks
|
||||
|
||||
3. Detection of invalid read/write accesses to freed memory
|
||||
|
||||
4. Thread safe
|
||||
|
||||
5. File/Line info reporting, based on imagehlp.dll
|
||||
|
||||
6. A GNU license (which means that it's free - read GnuLicense)
|
||||
|
||||
If you are eager to check it out, go to the Usage section. Just
|
||||
make sure you eventually read everything, or you'll be missing some
|
||||
goodies (like the ones in section ``Stack techniques'').
|
||||
|
||||
|
||||
3. Introduction
|
||||
|
||||
|
||||
As you program with C or C++, you are bound to hit upon a heap-related
|
||||
bug sooner or later. What's a heap, you ask? Well, it's the system
|
||||
resource from which you remove chunks when you call malloc(),
|
||||
calloc(), new(), etc. Unfortunately, it is associated with a lot of
|
||||
really tough bugs. You see, in this code:
|
||||
|
||||
|
||||
main()
|
||||
{
|
||||
char *p = (char *) malloc(5);
|
||||
strcpy( p, "12345");
|
||||
puts(p);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
...you probably get away clean in the debugging phase. You only
|
||||
allocated 5 bytes, you are writing 6 (5 for the string plus one
|
||||
trailing 0), but nothing seems to happen, right?
|
||||
|
||||
Wrong.
|
||||
|
||||
The extra byte you are writing moves your program into such things,
|
||||
others don't. Even those who seem to do, eventually don't. You see,
|
||||
the extra byte is written into memory not owned by the allocation.
|
||||
What is stored there can be anything from debugging info to
|
||||
application code.
|
||||
|
||||
Then again, we don't free the memory we allocated. It seems we forgot
|
||||
to:
|
||||
|
||||
free(p);
|
||||
|
||||
|
||||
Notice also that the call to 'puts' makes the system read 6 bytes,
|
||||
since puts is probably implemented in the C runtime library with some-
|
||||
thing like this:
|
||||
|
||||
while(*p)
|
||||
putchar(*p++);
|
||||
|
||||
|
||||
...which means that not only your code, but also system and RTL (run-
|
||||
time library) code accesses memory it shouldn't. This can make your
|
||||
program behave in a non-predictable way - crash sometimes, work OK as
|
||||
long as you don't run WinAmp... (you get the idea).
|
||||
|
||||
If you want to quickly find heap-related bugs in your Win32
|
||||
programming, you can use this library in addition to any others you
|
||||
have found/bought. It is a simple little library, which I have found
|
||||
useful in my programming efforts. Why do I use it instead of others
|
||||
(like the builtin debugging heap of Visual C++ 6.0)? It's small (and
|
||||
thus, easily configurable) and it supports C++. It also lacks any
|
||||
complicated interfaces, and provides you with a quick and easy way to
|
||||
detect invalid READ as well as write accesses (this last reason is
|
||||
probably the strongest point of the library).
|
||||
|
||||
HeapCheck employs a technique invented in the Unix's Electric Fence,
|
||||
created by Bruce Perens. It uses the virtual memory hardware of your
|
||||
computer to place an inaccessible memory page immediately after (or
|
||||
before, at a #define option) each memory allocation. When software
|
||||
reads or writes this inaccessible page, the hardware issues a
|
||||
segmentation fault, stopping the program at the offending
|
||||
instruction. It is then trivial to find the erroneous statement since
|
||||
Visual C++ will point to the code doing the invalid access. In a
|
||||
similar manner, memory that has been released is made
|
||||
inaccessible, and any code that touches it will get a segmentation
|
||||
fault.
|
||||
|
||||
HeapCheck also checks for any allocations you forgot to free/delete,
|
||||
and prints a report when your application exits to the Output window
|
||||
of Visual C++. This report tells you also the allocation requirements
|
||||
of your program (how much memory it needed in the previous run).
|
||||
|
||||
|
||||
|
||||
4. Usage
|
||||
|
||||
|
||||
You can easily use HeapCheck in your own programs in three easy steps:
|
||||
|
||||
|
||||
1. In the source files where you want the checks to take place,
|
||||
include the swaps.h header file. Make sure that it is the first
|
||||
include file you are using, after the system and RTL include files,
|
||||
e.g.
|
||||
|
||||
#include <xxx.h>
|
||||
#include <yyy.h>
|
||||
...
|
||||
#include "swaps.h"
|
||||
#include "myfile1.h"
|
||||
#include "myfile2.h"
|
||||
...
|
||||
|
||||
|
||||
This file #defines the calls to heap-related functions in your code to
|
||||
calls in the library. It also provides the prototypes for the new
|
||||
allocation and deletion operators.
|
||||
|
||||
2. If your code is in C only, add HeapCheck.c in the project, or
|
||||
|
||||
If your code is in C++, add HeapCheck.c and CplusCheck.cpp in the
|
||||
project.
|
||||
|
||||
3. Add imagehlp.lib in your link libraries.
|
||||
|
||||
That's it. Your code will be automatically checked for heap errors.
|
||||
To get correct file/line information, make sure you are using the
|
||||
correct versions of the debugging libraries (the Windows 2000 ones).
|
||||
I used dbghelp.dll version 5.0.2195.1, and imagehlp.dll version
|
||||
5.0.2195.1. Maybe SymGetLineFromAddr() works with other combinations,
|
||||
but I used these DLLs successfully under both NT 4.0sp6 and Windows
|
||||
2000.
|
||||
|
||||
By default, range checks will be done for post-block accesses.
|
||||
|
||||
After checking that everything works OK in this setup, modify your
|
||||
project so that PRE_CHECK is defined, or even edit swaps.h and define
|
||||
it on top:
|
||||
|
||||
#define PRE_CHECK
|
||||
|
||||
|
||||
Recompile everything, and this way, pre-block checking will take
|
||||
place.
|
||||
|
||||
HeapCheck messages appear on the Debugging Output of Visual C++. If
|
||||
you are running the program outside the IDE, use DebugView to see them
|
||||
(get it from www.sysinternals.com, an awesome site for programming
|
||||
utilities by the way).
|
||||
|
||||
If you program with MFC, make sure you use it in the form of a dynamic
|
||||
DLL (Project - Settings - General - Microsoft Foundation Classes - Use
|
||||
MFC in a Shared DLL) . Otherwise, you 'll get link problems, since MFC
|
||||
defines a global operator new, just as HeapCheck. If you use it in the
|
||||
form of a DLL, MFC sticks to its own operator new, while your code
|
||||
calls HeapCheck's.
|
||||
|
||||
When you have debugged your program, just recompile in Release mode.
|
||||
The debugging checks will melt away automatically.
|
||||
|
||||
|
||||
5. Configuration
|
||||
|
||||
|
||||
In HeapCheck.c, you can change the way the library behaves by
|
||||
changing:
|
||||
|
||||
|
||||
1. MAX_ALLOCATIONS:
|
||||
|
||||
Total concurrent allocations possible. If your program needs more,
|
||||
you'll get an assertion at runtime telling you to increase this.
|
||||
|
||||
|
||||
2. MAX_ALLOCATABLE_BLOCK:
|
||||
|
||||
Total heap available to the application. If your program needs
|
||||
more, you'll get an assertion at runtime telling you to increase
|
||||
this.
|
||||
|
||||
3. NO_VC_HEAP_ERRS:
|
||||
|
||||
It is possible to write code that bypasses the mechanisms of the
|
||||
library, and allocates from the standard VC-heap. An example is
|
||||
code inside the runtime library which is pre-compiled and uses
|
||||
different allocation mechanisms. Example: an enhanced new()
|
||||
operator in iostrini.cpp (line 21) and cerrinit.cpp (line 21) where
|
||||
_new_crt() is used. _new_crt() maps through a #define to a new()
|
||||
operator that takes extra parameters. HeapCheck can't catch this
|
||||
call, so when the time comes for the deletion of these blocks, the
|
||||
library's delete operator doesn't find them in it's tables. It is
|
||||
capable to understand that these are VC-heap blocks though, through
|
||||
the use of _CrtIsValidHeapPointer. If you #define NO_VC_HEAP_ERRS,
|
||||
the library won't complain for such situations. This is the
|
||||
default, but if your code issues direct calls to _malloc_dbg(),
|
||||
_calloc_dbg(), etc, you should disable this.
|
||||
|
||||
If the previous text sounds like Chinese, leave it as it is.
|
||||
|
||||
6. Debugging - Other tools
|
||||
|
||||
|
||||
1. Visual C++ 6.0 Runtime Heap Debugging:
|
||||
|
||||
This only checks for heap corruption (i.e. destructive side-effects
|
||||
of writing outside the allocations) and even then, it only catches
|
||||
writings in the NO_MANS_LAND_SIZE (default:4 bytes) on either side
|
||||
of the blocks. The detection of these errors is done whenever the
|
||||
user (or the system) calls _CrtCheckMemory(). HeapCheck catches
|
||||
read accesses as well, at the EXACT place they are made, and in a
|
||||
much larger block (a page in i386 systems is 4096 bytes).
|
||||
|
||||
2. BoundsChecker:
|
||||
|
||||
This is a very good debugging tool, capable of catching almost
|
||||
every bug. However, CPU cycles are used in order to perform all
|
||||
these checks, and especially in instrumentation mode and maximum
|
||||
memory checking, the program runs really slow (some programs, like
|
||||
protocol stacks, won't run correctly if they run too slowly).
|
||||
HeapCheck can only catch heap-related errors, but it uses the
|
||||
paging hardware to do the checking. The net result is that
|
||||
HeapCheck debug versions of programs run at almost the SAME speed
|
||||
as normal debug versions. In other words you can leave it in your
|
||||
project and forget about it (it will be automatically removed when
|
||||
you compile a Release version).
|
||||
|
||||
7. For UNIX gurus and fanatics only
|
||||
|
||||
|
||||
If you have a history using Electric Fence in UNIX, you'll remember
|
||||
that the only thing required was linking with libefence.a. Why can't
|
||||
we do something like this under Win32 for HeapCheck, too?
|
||||
|
||||
|
||||
1. Win32 ain't UNIX. I guess you knew that, but there's this little
|
||||
fact about libraries that makes them almost useless: if a library
|
||||
uses any function of the C run-time library (like memchr, strcpy,
|
||||
etc) it has to link with one of the six versions of the run-time
|
||||
library (RTL):
|
||||
|
||||
o Release, static, no multithreading
|
||||
|
||||
o Release, static, multithreading
|
||||
|
||||
o Release, dynamic, multithreading
|
||||
|
||||
o Debug, static, no multithreading
|
||||
|
||||
o Debug, static, multithreading
|
||||
|
||||
o Debug, dynamic, multithreading
|
||||
|
||||
|
||||
Now suppose that your library is linked with one of these RTLs.
|
||||
When you use your library inside one of your own projects, your
|
||||
project MUST be linked with the same RTL! Amazing. I don't know
|
||||
about you, but I prefer to just add two source files in the project
|
||||
and be done with it, instead of building six HeapCheck libraries.
|
||||
|
||||
I could replace calls to the C run-time library with my own
|
||||
versions of things, but that would lead to the next problem:
|
||||
|
||||
2. If HeapCheck was a library with implementations of standard
|
||||
functions (malloc, realloc, etc) then the projects using it would
|
||||
have to choose between using HeapCheck and using the C runtime
|
||||
library. Unless I am doing something wrong, the linker can't
|
||||
tolerate two libraries providing implementations of the same
|
||||
function. How is he to choose? The UNIX ld implements a first-serve
|
||||
attitude: Whichever library provides it first in the link line, is
|
||||
chosen.
|
||||
|
||||
If anyone of you comes up with any ideas on these matters, do
|
||||
share. This is why HeapCheck is under the GNU license - I made it,
|
||||
it's your turn now to make it better!
|
||||
|
||||
8. Stack techniques
|
||||
|
||||
If you are like me, you probably use code like this sometimes:
|
||||
|
||||
|
||||
void f()
|
||||
{
|
||||
char a[100];
|
||||
...
|
||||
}
|
||||
|
||||
|
||||
|
||||
Unfortunately, you don't have the automatic HeapCheck's checks for
|
||||
buffers allocated this way. There is a way around this, if you code in
|
||||
C++. Place this template/macro in a commonly accessed header file:
|
||||
|
||||
|
||||
template <class T>
|
||||
class Array {
|
||||
public:
|
||||
Array(T *p):_p(p) {}
|
||||
~Array() { delete [] _p; }
|
||||
|
||||
operator T*() { return _p; }
|
||||
T& operator [](int offset) { return _p[offset]; }
|
||||
T *GetPtr() { return _p; }
|
||||
|
||||
private:
|
||||
T *_p;
|
||||
};
|
||||
|
||||
#define ARRAY(x,y,z) Array<x> y(new x[z])
|
||||
|
||||
|
||||
and then, when you need a temporary array, use it like this:
|
||||
|
||||
|
||||
void f()
|
||||
{
|
||||
ARRAY(char,a,100);
|
||||
|
||||
or, directly:
|
||||
|
||||
void f()
|
||||
{
|
||||
Array<char> a(new char[100]);
|
||||
|
||||
|
||||
As you see, this way heap space is used for your arrays, and it is
|
||||
automatically freed when the variable goes out of scope, just like a
|
||||
stack-based array. So, you get the best of both worlds: automatic
|
||||
freeing (through the template) and bounds checking (through
|
||||
HeapCheck). This technique also lowers your stack usage, which could
|
||||
mean something if you use recursive algorithms.
|
||||
|
||||
|
||||
9. Known bugs
|
||||
|
||||
|
||||
HeapCheck uses the paging hardware of your machine to place an extra
|
||||
guard page before or after each allocation your program makes. A page
|
||||
is 4096 bytes for the vast majority of today's CPUs, which means that
|
||||
the memory requirements of your program can increase beyond usual. Of
|
||||
course these requirements vanish when you compile your Release
|
||||
versions, but still, make sure you have plenty of physical memory
|
||||
and/or swapfile for your Debug versions. For example, the default
|
||||
settings of HeapCheck create an 8MB heap. This consists of
|
||||
8*1048576/4096 = 2048 pages. If you make 1024 allocations of 1 byte
|
||||
each, you'll exhaust this heap (each allocation reserves one data and
|
||||
one guard page). This is the worst case scenario, of course, but it
|
||||
shows how quickly memory fills up with HeapCheck. From version 1.2 onward,
|
||||
guard pages no longer occupy physical storage, which will lower your
|
||||
actual memory requirements by up to 50%. You'll probably have to
|
||||
increase MAX_ALLOCATABLE_BLOCK in most cases, though ...(you'll know
|
||||
when to do this, because HeapCheck will give you an assertion when the
|
||||
heap is exhausted).
|
||||
|
||||
10. Contacting the author
|
||||
|
||||
|
||||
Why? As you can see in the disclaimer, I am not responsible for any
|
||||
disasters HeapCheck causes to the universe. Seriously though, I am
|
||||
interested in any bug reports/comments. You can e-mail me at
|
||||
ttsiod@softlab.ntua.gr
|
||||
|
||||
Good luck in your bughunts!
|
|
@ -1,41 +0,0 @@
|
|||
/***************************************************************************
|
||||
* HeapCheck - a heap debugging library
|
||||
* Copyright (C) 2001 Thanassis Tsiodras (ttsiod@softlab.ntua.gr)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*****************************************************************************/
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
#ifndef __SWAPS_H__
|
||||
#define __SWAPS_H__
|
||||
|
||||
#include "HeapCheckPrototypes.h"
|
||||
|
||||
#ifdef PRE_CHECK
|
||||
#define malloc(x) HeapCheckPreFenceMalloc(x)
|
||||
#define calloc(x,y) HeapCheckPreFenceCalloc(x*y)
|
||||
#define realloc(x,y) HeapCheckPreFenceRealloc(x,y)
|
||||
#define free(x) HeapCheckPreFenceFree(x)
|
||||
#else
|
||||
#define malloc(x) HeapCheckPostFenceMalloc(x)
|
||||
#define calloc(x,y) HeapCheckPostFenceCalloc(x*y)
|
||||
#define realloc(x,y) HeapCheckPostFenceRealloc(x,y)
|
||||
#define free(x) HeapCheckPostFenceFree(x)
|
||||
#endif
|
||||
|
||||
#endif /* __SWAPS_H__ */
|
||||
|
||||
#endif /* _DEBUG */
|
|
@ -1,51 +0,0 @@
|
|||
#include <iostream.h>
|
||||
|
||||
// Always include "swaps.h" LAST, after all other includes you make
|
||||
// (unless of course one of your includes invokes new/delete/malloc/etc)
|
||||
|
||||
#include "swaps.h"
|
||||
|
||||
// allocations deep in call stacks...f1() -> f2() -> f3()
|
||||
void f3()
|
||||
{
|
||||
char *p = new char[20];
|
||||
}
|
||||
|
||||
void f2()
|
||||
{
|
||||
f3();
|
||||
}
|
||||
|
||||
void f1()
|
||||
{
|
||||
f2();
|
||||
}
|
||||
|
||||
main()
|
||||
{
|
||||
char *p = new char[10];
|
||||
|
||||
// allocations deep in call stacks...
|
||||
// f1();
|
||||
|
||||
// Through malloc, too, not just new/delete...
|
||||
// char *q = (char *) malloc(200);
|
||||
|
||||
// Read/write access beyond bounds
|
||||
// char a = p[10];
|
||||
|
||||
// Access before bounds (globally define PRE_CHECK in project settings)
|
||||
// p[-1] = 0;
|
||||
|
||||
// Forgetting to delete
|
||||
// delete [] p;
|
||||
|
||||
// Reading from freed memory
|
||||
// char a = p[0];
|
||||
|
||||
// Deleting/freeing wrong pointer
|
||||
// free((char *)1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
const char *BOINC_RCSID_56bf366291 = "$Id$";
|
|
@ -1,33 +0,0 @@
|
|||
// boinc_setup_commit.cpp : Defines the entry point for the application.
|
||||
//
|
||||
|
||||
#include <windows.h>
|
||||
#include <string>
|
||||
|
||||
int APIENTRY WinMain(HINSTANCE hInstance,
|
||||
HINSTANCE hPrevInstance,
|
||||
LPTSTR lpCmdLine,
|
||||
int nCmdShow)
|
||||
{
|
||||
// execute the boinc as a new process and don't wait for it to finish.
|
||||
|
||||
STARTUPINFO si;
|
||||
PROCESS_INFORMATION pi;
|
||||
ZeroMemory( &si, sizeof(si) );
|
||||
si.cb = sizeof(si);
|
||||
ZeroMemory( &pi, sizeof(pi) );
|
||||
|
||||
std::string boincDir = lpCmdLine;
|
||||
std::string boincExePath = boincDir + "\\boinc_gui.exe";
|
||||
char commandLine[] = "boinc_gui.exe -min";
|
||||
|
||||
CreateProcess(boincExePath.c_str(), commandLine, NULL, NULL, FALSE, 0, NULL, boincDir.c_str(), &si, &pi);
|
||||
// Close process and thread handles.
|
||||
CloseHandle( pi.hProcess );
|
||||
CloseHandle( pi.hThread );
|
||||
|
||||
// Don't wait for process to exit! That's the whole point.
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *BOINC_RCSID_d2f0340771 = "$Id$";
|
|
@ -1,142 +0,0 @@
|
|||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="7.10"
|
||||
Name="boinc_setup_commit"
|
||||
ProjectGUID="{F0752A09-9799-4A77-AC26-8B6C239AB1F4}"
|
||||
Keyword="Win32Proj">
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"/>
|
||||
</Platforms>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="Debug"
|
||||
IntermediateDirectory="Debug"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
|
||||
MinimalRebuild="TRUE"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="5"
|
||||
UsePrecompiledHeader="3"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="TRUE"
|
||||
DebugInformationFormat="4"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
OutputFile="$(OutDir)/boinc_setup_commit.exe"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="TRUE"
|
||||
ProgramDatabaseFile="$(OutDir)/boinc_setup_commit.pdb"
|
||||
SubSystem="2"
|
||||
TargetMachine="1"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="Release"
|
||||
IntermediateDirectory="Release"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
|
||||
RuntimeLibrary="4"
|
||||
UsePrecompiledHeader="3"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="TRUE"
|
||||
DebugInformationFormat="3"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
OutputFile="$(OutDir)/boinc_setup_commit.exe"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="TRUE"
|
||||
SubSystem="2"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
|
||||
<File
|
||||
RelativePath=".\boinc_setup_commit.cpp">
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="0"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="0"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
|
||||
<File
|
||||
RelativePath=".\boinc_setup_commit.h">
|
||||
</File>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
Loading…
Reference in New Issue