fix VFS bug preventing directories from being created:

- vfs_lookup: currentPath was of wrong type; simplified and fix create
logic
- archive_zip: fix: correctly handle filenames with /
- vfs: remove workaround for above bug
- io: temporarily disable block caching (works around problem with zip
file created by 7z)

add and use new wdbg_heap module (WIP)
remove mmgr

This was SVN commit r5571.
This commit is contained in:
janwas 2008-01-20 16:53:09 +00:00
parent 1700e90a15
commit aebf8cbf68
15 changed files with 197 additions and 1865 deletions

View File

@ -22,6 +22,10 @@
#include "lib/sysdep/cpu.h" // cpu_CAS
#include "lib/sysdep/sysdep.h"
#if OS_WIN
#include "lib/sysdep/win/wdbg_heap.h"
#endif
ERROR_ASSOCIATE(ERR::SYM_NO_STACK_FRAMES_FOUND, "No stack frames found", -1);
ERROR_ASSOCIATE(ERR::SYM_UNRETRIEVABLE_STATIC, "Value unretrievable (stored in external module)", -1);
@ -396,7 +400,13 @@ static ErrorReaction carry_out_ErrorReaction(ErrorReaction er, uint flags, u8* s
case ER_EXIT:
exit_requested = true; // see declaration
abort();
#if OS_WIN
// prevent (slow) heap reporting since we're exiting abnormally and
// thus probably leaking like a sieve.
wdbg_heap_Enable(false);
#endif
exit(EXIT_FAILURE);
}
return er;

View File

@ -15,7 +15,6 @@
// diagnosing and reporting program errors.
// - a symbol engine provides access to compiler-generated debug information and
// can also give a stack trace including local variables;
// - hooks into the memory allocator improve its leak detection;
// - our more powerful assert() replacement gives a stack trace so
// that the underlying problem becomes apparent;
// - the output routines make for platform-independent logging and
@ -35,17 +34,6 @@ extern void debug_break();
#endif
//-----------------------------------------------------------------------------
// debug memory allocator
//-----------------------------------------------------------------------------
/**
* check heap integrity.
* errors are reported by the CRT or via debug_display_error.
**/
LIB_API void debug_heap_check(void);
//-----------------------------------------------------------------------------
// output
//-----------------------------------------------------------------------------

View File

@ -71,11 +71,11 @@ public:
size_t Size() const
{
debug_assert(m_magic == lfh_magic);
const size_t fn_len = read_le16(&m_fn_len);
const size_t e_len = read_le16(&m_e_len);
size_t size = sizeof(LFH);
size += read_le16(&m_fn_len);
size += read_le16(&m_e_len);
// note: LFH doesn't have a comment field!
return sizeof(LFH) + fn_len + e_len;
return size;
}
private:
@ -386,17 +386,12 @@ public:
std::string zipPathname;
cdfh->GetPathname(zipPathname);
const size_t lastSlash = zipPathname.find_last_of('/');
if(lastSlash != zipPathname.length()-1) // we only want files
const size_t lastSlashOfs = zipPathname.find_last_of('/');
const size_t nameOfs = (lastSlashOfs == std::string::npos)? 0 : lastSlashOfs+1;
if(nameOfs != zipPathname.length()) // ignore paths ending in slash (i.e. representing a directory)
{
std::string name;
std::string* pname = &zipPathname; // assume zipPathname only has a name component
if(lastSlash != std::string::npos)
{
name = zipPathname.substr(lastSlash, zipPathname.length()-lastSlash);
pname = &name;
}
FileInfo fileInfo(*pname, cdfh->USize(), cdfh->MTime());
const std::string name = zipPathname.substr(nameOfs, zipPathname.length()-nameOfs);
FileInfo fileInfo(name, cdfh->USize(), cdfh->MTime());
shared_ptr<ArchiveFile_Zip> archiveFile(new ArchiveFile_Zip(m_file, cdfh->HeaderOffset(), cdfh->CSize(), cdfh->Checksum(), cdfh->Method()));
cb(zipPathname, fileInfo, archiveFile, cbData);
}

View File

@ -119,7 +119,7 @@ public:
{
m_file = file;
m_blockId = BlockId(file->Pathname(), alignedOfs);
if(file->Mode() == 'r' && s_blockCache.Retrieve(m_blockId, m_cachedBlock))
if(false && file->Mode() == 'r' && s_blockCache.Retrieve(m_blockId, m_cachedBlock))
{
stats_block_cache(CR_HIT);

View File

@ -70,7 +70,6 @@ public:
CHECK_ERR(vfs_Lookup(pathname, &m_rootDirectory, directory, 0, VFS_LOOKUP_ADD|VFS_LOOKUP_CREATE));
PRealDirectory realDirectory = directory->AssociatedDirectory();
if(!realDirectory) return ERR::FAIL; // WORKAROUND: vfs doesn't create real dirs by itself
const std::string& name = pathname.leaf();
RETURN_ERR(realDirectory->Store(name, fileContents, size));

View File

@ -139,18 +139,25 @@ LibError vfs_Lookup(const VfsPath& pathname, VfsDirectory* startDirectory, VfsDi
{
TIMER_ACCRUE(tc_lookup);
directory = startDirectory;
// extract and validate flags (ensure no unknown bits are set)
const bool addMissingDirectories = (flags & VFS_LOOKUP_ADD) != 0;
const bool createMissingDirectories = (flags & VFS_LOOKUP_CREATE) != 0;
debug_assert((flags & ~(VFS_LOOKUP_ADD|VFS_LOOKUP_CREATE)) == 0);
if(pfile)
*pfile = 0;
directory = startDirectory;
RETURN_ERR(Populate(directory));
if(pathname.empty()) // early out for root directory
return INFO::OK; // (prevents iterator error below)
// early-out for pathname == "" when mounting into VFS root
if(pathname.empty()) // (prevent iterator error in loop end condition)
return INFO::OK;
VfsPath currentPath; // only used if flags & VFS_LOOKUP_CREATE
VfsPath::iterator it;
Path currentPath; // (.. thus far; used when createMissingDirectories)
// for each directory component:
VfsPath::iterator it; // (used outside of loop to get filename)
for(it = pathname.begin(); it != --pathname.end(); ++it)
{
const std::string& subdirectoryName = *it;
@ -158,26 +165,29 @@ TIMER_ACCRUE(tc_lookup);
VfsDirectory* subdirectory = directory->GetSubdirectory(subdirectoryName);
if(!subdirectory)
{
if(!(flags & VFS_LOOKUP_ADD))
if(addMissingDirectories)
subdirectory = directory->AddSubdirectory(subdirectoryName);
else
return ERR::VFS_DIR_NOT_FOUND; // NOWARN
}
subdirectory = directory->AddSubdirectory(subdirectoryName);
if(flags & VFS_LOOKUP_CREATE)
if(createMissingDirectories)
{
if(subdirectory->AssociatedDirectory())
currentPath /= subdirectory->AssociatedDirectory()->GetPath().leaf();
else
{
currentPath /= subdirectoryName;
#if 0
(void)mkdir(currentPath.external_directory_string().c_str(), S_IRWXO|S_IRWXU|S_IRWXG);
PRealDirectory realDirectory(new RealDirectory(currentPath.string(), 0, 0));
subdirectory->Attach(realDirectory);
#endif
if(mkdir(currentPath.external_directory_string().c_str(), S_IRWXO|S_IRWXU|S_IRWXG) == 0)
{
PRealDirectory realDirectory(new RealDirectory(currentPath, 0, 0));
subdirectory->Attach(realDirectory);
}
}
}
RETURN_ERR(Populate(subdirectory));
directory = subdirectory;
RETURN_ERR(Populate(directory));
}
if(pfile)

File diff suppressed because it is too large Load Diff

View File

@ -1,296 +0,0 @@
#if 0
/**
* =========================================================================
* File : mmgr.h
* Project : 0 A.D.
* Description : memory manager and tracker.
* =========================================================================
*/
// license: GPL; see lib/license.txt
/*
purpose and history
-------------------
our goal is to expose any memory handling bugs in the application as
early as possible. various checks are performed upon each memory API call;
if all options are on, we can spot the following:
memory leaks, double-free, allocation over/underruns,
unused memory, and use-after-free.
this code started life as Paul Nettle's memory manager (available
at http:www.fluidstudios.com), and has been completely overhauled.
in particular, it is now thread-safe and modularized;
duplicated code has been eliminated.
instructions for integrating into your project
----------------------------------------------
1) #include this from all project source files [that will allocate memory].
doing so from the precompiled header is recommended, since the
compiler will make sure it has actually been included.
2) all system headers must be #include-d before this header, so that
we don't mess with any of their local operator new/delete.
3) if project source/headers also use local operator new/delete, #include
"nommgr.h" before that spot, and re-#include "mmgr.h" afterwards.
4) if using MFC:
- set linker option /FORCE - works around conflict between our global
operator new and that of MFC. be sure to check for other errors.
- remove any #define new DEBUG_NEW from all source files.
effects
-------
many bugs are caught and announced with no further changes
required, due to integrity checks inside the allocator.
at exit, three report files are generated: a listing of leaks,
various statistics (e.g. total unused memory), and the log.
this lists (depending on settings) all allocations, enter/exit
indications for our functions, and failure notifications.
digging deeper
--------------
when tracking down hard-to-find bugs, more stringent checks can be
activated via mmgr_set_option, or by changing the initial value of
options in mmgr.cpp. however, they slow down the app considerably
and need not always be enabled. see option declarations above.
you can also change padding_size in mmgr.cpp at compile-time to provide
more safety vs. overruns, at the cost of wasting lots of memory per
allocation (which must also be cleared). this is only done in
CONFIG_PARANOIA builds, because overruns seldom 'skip' padding.
finally, you can induce memory allocations to fail a certain percentage
of the time - this tests your application's error handling.
adjust the RANDOM_FAILURE #define in mmgr.cpp.
fixing your bugs
----------------
if this code crashes or fails an debug_assert, it is most likely due to a bug
in your application. consult the current Alloc for information;
search the log for its address to determine what operation failed,
and what piece of code owns the allocation.
if the cause isn't visible (i.e. the error is reported after the fact),
you can try activating the more stringent checks to catch the problem
earlier. you may also call the validation routines at checkpoints
in your code to narrow the cause down. if all else fails, break on
the allocation number to see what's happening.
good luck!
*/
//
// memory headers
//
// these are all system headers that contain "new", "malloc" etc.; they must
// come before the memory tracker headers to avoid conflicts with their
// macros. therefore, they are always included, even if !CONFIG_PCH.
#if OS_WIN
# include <malloc.h>
# include <xdebug>
# include <xtree>
#endif
#include <new>
#include <memory>
#include <locale> // operator new
#include <valarray> // free() member function
// VC debug memory allocator / leak detector
// notes:
// - PCH is required because it makes sure system headers are included
// before redefining new (otherwise, tons of errors result);
// - disabled on ICC9 because the ICC 9.0.006 beta appears to generate
// incorrect code when we redefine new.
// TODO: remove when no longer necessary
#if MSC_VERSION && \
(!defined(NDEBUG) || defined(TESTING)) && \
HAVE_PCH && \
ICC_VERSION != 900
# define HAVE_VC_DEBUG_ALLOC 1
#else
# define HAVE_VC_DEBUG_ALLOC 0
#endif
#ifndef INCLUDED_MMGR
#define INCLUDED_MMGR
namespace ERR
{
const LibError MEM_ALLOC_NOT_FOUND = -100200;
const LibError MEM_OVERWRITTEN = -100201;
}
// provide for completely disabling the memory manager
// (e.g. when using other debug packages)
//
// note: this must go around the include-guarded part (constants+externs)
// as well as the macros. we don't want to mess up compiler include-guard
// optimizations, so duplicate this #if.
#if CONFIG_USE_MMGR
//
// optional additional checks, enabled via mmgr_set_options.
// these slow down the application; see 'digging deeper' in documentation.
//
// log all allocation/deallocation operations undertaken.
const uint MMGR_LOG_ALL = 0x001;
// validate all allocations on every memory API call. slow!
const uint MMGR_VALIDATE_ALL = 0x002;
// fill the user-visible part of each allocation with a certain pattern
// on alloc and free. this is required for unused memory tracking.
const uint MMGR_FILL = 0x004;
// log all enter/exit into our API. if there's an
// unmatched pair in the log, we know where a crash occurred.
const uint MMGR_TRACE = 0x008;
// use debug information to resolve owner address to file/line/function.
// note: passing owner information to global operator delete via macro
// isn't reliable, so a stack backtrace (list of function addresses) is all
// we have there. this costs ~500us per unique call site on Windows.
const uint MMGR_RESOLVE_OWNER = 0x010;
// force each log line to be written directly to disk. slow!
// use only when the application is crashing, to make sure all
// available information is written out.
const uint MMGR_FLUSH_LOG = 0x020;
// an alias that includes all of the above. (more convenient)
const uint MMGR_ALL = 0xfff;
// return the current options unchanged.
const uint MMGR_QUERY = ~0;
extern uint mmgr_set_options(uint);
// break when a certain allocation is created/reallocated/freed:
extern void mmgr_break_on_alloc(uint count);
extern void mmgr_break_on_realloc(const void*);
extern void mmgr_break_on_free(const void*);
// "proactive" validation: (see 'digging deeper')
extern bool mmgr_is_valid_ptr(const void*);
extern bool mmgr_are_all_valid(void);
// write a report file
extern void mmgr_write_report(void);
extern void mmgr_write_leak_report(void);
//
// our wrappers for C++ memory handling functions
//
// note that all line numbers are int, for compatibility with any external
// overloaded operator new (in case someone forget to include "mmgr.h").
extern void* mmgr_malloc_dbg (size_t size, const char* file, int line, const char* func);
extern void* mmgr_calloc_dbg (size_t num, size_t size, const char* file, int line, const char* func);
extern void* mmgr_realloc_dbg(void* p, size_t size, const char* file, int line, const char* func);
extern void mmgr_free_dbg (void* p, const char* file, int line, const char* func);
extern char* mmgr_strdup_dbg(const char*, const char* file, int line, const char* func);
extern wchar_t* mmgr_wcsdup_dbg(const wchar_t*, const char* file, int line, const char* func);
extern char* mmgr_getcwd_dbg(char*, size_t, const char* file, int line, const char* func);
// .. global operator new (to catch allocs from STL/external libs)
extern void* operator new (size_t size) throw(std::bad_alloc);
extern void* operator new[](size_t size) throw(std::bad_alloc);
// .. override commonly used global operator new overload (done e.g. by MFC),
// in case someone hasn't included this file
extern void* operator new (size_t size, const char* file, int line);
extern void* operator new[](size_t size, const char* file, int line);
// .. called by our global operator new hook macro
extern void* operator new (size_t size, const char* file, int line, const char* func);
extern void* operator new[](size_t size, const char* file, int line, const char* func);
// .. global operator delete
extern void operator delete (void* p) throw();
extern void operator delete[](void* p) throw();
// .. corresponding delete for first overloaded new,
// only called if exception raised during ctor
extern void operator delete (void* p, const char* file, int line) throw();
extern void operator delete[](void* p, const char* file, int line) throw();
// .. corresponding delete for our overloaded new,
// only called if exception raised during ctor
extern void operator delete (void* p, const char* file, int line, const char* func) throw();
extern void operator delete[](void* p, const char* file, int line, const char* func) throw();
#endif // #if CONFIG_USE_MMGR
#endif // #ifdef INCLUDED_MMGR
//
// hook macros
//
#include "nommgr.h"
#if CONFIG_USE_MMGR || HAVE_VC_DEBUG_ALLOC
// notify user code that they must #include "nommgr.h" in places
// where our macro would cause breakage (e.g. placement new)
# define REDEFINED_NEW
#endif
// mmgr version:
// (to simplify code that may either use mmgr or the VC debug heap,
// we support enabling/disabling both in this header)
#if CONFIG_USE_MMGR
// get rid of __FUNCTION__ unless we know the compiler supports it.
// (note: don't define if built-in - compiler will raise a warning)
#if !MSC_VERSION && !GCC_VERSION
#define __FUNCTION__ 0
#endif
#define new new(__FILE__, __LINE__, __FUNCTION__)
// hooking delete and setting global owner variables/pushing them on a stack
// isn't thread-safe and can be fooled with destructor chains.
// we instead rely on the call stack (works with VC and GCC)
#define malloc(size) mmgr_malloc_dbg (size, __FILE__,__LINE__,__FUNCTION__)
#define calloc(num, size) mmgr_calloc_dbg (num,size,__FILE__,__LINE__,__FUNCTION__)
#define realloc(p,size) mmgr_realloc_dbg(p,size, __FILE__,__LINE__,__FUNCTION__)
#define free(p) mmgr_free_dbg (p, __FILE__,__LINE__,__FUNCTION__)
#define strdup(p) mmgr_strdup_dbg(p, __FILE__,__LINE__,__FUNCTION__)
#define wcsdup(p) mmgr_wcsdup_dbg(p, __FILE__,__LINE__,__FUNCTION__)
#define getcwd(p,size) mmgr_getcwd_dbg(p, size, __FILE__,__LINE__,__FUNCTION__)
#elif HAVE_VC_DEBUG_ALLOC
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
// crtdbg.h didn't define "new" (probably for compatibility); do so now.
#define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
#endif // #if CONFIG_USE_MMGR
#endif

View File

@ -1,18 +0,0 @@
// remove all of mmgr.h's memory allocation "hooks" -
// but only if we actually defined them!
#if CONFIG_USE_MMGR || HAVE_VC_DEBUG_ALLOC
# undef new
# undef delete
# undef malloc
# undef calloc
# undef realloc
# undef free
# undef strdup
# undef wcsdup
# undef getcwd
#endif
// sanity check
#ifdef new
#error "nommgr.h - something is wrong, new is still defined"
#endif

View File

@ -174,11 +174,6 @@ static i32 last_in_use = -1; // don't search unused entries
// also used by h_data, and alloc_idx to find a free entry.
static HDATA* h_data_from_idx(const i32 idx)
{
// makes things *crawl*!
#if CONFIG_PARANOIA
debug_heap_check();
#endif
// don't compare against last_in_use - this is called before allocating
// new entries, and to check if the next (but possibly not yet valid)
// entry is free. tag check protects against using unallocated entries.

View File

@ -14,64 +14,7 @@
#include "lib/bits.h"
#include "win.h"
#include "wutil.h"
#include "winit.h"
WINIT_REGISTER_CRITICAL_INIT(wdbg_Init);
static NT_TIB* get_tib()
{
#if ARCH_IA32
NT_TIB* tib;
// ICC 10 doesn't support the NT_TIB.Self syntax, so we have to use
// a constant (asm code isn't 64-bit safe anyway).
__asm
{
mov eax, fs:[NT_TIB.Self]
mov [tib], eax
}
return tib;
#endif
}
//-----------------------------------------------------------------------------
// debug heap
//-----------------------------------------------------------------------------
static void debug_heap_init()
{
uint flags = 0;
flags |= _CRTDBG_ALLOC_MEM_DF; // enable checks at deallocation time
flags |= _CRTDBG_LEAK_CHECK_DF; // report leaks at exit
#if CONFIG_PARANOIA
flags |= _CRTDBG_CHECK_ALWAYS_DF; // check during every heap operation (slow!)
flags |= _CRTDBG_DELAY_FREE_MEM_DF; // blocks cannot be reused
#endif
_CrtSetDbgFlag(flags);
}
void debug_heap_check()
{
int ret;
__try
{
// NB: this is a no-op if !_CRTDBG_ALLOC_MEM_DF.
// we could call _heapchk but that would catch fewer errors.
ret = _CrtCheckMemory();
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
ret = _HEAPBADNODE;
}
if(ret != _HEAPOK)
DEBUG_DISPLAY_ERROR(L"debug_heap_check: heap is corrupt");
}
//-----------------------------------------------------------------------------
// return 1 if the pointer appears to be totally bogus, otherwise 0.
// this check is not authoritative (the pointer may be "valid" but incorrect)
@ -112,6 +55,21 @@ bool debug_is_code_ptr(void* p)
}
static NT_TIB* get_tib()
{
#if ARCH_IA32
NT_TIB* tib;
// ICC 10 doesn't support the NT_TIB.Self syntax, so we have to use
// a constant (asm code isn't 64-bit safe anyway).
__asm
{
mov eax, fs:[NT_TIB.Self]
mov [tib], eax
}
return tib;
#endif
}
bool debug_is_stack_ptr(void* p)
{
uintptr_t addr = (uintptr_t)p;
@ -167,10 +125,3 @@ void debug_set_thread_name(const char* name)
debug_assert(0); // thread name hack doesn't work under this debugger
}
}
static LibError wdbg_Init()
{
debug_heap_init();
return INFO::OK;
}

View File

@ -0,0 +1,94 @@
#include "precompiled.h"
#include "wdbg_heap.h"
#include <crtdbg.h>
#include <excpt.h>
#include "winit.h"
WINIT_REGISTER_CRITICAL_INIT(wdbg_heap_Init);
// CAUTION: called from critical init
void wdbg_heap_Enable(bool enable)
{
uint flags = 0;
if(enable)
{
flags |= _CRTDBG_ALLOC_MEM_DF; // enable checks at deallocation time
flags |= _CRTDBG_LEAK_CHECK_DF; // report leaks at exit
#if CONFIG_PARANOIA
flags |= _CRTDBG_CHECK_ALWAYS_DF; // check during every heap operation (slow!)
flags |= _CRTDBG_DELAY_FREE_MEM_DF; // blocks cannot be reused
#endif
}
_CrtSetDbgFlag(flags);
// Send output to stdout as well as the debug window, so it works during
// the normal build process as well as when debugging the test .exe
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);
}
void wdbg_heap_Validate()
{
int ret;
__try
{
// NB: this is a no-op if !_CRTDBG_ALLOC_MEM_DF.
// we could call _heapchk but that would catch fewer errors.
ret = _CrtCheckMemory();
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
ret = _HEAPBADNODE;
}
if(ret != _HEAPOK)
DEBUG_DISPLAY_ERROR(L"Heap is corrupted!");
}
//-----------------------------------------------------------------------------
static int __cdecl ReportHook(int reportType, char* message, int* shouldTriggerBreakpoint)
{
if(message[0] == '{')
{
debug_printf("leak\n");
}
*shouldTriggerBreakpoint = 0;
return 1; // CRT is to display the message as normal
}
static _CRT_ALLOC_HOOK previousAllocHook;
/**
* @param userData is only valid (nonzero) for allocType == _HOOK_FREE because
* we are called BEFORE the actual heap operation.
**/
static int __cdecl AllocHook(int allocType, void* userData, size_t size, int blockType, long requestNumber, const unsigned char* file, int line)
{
if(previousAllocHook)
return previousAllocHook(allocType, userData, size, blockType, requestNumber, file, line);
return 1; // continue as if the hook had never been called
}
// NB: called from critical init => can't use debug.h services
static void InstallHooks()
{
int ret = _CrtSetReportHook2(_CRT_RPTHOOK_INSTALL, ReportHook);
if(ret == -1)
abort();
previousAllocHook = _CrtSetAllocHook(AllocHook);
}
static LibError wdbg_heap_Init()
{
InstallHooks();
wdbg_heap_Enable(true);
return INFO::OK;
}

View File

@ -0,0 +1,33 @@
/**
* =========================================================================
* File : wdbg_heap.h
* Project : 0 A.D.
* Description : improved debug heap using MS CRT
* =========================================================================
*/
// license: GPL; see lib/license.txt
#ifndef INCLUDED_WDBG_HEAP
#define INCLUDED_WDBG_HEAP
// this module provides a more convenient interface to the MS CRT's
// debug heap checks. it also hooks into allocations to record the
// caller/owner information without requiring macros (which break code
// using placement new or member functions called free).
/**
* enable or disable manual and automatic heap validity checking.
* (enabled by default during critical_init.)
**/
LIB_API void wdbg_heap_Enable(bool);
/**
* check heap integrity.
* errors are reported by the CRT or via debug_display_error.
* no effect if called between wdbg_heap_Enable(false) and the next
* wdbg_heap_Enable(true).
**/
LIB_API void wdbg_heap_Validate(void);
#endif // #ifndef INCLUDED_WDBG_HEAP

View File

@ -373,7 +373,7 @@ void CProfileNode::Frame()
}
// TODO: these should probably only count allocations that occur in the thread being profiled
#if HAVE_VC_DEBUG_ALLOC
#if MSC_VERSION
static intptr_t memory_alloc_count = 0;
static int (*old_alloc_hook) (int, void*, size_t, int, long, const unsigned char*, int);
static int alloc_hook(int allocType, void* userData, size_t size, int blockType,

View File

@ -9,6 +9,10 @@
#include <cxxtest/GlobalFixture.h>
#if OS_WIN
#include "lib/sysdep/win/wdbg_heap.h"
#endif
class LeakReporter : public CxxTest::GlobalFixture
{
virtual bool tearDownWorld()
@ -16,19 +20,9 @@ class LeakReporter : public CxxTest::GlobalFixture
// Enable leak reporting on exit.
// (This is done in tearDownWorld so that it doesn't report 'leaks'
// if the program is aborted before finishing cleanly.)
#if HAVE_VC_DEBUG_ALLOC
int flags = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
flags |= _CRTDBG_LEAK_CHECK_DF; // check for memory leaks
flags |= _CRTDBG_ALLOC_MEM_DF; // also check allocs using the non-debug version of new
_CrtSetDbgFlag(flags);
// Send output to stdout as well as the debug window, so it works during
// the normal build process as well as when debugging the test .exe
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);
#if OS_WIN
wdbg_heap_Enable(true);
#endif
return true;
}