typed_mem
— heap
memory accounting system
PDEL Library (libpdel, -lpdel)
#include
<sys/types.h>
#include <stdio.h>
#include <stdarg.h>
#include
<pdel/structs/structs.h>
#include
<pdel/structs/type/array.h>
#include
<pdel/util/typed_mem.h>
void *
MALLOC
(const
char *mtype, size_t
size);
void *
CALLOC
(const
char *mtype, size_t
number, size_t
size);
void *
REALLOC
(const
char *mtype, void
*mem, size_t
size);
void *
REALLOCF
(const
char *mtype, void
*mem, size_t
size);
void
FREE
(const
char *mtype, void
*mem);
char *
STRDUP
(const
char *mtype, const char
*str);
int
ASPRINTF
(const
char *mtype, char
**ret, const char
*format, ...);
int
VASPRINTF
(const
char *mtype, char
**ret, const char
*format, va_list
ap);
int
typed_mem_enable
(void);
char *
typed_mem_type
(const
void *mem, char
*typebuf);
int
typed_mem_usage
(struct
typed_mem_stats *stats);
void
typed_mem_dump
(FILE
*fp);
extern const struct structs_type
typed_mem_stats_type;
The typed_mem
library provides accounting
and sanity checking for heap-allocated memory, configurable at run time.
If you're reading this man page because you need to pass a
variable named mtype to a function where a
“typed_mem(3) memory type” is required, but you don't want to
use or deal with typed memory in any way, then just pass
NULL
for mtype and stop
reading here. Otherwise, read on...
In this system, the user code uses the
MALLOC
(),
CALLOC
(),
REALLOC
(), REALLOCF
(),
FREE
(),
STRDUP
(),
ASPRINTF
(),
and
VASPRINTF
()
macros as replacements for their lowercase standard C library equivalents.
These macros take an additional first argument, which is the
memory
type for the block of memory. A memory type is simply an ASCII
string (of which only the first TYPED_MEM_TYPELEN -
1
characters are significant) containing a short, human-readable
description of what the memory is being used for. Note it is the contents of
the string, not the string pointer itself, which defines the type.
Once typed memory is enabled (see below), any memory
allocated with a memory type must be reallocated and/or freed with that same
type, otherwise the library will immediately abort with an assertion
failure. Similarly, invoking
REALLOC
(),
REALLOCF
()
or FREE
() with a pointer that was not returned by
one of the allocation macros will also cause an abort. In addition,
FREE
() never modifies the value of
errno.
To accomodate code that is not participating in the
typed memory system, a NULL
type may always be used
to indicate a block that should not be accounted for. That is, the
NULL
memory type just falls through to the existing
malloc(3),
free(3),
etc. For example,
scandir(3)
returns a heap-allocated array namelist which the
caller must free. Instead of calling
free
(namelist)
the caller may call
FREE
(NULL,
namelist). Calling FREE
() in
this case with any type other than NULL
would result
in an assertion failure. Similarly, memory allocated with
NULL
memory type may be freed via the normal
free(3).
Memory allocated by the
typed_mem
macros is bracketed by guard bytes before
and after the returned region. The
REALLOC
(),
REALLOCF
()
and FREE
() routines detect if the program has
modified these bytes, and they generate an assertion failure if so.
If a source file consistently uses the typed memory macros for all
heap memory operations, then it may define
TYPED_MEM_UNDEFINE_ORIGINALS
before including
<pdel/util/typed_mem.h>
. This will cause the
lowercase names to be redefined in such a way that their use will prevent
the source file from compiling. This helps avoid inadvertently mixing the
libc routines with typed memory routines.
Participation in the typed memory system is
optional and configurable at run time. To enable typed memory accounting,
typed_mem_enable
()
must be called once at program start before any heap allocations are
performed. This function returns zero if successful, or else -1 with
errno set to EALREADY
if a
typed memory allocation has already been performed.
If
typed_mem_enable
()
is never called, then all of the above macros ignore their
type argument and simply fall through to the
underlying libc routines, therefore having no effect. The program will
behave exactly as if the original functions had been used, except that there
is one function call of overhead for each macro.
typed_mem_usage
()
may be called to get the current statistics on memory types and usage. An
array of statistics structures is returned, one for each type, containing
the number of blocks and total bytes allocated under that type:
/* Statistics for a single memory type */
struct typed_mem_typestats {
char type[TYPED_MEM_TYPELEN]; /* type string + '\0' */
u_int allocs; /* # blocks alloc'd */
u_int bytes; /* # bytes alloc'd */
};
/* Variable length array of 'struct typed_mem_typestats' */
DEFINE_STRUCTS_ARRAY(typed_mem_stats, struct typed_mem_typestats);
The array is sorted lexicographically by type name. The array
itself must be eventually freed by the caller, by invoking:
structs_free(&typed_mem_stats_type, NULL, stats);
typed_mem_usage
()
returns zero if successful, or else -1 and sets errno
if there was an error; in particular, ENXIO
if typed
memory is not enabled.
A
structs(3)
type typed_mem_stats_type describing a
struct typed_mem_stats
is pre-defined.
typed_mem_type
()
retrieves the type for the memory block pointed to by
mem and writes it (including terminating '\0') into
the buffer pointed to by typebuf, which must have size
at least TYPED_MEM_TYPELEN
. If successful,
typed_mem_type
() returns
typebuf; otherwise
typed_mem_type
() returns
NULL
. This will happen if
typed_mem_enable
() has not been called, if
mem was allocated with type
NULL
, or if mem was never
returned by any of these allocation routines.
typed_mem_dump
()
prints out the current statistics on memory types and usage to the supplied
output stream.
The typed_mem
routines may safely be
called from multiple threads simultaneously.
The PDEL library was developed at Packet Design, LLC.
http://www.packetdesign.com/
Archie Cobbs
⟨archie@freebsd.org⟩