
#include "devel_template.inc" title="Smart Memory Allocation"

<center>
<H1><FONT COLOR="#0000D8"><img src="smartall.gif" width=444 height=68 alt="SMARTALLOC"></FONT></H1>
<H3><FONT COLOR="#0000D8">Smart Memory Allocation With Orphaned Buffer Detection
</FONT></H3>
</center>
<hr>

<P>
Few things are as embarrassing as a program that leaks, yet few errors 
are so easy to commit or as difficult to track down in a large, 
complicated program as failure to release allocated memory. SMARTALLOC 
replaces the standard C library memory allocation functions with 
versions which keep track of buffer allocations and releases and report 
all orphaned buffers at the end of program execution. By including this 
package in your program during development and testing, you can 
identify code that loses buffers right when it's added and most easily 
fixed, rather than as part of a crisis debugging push when the problem 
is identified much later in the testing cycle (or even worse, when the 
code is in the hands of a customer). When program testing is complete, 
simply recompiling with different flags removes SMARTALLOC from your 
program, permitting it to run without speed or storage penalties.
<P>
In addition to detecting orphaned buffers, SMARTALLOC also helps to 
find other common problems in management of dynamic storage including 
storing before the start or beyond the end of an allocated buffer, 
referencing data through a pointer to a previously released buffer, 
attempting to release a buffer twice or releasing storage not obtained 
from the allocator, and assuming the initial contents of storage 
allocated by functions that do not guarantee a known value. 
SMARTALLOC's checking does not usually add a large amount of overhead 
to a program (except for programs which use <TT>realloc()</TT>
 extensively; see below). SMARTALLOC focuses on proper storage 
management rather than internal consistency of the heap as checked by 
the malloc_debug facility available on some systems. SMARTALLOC does 
not conflict with malloc_debug and both may be used together, if you 
wish. SMARTALLOC makes no assumptions regarding the internal structure 
of the heap and thus should be compatible with any C language 
implementation of the standard memory allocation functions.
<H3>
Installing SMARTALLOC</H3>
<P>
SMARTALLOC is provided as a Zipped archive, <A HREF="http://www.fourmilab.ch/smartall/smartall.zip">smartall.zip</A>; 
see the download instructions below.
<P>
To install SMARTALLOC in your program, simply add the statement:
<P>
<CODE>#include "smartall.h"</CODE>
<P>
to every C program file which calls any of the memory allocation 
functions (<TT>malloc</TT>, <TT>calloc</TT>, <TT>free</TT>, etc.). 
SMARTALLOC must be used for all memory allocation with a program, so 
it's best to add the #include of "smartall.h" to the omnibus 
include file for your entire program, if you have such a thing. Next, 
define the symbol SMARTALLOC in the compilation before the inclusion of 
smartall.h. I usually do this by having my Makefile add the "<TT>-DSMARTALLOC</TT>" 
option to the C compiler for non-production builds. You can define the 
symbol manually, if you prefer, by adding the statement:
<P>
<CODE>#define SMARTALLOC</CODE>
<P>
before the #include of "smartall.h".
<P>
At the point where your program is all done and ready to relinquish 
control to the operating system, add the call:
<P>
<tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sm_dump(</tt><EM>datadump</EM><tt>);</tt>
<P>
where <EM>datadump</EM> specifies whether the contents of orphaned 
buffers are to be dumped in addition printing to their size and place 
of allocation. The data are dumped only if <EM>datadump</EM> is 
nonzero, so most programs will normally use "<TT>sm_dump(0);</TT>". 
If a mysterious orphaned buffer appears that can't be identified from 
the information this prints about it, replace the statement with "<TT>sm_dump(1)</TT>;". 
Usually the dump of the buffer's data will furnish the additional clues 
you need to excavate and extirpate the elusive error that left the 
buffer allocated.
<P>
Finally, add the files "smartall.h" and 
"smartall.c" from this release to your source directory, make 
dependencies, and linker input. You needn't make inclusion of 
smartall.c in your link optional; if compiled with SMARTALLOC not 
defined it generates no code, so you may always include it knowing it 
will waste no storage in production builds. Now when you run your 
program, if it leaves any buffers around when it's done, each will be 
reported by <TT>sm_dump()</TT> on stderr as follows:
<PRE>
Orphaned buffer:     120 bytes allocated at line 50 of gutshot.c
</PRE>
<H3>
Squelching a SMARTALLOC</H3>
<P>
Usually, when you first install SMARTALLOC in an existing program 
you'll find it nattering about lots of orphaned buffers. Some of these 
turn out to be legitimate errors, but some are storage allocated during 
program initialisation that, while dynamically allocated, is logically 
static storage not intended to be released. Of course, you can get rid 
of the complaints about these buffers by adding code to release them, 
but by doing so you're adding unnecessary complexity and code size to 
your program just to silence the nattering of a SMARTALLOC, so an 
escape hatch is provided to eliminate the need to release these 
buffers.
<P>
Normally all storage allocated with the functions <TT>malloc()</TT>, <TT>calloc()</TT>, 
and <TT>realloc()</TT> is monitored by SMARTALLOC. If you make the 
function call:
<PRE>
        sm_static(1);
</PRE>
<P>
you declare that subsequent storage allocated by <TT>malloc()</TT>, <TT>calloc()</TT>, 
and <TT>realloc()</TT> should not be considered orphaned if found to be 
allocated when <TT>sm_dump()</TT> is called. I use a call on "<TT>sm_static(1);</TT>" 
before I allocate things like program configuration tables so I don't 
have to add code to release them at end of program time. After 
allocating unmonitored data this way, be sure to add a call to:
<PRE>
        sm_static(0);
</PRE>
<P>
to resume normal monitoring of buffer allocations. Buffers allocated 
while <TT>sm_static(1</TT>) is in effect are not checked for having 
been orphaned but all the other safeguards provided by SMARTALLOC 
remain in effect. You may release such buffers, if you like; but you 
don't have to.
<H3>
Living with Libraries</H3>
<P>
Some library functions for which source code is unavailable may 
gratuitously allocate and return buffers that contain their results, or 
require you to pass them buffers which they subsequently release. If 
you have source code for the library, by far the best approach is to 
simply install SMARTALLOC in it, particularly since this kind of 
ill-structured dynamic storage management is the source of so many 
storage leaks. Without source code, however, there's no option but to 
provide a way to bypass SMARTALLOC for the buffers the library 
allocates and/or releases with the standard system functions.
<P>
For each function <EM>xxx</EM> redefined by SMARTALLOC, a corresponding 
routine named "<TT>actually</TT><EM>xxx</EM>" is furnished 
which provides direct access to the underlying system function, as 
follows:
<P>
<blockquote>
<TABLE>
    <TR>
        <TH ALIGN="LEFT">Standard function </TH>
        <TH ALIGN="LEFT">Direct access function </TH>
    </TR>
    <TR>
        <TD><TT>malloc(</TT><I>size</I><TT>)</TT></TD>
        <TD><TT>actuallymalloc(</TT><I>size</I><TT>)</TT> </TD>
    </TR>
    <TR>
        <TD><TT>calloc(</TT><I>nelem</I><TT>,</TT> <I>elsize</I><TT>)</TT>
             </TD>
        <TD><TT>actuallycalloc(</TT><I>nelem</I>, <I>elsize</I><TT>)</TT>
             </TD>
    </TR>
    <TR>
        <TD><TT>realloc(</TT><I>ptr</I><TT>,</TT> <I>size</I><TT>)</TT> </TD>
        <TD><TT>actuallyrealloc(</TT><I>ptr</I>, <I>size</I><TT>)</TT> </TD>
    </TR>
    <TR>
        <TD><TT>free(</TT><I>ptr</I><TT>)</TT> </TD>
        <TD><TT>actuallyfree(</TT><I>ptr</I><TT>)</TT> </TD>
    </TR>
</TABLE>
</blockquote>
<P>
For example, suppose there exists a system library function named "<TT>getimage()</TT>" 
which reads a raster image file and returns the address of a buffer 
containing it. Since the library routine allocates the image directly 
with <TT>malloc()</TT>, you can't use SMARTALLOC's <TT>free()</TT>, as 
that call expects information placed in the buffer by SMARTALLOC's 
special version of <TT>malloc()</TT>, and hence would report an error. 
To release the buffer you should call <TT>actuallyfree()</TT>, as in 
this code fragment:
<PRE>
        struct image *ibuf = getimage("ratpack.img");
        display_on_screen(ibuf);
        actuallyfree(ibuf);
</PRE>
<P>
Conversely, suppose we are to call a library function, "<TT>putimage()</TT>", 
which writes an image buffer into a file and then releases the buffer 
with <TT>free()</TT>. Since the system <TT>free()</TT> is being called, 
we can't pass a buffer allocated by SMARTALLOC's allocation routines, 
as it contains special information that the system <TT>free()</TT>
 doesn't expect to be there. The following code uses <TT>actuallymalloc()</TT>
 to obtain the buffer passed to such a routine.
<PRE>
        struct image *obuf = 
           (struct image *) actuallymalloc(sizeof(struct image));
        dump_screen_to_image(obuf);
        putimage("scrdump.img", obuf);  /* putimage() releases obuf */
</PRE>
<P>
It's unlikely you'll need any of the "actually" calls except 
under very odd circumstances (in four products and three years, I've 
only needed them once), but they're there for the rare occasions that 
demand them. Don't use them to subvert the error checking of 
SMARTALLOC; if you want to disable orphaned buffer detection, use the <TT>sm_static(1)</TT>
 mechanism described above. That way you don't forfeit all the other 
advantages of SMARTALLOC as you do when using <TT>actuallymalloc()</TT>
 and <TT>actuallyfree()</TT>.
<H3>
SMARTALLOC Details</H3>
<P>
When you include "smartall.h" and define SMARTALLOC, the 
following standard system library functions are redefined with the 
\#define mechanism to call corresponding functions within smartall.c 
instead. (For details of the redefinitions, please refer to 
smartall.h.)
<PRE>
        void *malloc(size_t size)
        void *calloc(size_t nelem, size_t elsize)
        void *realloc(void *ptr, size_t size)
        void free(void *ptr)
        void cfree(void *ptr)
</PRE>
<P>
<TT>cfree()</TT> is a historical artifact identical to <TT>free()</TT>.
<P>
In addition to allocating storage in the same way as the standard 
library functions, the SMARTALLOC versions expand the buffers they 
allocate to include information that identifies where each buffer was 
allocated and to chain all allocated buffers together. When a buffer is 
released, it is removed from the allocated buffer chain. A call on <TT>sm_dump()</TT>
 is able, by scanning the chain of allocated buffers, to find all 
orphaned buffers. Buffers allocated while <TT>sm_static(1)</TT> is in 
effect are specially flagged so that, despite appearing on the 
allocated buffer chain, <TT>sm_dump()</TT> will not deem them orphans.
<P>
When a buffer is allocated by <TT>malloc()</TT> or expanded with <TT>realloc()</TT>, 
all bytes of newly allocated storage are set to the hexadecimal value 
0x55 (alternating one and zero bits). Note that for <TT>realloc()</TT>
 this applies only to the bytes added at the end of buffer; the 
original contents of the buffer are not modified. Initializing 
allocated storage to a distinctive nonzero pattern is intended to catch 
code that erroneously assumes newly allocated buffers are cleared to 
zero; in fact their contents are random. The <TT>calloc()</TT>
 function, defined as returning a buffer cleared to zero, continues to 
zero its buffers under SMARTALLOC.
<P>
Buffers obtained with the SMARTALLOC functions contain a special 
sentinel byte at the end of the user data area. This byte is set to a 
special key value based upon the buffer's memory address. When the 
buffer is released, the key is tested and if it has been overwritten an 
assertion in the <tt>free</tt> function will fail. This catches incorrect 
program code that stores beyond the storage allocated for the buffer. 
At <TT>free()</TT> time the queue links are also validated and an 
assertion failure will occur if the program has destroyed them by 
storing before the start of the allocated storage.
<P>
In addition, when a buffer is released with <TT>free()</TT>, its 
contents are immediately destroyed by overwriting them with the 
hexadecimal pattern 0xAA (alternating bits, the one's complement of the 
initial value pattern). This will usually trip up code that keeps a 
pointer to a buffer that's been freed and later attempts to reference 
data within the released buffer. Incredibly, this is <EM>legal</EM> in 
the standard Unix memory allocation package, which permits programs to 
free() buffers, then raise them from the grave with <TT>realloc()</TT>. 
Such program "logic" should be fixed, not accommodated, and 
SMARTALLOC brooks no such Lazarus buffer" nonsense.
<P>
Some C libraries allow a zero size argument in calls to <TT>malloc()</TT>. 
Since this is far more likely to indicate a program error than a 
defensible programming stratagem, SMARTALLOC disallows it with an 
assertion.
<P>
When the standard library <TT>realloc()</TT> function is called to 
expand a buffer, it attempts to expand the buffer in place if possible, 
moving it only if necessary. Because SMARTALLOC must place its own 
private storage in the buffer and also to aid in error detection, its 
version of <TT>realloc()</TT> always moves and copies the buffer except 
in the trivial case where the size of the buffer is not being changed. 
By forcing the buffer to move on every call and destroying the contents 
of the old buffer when it is released, SMARTALLOC traps programs which 
keep pointers into a buffer across a call on <TT>realloc()</TT> which 
may move it. This strategy may prove very costly to programs which make 
extensive use of <TT>realloc()</TT>. If this proves to be a problem, 
such programs may wish to use <TT>actuallymalloc()</TT>, <TT>actuallyrealloc()</TT>, 
and <TT>actuallyfree()</TT> for such frequently-adjusted buffers, 
trading error detection for performance. Although not specified in the 
System V Interface Definition, many C library implementations of <TT>realloc()</TT>
 permit an old buffer argument of NULL, causing <TT>realloc()</TT> to 
allocate a new buffer. The SMARTALLOC version permits this.
<H3>
When SMARTALLOC is Disabled</H3>
<P>
When SMARTALLOC is disabled by compiling a program with the symbol 
SMARTALLOC not defined, calls on the functions otherwise redefined by 
SMARTALLOC go directly to the system functions. In addition, 
compile-time definitions translate calls on the "<TT>actually</TT>...<TT>()</TT>" 
functions into the corresponding library calls; "<TT>actuallymalloc(100)</TT>", 
for example, compiles into "<TT>malloc(100)</TT>". The two 
special SMARTALLOC functions, <TT>sm_dump()</TT> and <TT>sm_static()</TT>, 
are defined to generate no code (hence the null statement). Finally, if 
SMARTALLOC is not defined, compilation of the file smartall.c generates 
no code or data at all, effectively removing it from the program even 
if named in the link instructions.
<P>
Thus, except for unusual circumstances, a program that works with 
SMARTALLOC defined for testing should require no changes when built 
without it for production release.
<H3>
The <CODE>alloc()</CODE> Function</H3>
<P>
Many programs I've worked on use very few direct calls to <TT>malloc()</TT>, 
using the identically declared <TT>alloc()</TT> function instead. Alloc 
detects out-of-memory conditions and aborts, removing the need for 
error checking on every call of <TT>malloc()</TT> (and the temptation 
to skip checking for out-of-memory).
<P>
As a convenience, SMARTALLOC supplies a compatible version of <TT>alloc()</TT>
 in the file alloc.c, with its definition in the file alloc.h. This 
version of <TT>alloc()</TT> is sensitive to the definition of 
SMARTALLOC and cooperates with SMARTALLOC's orphaned buffer detection. 
In addition, when SMARTALLOC is defined and <TT>alloc()</TT> detects an 
out of memory condition, it takes advantage of the SMARTALLOC 
diagnostic information to identify the file and line number of the call 
on <TT>alloc()</TT> that failed.
<H3>
Overlays and Underhandedness</H3>
<P>
String constants in the C language are considered to be static arrays 
of characters accessed through a pointer constant. The arrays are 
potentially writable even though their pointer is a constant. 
SMARTALLOC uses the compile-time definition <TT>__FILE__</TT> to obtain 
the name of the file in which a call on buffer allocation was 
performed. Rather than reserve space in a buffer to save this 
information, SMARTALLOC simply stores the pointer to the compiled-in 
text of the file name. This works fine as long as the program does not 
overlay its data among modules. If data are overlayed, the area of 
memory which contained the file name at the time it was saved in the 
buffer may contain something else entirely when <TT>sm_dump()</TT> gets 
around to using the pointer to edit the file name which allocated the 
buffer.
<P>
If you want to use SMARTALLOC in a program with overlayed data, you'll 
have to modify smartall.c to either copy the file name to a 
fixed-length field added to the <TT>abufhead</TT> structure, or else 
allocate storage with <TT>malloc()</TT>, copy the file name there, and 
set the <TT>abfname</TT> pointer to that buffer, then remember to 
release the buffer in <TT>sm_free</TT>. Either of these approaches are 
wasteful of storage and time, and should be considered only if there is 
no alternative. Since most initial debugging is done in non-overlayed 
environments, the restrictions on SMARTALLOC with data overlaying may 
never prove a problem. Note that conventional overlaying of code, by 
far the most common form of overlaying, poses no problems for 
SMARTALLOC; you need only be concerned if you're using exotic tools for 
data overlaying on MS-DOS or other address-space-challenged systems.
<P>
Since a C language "constant" string can actually be written 
into, most C compilers generate a unique copy of each string used in a 
module, even if the same constant string appears many times. In modules 
that contain many calls on allocation functions, this results in 
substantial wasted storage for the strings that identify the file name. 
If your compiler permits optimization of multiple occurrences of 
constant strings, enabling this mode will eliminate the overhead for 
these strings. Of course, it's up to you to make sure choosing this 
compiler mode won't wreak havoc on some other part of your program.
<H3>
Test and Demonstration Program</H3>
<P>
A test and demonstration program, smtest.c, is supplied with 
SMARTALLOC. You can build this program with the Makefile included. 
Please refer to the comments in smtest.c and the Makefile for 
information on this program. If you're attempting to use SMARTALLOC on 
a new machine or with a new compiler or operating system, it's a wise 
first step to check it out with smtest first.
<H3>
Invitation to the Hack</H3>
<P>
SMARTALLOC is not intended to be a panacea for storage management 
problems, nor is it universally applicable or effective; it's another 
weapon in the arsenal of the defensive professional programmer 
attempting to create reliable products. It represents the current state 
of evolution of expedient debug code which has been used in several 
commercial software products which have, collectively, sold more than 
third of a million copies in the retail market, and can be expected to 
continue to develop through time as it is applied to ever more 
demanding projects.
<P>
The version of SMARTALLOC here has been tested on a Sun SPARCStation, 
Silicon Graphics Indigo&#178;, and on MS-DOS using both Borland and 
Microsoft C. Moving from compiler to compiler requires the usual small 
changes to resolve disputes about prototyping of functions, whether the 
type returned by buffer allocation is <CODE>char&nbsp;*</CODE> or <CODE>void&nbsp;*</CODE>, 
and so forth, but following those changes it works in a variety of
environments. I hope you'll find SMARTALLOC as useful for 
your projects as I've found it in mine.

<h2><a href="http://www.fourmilab.ch/smartall/smartall.zip"><img src="http://www.fourmilab.ch/images/icons/file.gif" alt="" align=middle width=40 height=40></a> <a href="http://www.fourmilab.ch/smartall/smartall.zip">Download smartall.zip</a> (Zipped archive)</h2>

    SMARTALLOC is provided as <a href="http://www.fourmilab.ch/smartall/smartall.zip">smartall.zip</a>, a
    <a href="http://www.pkware.com/">Zipped</a> archive containing
    source code, documentation, and a
    <code>Makefile</code> to build the software under Unix.


<H3>
Copying</H3>
<BLOCKQUOTE>
SMARTALLOC is in the public domain. Permission to use, copy, modify, 
and distribute this software and its documentation for any purpose and 
without fee is hereby granted, without any conditions or restrictions. 
This software is provided "as is" without express or implied 
warranty.
</BLOCKQUOTE>

<HR>
<ADDRESS>
<A HREF="http://www.fourmilab.ch">by John Walker</A><BR>
October 30th, 1998 </ADDRESS>

<page_prev name="MD5 Algorithm" url="md5.html">
