mush_malloc() and memcheck

Submitted by raevnos on Fri, 2007-06-22 14:40

Penn includes a basic memory allocation debugger, enabled by setting mem_check to yes in mush.cnf and rebooting. However, to take advantage of this, you have to use special functions to allocate and free memory.

The memcheck system uses reference counting, incrementing the count for a particular tag that have been allocated and decrementing it when a tag is freed. You can see the current counts with @list allocations as an admin character (@stats/tables and God for pre-1.8.3p3p4 versions). Each line looks like:

TAG : COUNT.

A constantly increasing count where there shouldn't be one means you're not freeing memory after you're done. Attempts to free memory with a tag that has a 0 or negative count get logged in game/log/checkpt.log, along with where this was done in the source (The latter as of 1.8.3p4).

tags are just strings describing what's been allocated. More specific tags, for example "fun_align.string", make tracking down leaks easier than more generic tags like "string", but increase the size of the data structures that store reference counts.

API

To associate memory with a tag, use the following wrapper functions, prototyped in externs.h. All take a tag argument, which is a string describing what's being allocated or freed. The same tag must be used to free a chunk of memory as what used when it was allocated.

void* mush_malloc(size_t bytes, const char *tag)
Wrapper for malloc(), allocates a number of bytes and returns them or NULL.
void* mush_calloc(size_t count, size_t size, const char *tag)
Allocates an array of count elements of size bytes and returns a pointer to the first or NULL. The returned memory is filled with zero bytes. (Added in 1.8.3p3)
void* mush_realloc(void * restrict ptr, size_t size, const char * restrict tag)
Wrapper for realloc(): Allocates, resizes, or frees memory depending on the values of ptr and size. The tag and pointer cannot be the same string. (Added in 1.8.3p4)
char* mush_strdup(const char * restrict string, const char * restrict tag)
Returns a newly allocated copy of a C string (or NULL). The arguments cannot be the same string. Does not work with multibyte character strings.
void mush_free(void * restrict ptr, const char * restrict tag)
Frees memory. The arguments cannot be the same string.

Even if an allocation function returns NULL, it still increases the reference count of that tag.

If you have no control over allocation of some memory (Such as something returned by a foreign library), you can add a reference for it with void add_check(const char *tag) and decrement it with void del_check(const char *tag). Finally, void list_mem_check(dbref player) displays the current counts to a player and void log_mem_check(void) writes them to a log file.

See the Source documentation for more on the functions mentioned in the above paragraph.

Other options

Penn comes with an malloc implementation that includes optional memory debugging (CSRImalloc in debug mode, #define MALLOC_PACKAGE 2 in options.h. I've never used it.

(TODO: Links for the things mentioned below)

There are a variety of third-party tools for detecting memory leaks and other allocation-related problems, such as the MallocDebug program and library that come with the Mac OS X developer tools, the Boehm garbage collection library in leak-detection mode, and more.