1
0
forked from 0ad/0ad

memory tracker work-in-progress. detects memory leaks, overruns, and all sorts of goodies.

This was SVN commit r1784.
This commit is contained in:
janwas 2005-01-23 18:19:28 +00:00
parent e4bcd210d3
commit cca00f9555
3 changed files with 1604 additions and 0 deletions

1387
source/lib/mmgr.cpp Normal file

File diff suppressed because it is too large Load Diff

209
source/lib/mmgr.h Normal file
View File

@ -0,0 +1,209 @@
// memory manager and tracker
//
// Copyright (c) 2005 Jan Wassenberg
//
// 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.
//
// Contact info:
// Jan.Wassenberg@stud.uni-karlsruhe.de
// http://www.stud.uni-karlsruhe.de/~urkt/
#ifndef MMGR_H__
#define MMGR_H__
#include "types.h"
// purpose and history
// -------------------
// our goal is to expose any memory handling bugs in the
// application as early as possible, by triggering
// breakpoints when a problem is detected.
// 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].
// 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 below.
//
// 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
// 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 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!
//
// optional additional checks, enabled via mmgr_set_options.
// these slow down the application; see 'digging deeper' above.
//
// log all allocation/deallocation operations undertaken.
const uint MMGR_LOG_ALL = 0x01;
// validate all allocations on every call to the allocator (slow!)
const uint MMGR_VALIDATE_ALL = 0x02;
// 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 = 0x04;
// log all enter/exit into our main functions. if there's an
// unmatched pair in the log, we know where a crash occurred.
const uint MMGR_TRACE = 0x08;
// when calling global operator delete, where we can't pass owner
// information via macro, find out who called us via stack trace
// and resolve the symbol via debug information.
// more informative, but adds 500µs to every call.
const uint MMGR_RESOLVE_OWNER = 0x10;
const uint MMGR_ALL = MMGR_LOG_ALL|MMGR_VALIDATE_ALL|MMGR_FILL|MMGR_TRACE|MMGR_RESOLVE_OWNER;
// 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' above)
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 external
// overloaded operator new.
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);
// .. global operator new (to catch allocs from STL/external libs)
extern void* operator new (size_t size);
extern void* operator new[](size_t size);
// .. 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 // #ifdef MMGR_H__
//
// hook macros
//
#include "nommgr.h"
// get rid of __FUNCTION__ unless we know the compiler supports it.
// (note: don't define if built-in - compiler will raise a warning)
#if !defined(_MSC_VER) && !defined(__GNUC__)
#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__)
// avoid macro replacement of new for local operator new
#define operator_new operator n##ew

8
source/lib/nommgr.h Normal file
View File

@ -0,0 +1,8 @@
// remove all memory allocation "hooks"
#undef new
#undef delete
#undef malloc
#undef calloc
#undef realloc
#undef free