MemCheckDeluxe, v1.2.2 Copyright 2002, 2003 Softpixel (http://softpixel.com) Chris Wright (cwright@softpixel.com) MemCheckDeluxe is an enhanced leak finder/memory profiler. It tracks all the memory allocated, and can report where it was created at the end of a program (memory that would have been leaked). It tracks the largest and smallest chunks allocated, the maximum memory used, and the highest number of allocations at any time. Some headway has been made to allow C++'s allocation operators new and delete to be tracked. ************* ** USAGE ** ************* To use it, #define _MCD_CHECK, include mcd.h, and add mcd.c to the list of source files to build in your project. then, call 'showMemStats()' at any time to see the currently outstanding allocations and usage stats. If you don't define _MCD_CHECK, it compiles away, improving performance. It is probably not a good idea to have some parts of a library use mcd, and not others. Pointers created in non-mcd parts won't be tracked and may confuse mcd, and stuff made in mcd, and freed elsewhere won't be properly cleaned up internally, leading to false leaks. When included, a warning is normally issued, informing the user that performance will be affected. If this gets annoying, define MCD_QUIET to make it go away. When including mcd.h, be sure to make it the last file included, as it redefines some macros. including things after it, especially system headers (stdlib.h, etc) can cause some nasty error messages and it will fail to compile anything. One can define MCD_VERBOSE to have each and every malloc, calloc, realloc, strdup, strndup, and free be written to the RealTime log, including the size, calling function, and line number. The RealTime log defaults to stderr, but can be set to any file you want with _MCD_RealTimeLog(FILE*fp). Just make sure the file is opened for writing/appending, and all verbosity will go there instead. Please note that if you want RealTime log output, you MUST define MCD_VERBOSE. With default settings, free(NULL) will simply return, providing you with an error message in the RealTime log if verbose was enabled. If you are working with a C library that acts differently when free(null) happens, define MCD_FREE_NULL, and it will generate the log message, and then perform the native free. Using this is probably seldom needed, and will probably lead to a crash when/if it happens, providing you with a nice coredump to analyze. Again, this only applies if your C library's free(null) does something other than simply return. There is a new flag, _MCD_GONE, that will remove all MCD code from the end product. It must be defined when compiling both mcd.c, and any other file that includes mcd.h. Note that defining _MCD_CHECK has no effect when _MCD_GONE is defined. The savings from this are about 15-20k (4-5k stripped). ***************** ** FUNCTIONS ** ***************** showMemStats() - prints the current memory statistic information to the MemStat log, if specified, or stdout if it isn't. _MCD_MemStatLog(FILE *f) - sets the MemStat log to f. f must be a file opened for writing or appending. _MCD_RealTimeLog(FILE *f) - sets the RealTime log to f. f must be a file opened for writing or appending. *************** ** HISTORY ** *************** Since version 1.1.0, an aggressive allocation system has been coded that modifies outgoing pointers. To the program, they are usable and completely normal, with two exceptions: you cannot free them without mcd, and you cannot realloc them without mcd. trying to will most likly cause a crash, because the unwrapped malloc won't get a pointer created by malloc, but an offset into one. The reason for this modification was to make free approximatly as fast as regular free, whereas older versions simply scanned the whole list looking for the pointer (which took a long time with lots of mallocs outstanding). Because MCD should work out of the box, I made FastFrees disabled by default in version 1.1.2 and later. To activate FastFrees (disabling free/realloc from outside mcd's scope), define MCD_FASTFREE when compiling mcd.c. To the rest of the code, there shouldn't be any changes necessary. Version 1.1.3 introduced a 'Tracking Bias,' which follows which end of the Chunk list the last few frees were from. Default number is 5, but this can be changed in mcd.c (Look for TRACK_LENGTH). Because programs tend to do malloc/free stuff in a stack like fashion (LIFO), it seemed logical to search the list from the bottom up instead of top down to speed up frees. However, there are some programs which perform malloc/free stuff in different orders (FIFO), and these programs would suffer. So I finally decided to have it dynamically recognize which is more likly by past trends, and search from either end based on that. Hopefully this will help performance considerably for both cases. And this allows programs to have parts that are both LIFO and FIFO, and still take very few hits if the trends hold long enough. Track Biasing only works when FASTFREE is disabled, as there'd be no point in having it when FASTFREE never really traverses the list. Timing the example program 'lifo' shows an 8x speedup using the tracking bias. This is a really simple, ideal case, but it does seem that such an improvement would help in other situations at least a little bit. Versions 1.1.4-1.1.4c were a set of bug fix releases, mostly dealing with accounting of string functions. 1.2.0 was a clean up release that fixed a bunch of small bugs, added a few usability enhancements, and extended the demos to match the core a bit more. The source was also cleaned to work on Win32 essentially out of the box. Log redirection was also started here. Version 1.2.1 cleaned up some of the left over (and newly created) bugs in 1.2.0. It also introduced Stephen Lee's patch for scanf, sscanf, and fscanf, as well as suport for getcwd extentions. ********************************* ** What's Tracked / What's Not ** ********************************* The following allocating functions are tracked and properly handled at present * new * new [] * delete * delete [] * malloc * calloc * realloc * strdup * strndup * asprintf * vasprintf * scanf * sscanf * fscanf * free * Note that not all platforms offer all functions. These ones aren't yet (this list may be incomplete) * memalign * posix_memalign * cfree * morecore * vscanf * vsscanf * vfscanf The following Statistics are also recorded * Total number of unfreed bytes * Peak memory usage * Biggest allocation * Smallest allocation * Total number of allocations * Total number of frees * Peak number of outstanding allocations These may be tracked in future releases, but are NOT tracked now * Allocation timestamps (timeofday and rdtsc where available) * Allocation life times * Number of buffers overflowed (approximate) * Double frees * Size/location map for visualization *************************** ** Interpreting The Data ** *************************** When showMemStats() is called, data representing the current state are printed out on the MemStat log. It looks something like this: Memory Stats: 15 bytes allocated in [main:example.c], line 11 [0804A410][id 0000000000000000] 64 bytes allocated in [main:example.c], line 14 [0804A458][id 0000000000000001] 64 bytes allocated in [main:example.c], line 15 [0804A4D0][id 0000000000000002] 256 bytes allocated in [main:example.c], line 16 [0804A548][id 0000000000000003] total unfreed bytes: 399 Peak memory usage: 435 Largest allocation: 256 Smallest allocation: 15 Total Allocations: 5 Total Frees: 1 Peak Allocations: 5 First, a list of all outstanding allocations is printed. The line starts off with the allocation's size, followed by the function, file, and line where it was created. At the end, the allocation ID is printed, allowing one to find it's chronological creation point if MCD was compiled with MCD_VERBOSE. each chunk gets a unique ID (unless you have a lot of them), so this should facilitate finding the right one the first time. After that, some overall stats are printed. In a completely leak-free program, Total Allocations should equal Total Frees, and total unfreed bytes should be zero. The MemStat log defaults to stdout, but can be set to any opened file you'd like by using _MCD_MemStatLog(FILE*fp);, where fp is a file opened for writing or appending. showMemStats() can be called as many times as desired. ***************** ** PLATFORMS ** ***************** This version has been tested with gcc under linux 2.2.18, 2.4.18, 2.4.19, and Msvc 6.0 under Windows 2000 and Windows 98. With windows 2000 and windows 98, it is not possible to obtain the function names, but line numbers and file names are still reported.