Using the librcheck library

The librcheck library provides the capabilities for detecting and reporting errors.
It's available when you link your program with the -lrcheck option.

Another way to use the librcheck library is to use the
LD_PRELOAD capability to the dynamic loader.
The LD_PRELOAD environment variable lets you specify libraries to load before any other
library in the system.
In this case, set the LD_PRELOAD variable as follows:

LD_PRELOAD=librcheck.so

For example:

LD_PRELOAD=librcheck.so ./my_program

By default, the librcheck library provides a minimal level of
checking. When an allocation or release request is performed, the
library checks only the immediate block under consideration and
its neighbors, looking for sources of heap corruption.

Additional checking and more informative error reporting can be
done by using additional options provided by the librcheck library.
The
mallopt()
function provides control over the types of
checking performed by the library.
In addition to reporting the file and line information about the
caller when an error is detected, the error-reporting mechanism
prints out the file and line information that was associated with
the allocation of the offending heap buffer.

To control the use of the librcheck library, you need to
include a different header file, <rcheck/malloc.h>.
If you want to use any of the additional mallopt() commands
that this header file declares, make
sure that you link your application with librcheck;
the libc version of mallopt() gives an error
of EINVAL for these additional commands.

In addition, you may want to add an exit handler that provides a dump of leaked
memory, and initialization code that turns on a reasonable level
of checking for the debug variant of the program.

The librcheck library keeps
additional information in the header of each heap buffer, including
doubly-linked lists of all allocated blocks, file, line, and other
debug information, flags, and a CRC of the header. The allocation
policies and configuration are identical to the normal
memory allocation routines except for the additional internal
overhead imposed by the librcheck library. This allows the
librcheck
library to perform checks without altering the size of blocks
requested by the program. Such manipulation could result in an
alteration of the behavior of the program with respect to the
allocator, yielding different results when linked against the
librcheck library.

All allocated blocks are integrated into a number of allocation
chains associated with allocated regions of memory kept by the
allocator in arenas or blocks.
The librcheck library has intimate
knowledge about the internal structures of the allocator,
allowing it to use short cuts to find the correct heap buffer
associated with any pointer, resorting to a lookup on the
appropriate allocation chain only when necessary. This minimizes
the performance penalty associated with validating pointers, but
it's still significant.

The time and space overheads imposed by the librcheck
library are too great to make it suitable for use as a production library,
but are manageable enough to allow them to be used during the
test phase of development and during program maintenance.

What's checked?

The librcheck library provides a minimal level
of checking by default. This includes a check of the integrity of
the allocation chain at the point of the local heap buffer on
every allocation request. In addition, the flags and CRC of the
header are checked for integrity. When the library can locate the
neighboring heap buffers, it also checks their integrity. There
are also checks specific to each type of allocation request that
are done. Call-specific checks are described according to the
type of call below.

You can enable additional checks by using the mallopt() call. For
more information on the types of checking, and the sources of
heap corruption that can be detected, see
"Controlling the level of checking."

Allocating memory

When a heap buffer is allocated using any of the heap-allocation
routines, the heap buffer is added to the allocation chain for
the arena or block within the heap that the heap buffer was
allocated from. At this time, any problems detected in the
allocation chain for the arena or block are reported. After
successfully inserting the allocated buffer in the allocation
chain, the previous and next buffers in the chain are also
checked for consistency.

Reallocating memory

When an attempt is made to resize a buffer through a call to the
realloc()
function,
the pointer is checked for validity if it's a
non-NULL value. If it's valid, the header of the heap buffer is
checked for consistency. If the buffer is large enough to satisfy
the request, the buffer header is modified, and the call returns.
If a new buffer is required to satisfy the request, memory
allocation is performed to obtain a new buffer large enough to
satisfy the request with the same consistency checks being
applied as in the case of memory allocation described above. The
original buffer is then released.

If fill-area boundary checking is enabled (described in the
"Controlling the level of checking"
section),
the guard code checks are also
performed on the allocated buffer before it's actually resized.
If a new buffer is used, the guard code checks are done just
before releasing the old buffer.

Releasing memory

This includes, but isn't limited to, checking to ensure that the
pointer provided to a
free()
request is correct and points to an allocated heap buffer.
Guard code checks may also be performed on
release operations to allow fill-area boundary checking.