Sophie

Sophie

distrib > Fedora > 16 > i386 > by-pkgid > df754e4e6f7f5fc8ab9d6ed8559f3e3d > files > 89

bacula-docs-5.0.3-19.fc16.noarch.rpm

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">

<!--Converted with LaTeX2HTML 2008 (1.71)
original version by:  Nikos Drakos, CBLU, University of Leeds
* revised and updated by:  Marcus Hennecke, Ross Moore, Herb Swan
* with significant contributions from:
  Jens Lippmann, Marek Rouchal, Martin Wilck and others -->
<HTML>
<HEAD>
<TITLE>Smart Memory Allocation</TITLE>
<META NAME="description" CONTENT="Smart Memory Allocation">
<META NAME="keywords" CONTENT="developers">
<META NAME="resource-type" CONTENT="document">
<META NAME="distribution" CONTENT="global">

<META NAME="Generator" CONTENT="LaTeX2HTML v2008">
<META HTTP-EQUIV="Content-Style-Type" CONTENT="text/css">

<LINK REL="STYLESHEET" HREF="developers.css">

<LINK REL="next" HREF="GNU_Free_Documentation_Lice.html">
<LINK REL="previous" HREF="TCP_IP_Network_Protocol.html">
<LINK REL="up" HREF="Developer_s_Guide.html">
<LINK REL="next" HREF="http_www_fourmilab_ch_smart.html">
</HEAD>

<BODY >
<!--Navigation Panel-->
<A NAME="tex2html1809"
  HREF="http_www_fourmilab_ch_smart.html">
<IMG WIDTH="37" HEIGHT="24" ALIGN="BOTTOM" BORDER="0" ALT="next" SRC="next.png"></A> 
<A NAME="tex2html1803"
  HREF="Developer_s_Guide.html">
<IMG WIDTH="26" HEIGHT="24" ALIGN="BOTTOM" BORDER="0" ALT="up" SRC="up.png"></A> 
<A NAME="tex2html1797"
  HREF="Higher_Level_Conventions.html">
<IMG WIDTH="63" HEIGHT="24" ALIGN="BOTTOM" BORDER="0" ALT="previous" SRC="prev.png"></A> 
<A NAME="tex2html1805"
  HREF="Contents.html">
<IMG WIDTH="65" HEIGHT="24" ALIGN="BOTTOM" BORDER="0" ALT="contents" SRC="contents.png"></A> 
<A NAME="tex2html1807"
  HREF="GNU_Free_Documentation_Lice.html">
<IMG WIDTH="43" HEIGHT="24" ALIGN="BOTTOM" BORDER="0" ALT="index" SRC="index.png"></A> 
<BR>
<B> Next:</B> <A NAME="tex2html1810"
  HREF="http_www_fourmilab_ch_smart.html">http://www.fourmilab.ch/smartall/smartall.zip Download smartall.ziphttp://www.fourmilab.ch/smartall/smartall.zip (Zipped</A>
<B> Up:</B> <A NAME="tex2html1804"
  HREF="Developer_s_Guide.html">Developer's Guide</A>
<B> Previous:</B> <A NAME="tex2html1798"
  HREF="Higher_Level_Conventions.html">Higher Level Conventions</A>
 &nbsp; <B>  <A NAME="tex2html1806"
  HREF="Contents.html">Contents</A></B> 
 &nbsp; <B>  <A NAME="tex2html1808"
  HREF="GNU_Free_Documentation_Lice.html">Index</A></B> 
<BR>
<BR>
<!--End of Navigation Panel-->

<H1><A NAME="SECTION001900000000000000000"></A>
<A NAME="_ChapterStart4"></A><A NAME="6425"></A>
<A NAME="6426"></A>
<BR>
Smart Memory Allocation
</H1>

<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. 

<P>

<H2><A NAME="SECTION001901000000000000000"></A>
<A NAME="6432"></A>
<A NAME="6433"></A>
<BR>
Installing SMARTALLOC
</H2>

<P>
SMARTALLOC is provided as a Zipped archive, 
smartall.ziphttp://www.fourmilab.ch/smartall/smartall.zip; see the
download instructions below. 

<P>
To install SMARTALLOC in your program, simply add the statement: 

<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 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>
<TT>#define SMARTALLOC</TT> 

<P>
At the point where your program is all done and ready to relinquish control to
the operating system, add the call: 

<P>
<TT>        sm_dump(</TT><I>datadump</I><TT>);</TT> 

<P>
where <I>datadump</I> 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 <I>datadump</I> 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: 

<P>
<PRE>
Orphaned buffer:     120 bytes allocated at line 50 of gutshot.c
</PRE>
<P>

<H2><A NAME="SECTION001902000000000000000"></A>
<A NAME="6455"></A>
<A NAME="6456"></A>
<BR>
Squelching a SMARTALLOC
</H2>

<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: 

<P>
<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: 

<P>
<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. 

<P>

<H2><A NAME="SECTION001903000000000000000"></A>
<A NAME="6474"></A>
<A NAME="6475"></A>
<BR>
Living with Libraries
</H2>

<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 <I>xxx</I> redefined by SMARTALLOC, a corresponding routine
named ``<TT>actually</TT><I>xxx</I>'' is furnished which provides direct access to
the underlying system function, as follows: 

<P>
<P>
<BLOCKQUOTE><TABLE CELLPADDING=3>
<TR><TD ALIGN="LEFT" COLSPAN=1><B>Standard function </B></TD>
<TD ALIGN="LEFT" COLSPAN=1><B>Direct
access function  </B></TD>
</TR>
<TR><TD ALIGN="LEFT"><TT>malloc(</TT><I>size</I><TT>)</TT></TD>
<TD ALIGN="LEFT"><TT>actuallymalloc(</TT><I>size</I><TT>)</TT></TD>
</TR>
<TR><TD ALIGN="LEFT"><TT>calloc(</TT><I>nelem</I><TT>,</TT> <I>elsize</I><TT>)</TT></TD>
<TD ALIGN="LEFT"><TT>actuallycalloc(</TT><I>nelem</I>, <I>elsize</I><TT>)</TT></TD>
</TR>
<TR><TD ALIGN="LEFT"><TT>realloc(</TT><I>ptr</I><TT>,</TT> <I>size</I><TT>)</TT></TD>
<TD ALIGN="LEFT"><TT>actuallyrealloc(</TT><I>ptr</I>, <I>size</I><TT>)</TT></TD>
</TR>
<TR><TD ALIGN="LEFT"><TT>free(</TT><I>ptr</I><TT>)</TT></TD>
<TD ALIGN="LEFT"><TT>actuallyfree(</TT><I>ptr</I><TT>)</TT> 

<P></TD>
</TR>
</TABLE>
</BLOCKQUOTE>
<P>

<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: 

<P>
<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. 

<P>
<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>. 

<P>

<H2><A NAME="SECTION001904000000000000000"></A>
<A NAME="6541"></A>
<A NAME="6542"></A>
<BR>
SMARTALLOC Details
</H2>

<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.) 

<P>
<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 <I>legal</I> 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. 

<P>

<H2><A NAME="SECTION001905000000000000000"></A>
<A NAME="6573"></A>
<A NAME="6574"></A>
<BR>
When SMARTALLOC is Disabled
</H2>

<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. 

<P>

<H2><A NAME="SECTION001906000000000000000"></A>
<A NAME="6585"></A>
<A NAME="6586"></A>
<BR>
The <TT>alloc()</TT> Function
</H2>

<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. 

<P>

<H2><A NAME="SECTION001907000000000000000"></A>
<A NAME="6598"></A>
<A NAME="6599"></A>
<BR>
Overlays and Underhandedness
</H2>

<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>./smartall.wml</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. 

<P>

<H2><A NAME="SECTION001908000000000000000"></A>
<A NAME="6610"></A>
<A NAME="6611"></A>
<BR>
Test and Demonstration Program
</H2>

<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. 

<P>

<H2><A NAME="SECTION001909000000000000000"></A>
<A NAME="6616"></A>
<A NAME="6617"></A>
<BR>
Invitation to the Hack
</H2>

<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 Indigo2, 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 <TT>char *</TT> or <TT>void *</TT>, 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. 

<P>
<BR><HR>
<!--Table of Child-Links-->
<A NAME="CHILD_LINKS"><STRONG>Subsections</STRONG></A>

<UL>
<LI><UL>
<LI><A NAME="tex2html1811"
  HREF="Smart_Memory_Allocation.html#SECTION001901000000000000000">Installing SMARTALLOC</A>
<LI><A NAME="tex2html1812"
  HREF="Smart_Memory_Allocation.html#SECTION001902000000000000000">Squelching a SMARTALLOC</A>
<LI><A NAME="tex2html1813"
  HREF="Smart_Memory_Allocation.html#SECTION001903000000000000000">Living with Libraries</A>
<LI><A NAME="tex2html1814"
  HREF="Smart_Memory_Allocation.html#SECTION001904000000000000000">SMARTALLOC Details</A>
<LI><A NAME="tex2html1815"
  HREF="Smart_Memory_Allocation.html#SECTION001905000000000000000">When SMARTALLOC is Disabled</A>
<LI><A NAME="tex2html1816"
  HREF="Smart_Memory_Allocation.html#SECTION001906000000000000000">The <TT>alloc()</TT> Function</A>
<LI><A NAME="tex2html1817"
  HREF="Smart_Memory_Allocation.html#SECTION001907000000000000000">Overlays and Underhandedness</A>
<LI><A NAME="tex2html1818"
  HREF="Smart_Memory_Allocation.html#SECTION001908000000000000000">Test and Demonstration Program</A>
<LI><A NAME="tex2html1819"
  HREF="Smart_Memory_Allocation.html#SECTION001909000000000000000">Invitation to the Hack</A>
</UL>
<BR>
<LI><A NAME="tex2html1820"
  HREF="http_www_fourmilab_ch_smart.html">http://www.fourmilab.ch/smartall/smartall.zip 
Download smartall.ziphttp://www.fourmilab.ch/smartall/smartall.zip
(Zipped archive)</A>
<UL>
<LI><A NAME="tex2html1821"
  HREF="http_www_fourmilab_ch_smart.html#SECTION001911000000000000000">Copying</A>
</UL></UL>
<!--End of Table of Child-Links-->
<HR>
<!--Navigation Panel-->
<A NAME="tex2html1809"
  HREF="http_www_fourmilab_ch_smart.html">
<IMG WIDTH="37" HEIGHT="24" ALIGN="BOTTOM" BORDER="0" ALT="next" SRC="next.png"></A> 
<A NAME="tex2html1803"
  HREF="Developer_s_Guide.html">
<IMG WIDTH="26" HEIGHT="24" ALIGN="BOTTOM" BORDER="0" ALT="up" SRC="up.png"></A> 
<A NAME="tex2html1797"
  HREF="Higher_Level_Conventions.html">
<IMG WIDTH="63" HEIGHT="24" ALIGN="BOTTOM" BORDER="0" ALT="previous" SRC="prev.png"></A> 
<A NAME="tex2html1805"
  HREF="Contents.html">
<IMG WIDTH="65" HEIGHT="24" ALIGN="BOTTOM" BORDER="0" ALT="contents" SRC="contents.png"></A> 
<A NAME="tex2html1807"
  HREF="GNU_Free_Documentation_Lice.html">
<IMG WIDTH="43" HEIGHT="24" ALIGN="BOTTOM" BORDER="0" ALT="index" SRC="index.png"></A> 
<BR>
<B> Next:</B> <A NAME="tex2html1810"
  HREF="http_www_fourmilab_ch_smart.html">http://www.fourmilab.ch/smartall/smartall.zip Download smartall.ziphttp://www.fourmilab.ch/smartall/smartall.zip (Zipped</A>
<B> Up:</B> <A NAME="tex2html1804"
  HREF="Developer_s_Guide.html">Developer's Guide</A>
<B> Previous:</B> <A NAME="tex2html1798"
  HREF="Higher_Level_Conventions.html">Higher Level Conventions</A>
 &nbsp; <B>  <A NAME="tex2html1806"
  HREF="Contents.html">Contents</A></B> 
 &nbsp; <B>  <A NAME="tex2html1808"
  HREF="GNU_Free_Documentation_Lice.html">Index</A></B> 
<!--End of Navigation Panel-->
<ADDRESS>

2012-01-24
</ADDRESS>
</BODY>
</HTML>