MANDOC_DBG_INIT(3)

NAME
mandoc_dbg_init, mandoc_dbg_name, mandoc_dbg_finish - search for memory leaks in mandoc

SYNOPSIS
void
mandoc_dbg_init(int argc, char *argv[]);
void
mandoc_dbg_name(const char *);
void
mandoc_dbg_finish(void);

DESCRIPTION
If the mandoc package is built with the line ‘DEBUG_MEMORY=1’ in the file configure.local, the functions documented in mandoc_malloc(3) and the function free(3) are instrumented to record every memory allocation in a dedicated hash table and to check that every allocation is freed again. This compile time option is only intended for binaries that are used exclusively for debugging. It is not intended for production binaries because it significantly increases run time and memory usage and makes the programs more fragile and more error-prone.

The function mandoc_dbg_init() initializes the memory debugging subsystem. It is called from the top of the main() programs, passing through the arguments that main() received. The ENVIRONMENT section of the present manual page explains how the DEBUG_MEMORY environment variable controls the amount and destination of reporting.

The function mandoc_dbg_name() is called from the mdoc(7) and man(7) parsers whenever a Dt or TH macro is parsed, passing the complete macro line as the argument.

The function mandoc_dbg_finish() performs cleanup and optionally final reporting. It is called from the end of the main() programs, just before normal termination.

Getting the #include directives right for these functions is slightly tricky. If a file already includes "mandoc_aux.h", no additional directive is needed because "mandoc_aux.h" already includes "mandoc_dgb.h" if ‘DEBUG_MEMORY=1’ is set in configure.local.

If a file does not need "mandoc_aux.h" but calls a function documented in the present manual page and also calls free(3) directly, it needs this code before the other mandoc_headers(3):

    #if DEBUG_MEMORY
    #include "mandoc_dbg.h"
    #endif

If a file calls a function documented in the present manual page but does not directly call free(3), it can use this less intrusive idiom:

    #if DEBUG_MEMORY
    #define DEBUG_NODEF
    #include "mandoc_dbg.h"
    #endif

ENVIRONMENT
The environment variable DEBUG_MEMORY controls the amount and destination of reporting.

If it is unset, diagnostic output is directed to standard error output and only fatal errors are reported. Even though full memory accounting is always performed by any binary that was compiled with ‘DEBUG_MEMORY=1’, resulting in a significant increase in both run time and memory usage, memory leaks are not reported when DEBUG_MEMORY is not set at run time.

If DEBUG_MEMORY is set, it is interpreted as a string of flags. The flags are as follows:

A   Log every allocation. This produces huge amounts of output and is usually not needed to find memory leaks. Its main purpose is debugging the memory debugging subsystem itself.

    When enabled, allocations are logged in this format:

        A file.c:line function(nmemb, size) = address

    The meaning of the fields is the same as for the L option.

F   Log every free(3) and every reallocation where the memory to be released or reallocated was allocated with one of the functions documented in mandoc_malloc(3). Again, this produces huge amounts of output and is usually not needed to find memory leaks, and its main purpose is debugging the memory debugging subsystem itself.

    The logging format is:

        F file.c:line function(address)

    It provides the name of the file and the number of the line in that file which called the free(3) or reallocation function, and the address that was given as an argument.

    If both the A and the F flags are enabled, calls to reallocation functions often log two lines, first an F line reporting the address passed in as an argument, then an A line reporting the adress returned as the function return value.

L   Log every memory leak. For every allocation made after mandoc_dbg_init() using functions documented in mandoc_malloc(3) that was not freed before mandoc_dbg_finish(), print a line in this format:

        L file.c:line function(nmemb, size) = address

    It provides the name of the file and the number of the line in that file which called the allocation function with the arguments nmemb and size documented for calloc(3). If the function does not take an nmemb argument, nmemb is reported as 1. At the end of the line, the virtual address of the memory returned from the allocation function is reported.

N   Log the names of manual pages processed in the following formats:

        N .Dt name section [architecture]
        N .TH name section [additional arguments]

    This is particularly useful if a program crashes, runs out of memory, or enters an infinite loop. The last N line logged often indicates the input file triggering the problem.

/   Interpret the rest of DEBUG_MEMORY as an absolute path and redirect debugging output to that file, appending to the file if it already exists or creating it otherwise.

If DEBUG_MEMORY is set, even if it is empty, mandoc_dbg_init() always writes the line

    P pid [progname] [argument] ...

enclosing each element of argv in square brackets, to avoid that arguments containing whitespace appear in the same way as multiple arguments, and mandoc_dbg_finish() always writes the line:

    S number memory leaks found

EXAMPLES
The following is a typical sequence of commands for finding memory leaks in the parsers, in the HTML formatter, and in the regression suite:

    make distclean
    echo BUILD_CATMAN=1 >> configure.local
    echo DEBUG_MEMORY=1 >> configure.local
    ./configure
    make
    export DEBUG_MEMORY=NL/tmp/mandoc.debug.txt
    mkdir Out
    export PATH=$PATH:$(pwd)
    ./catman -T html /usr/share/man Out
    make regress-clean
    make regress
    less /tmp/mandoc.debug.txt

SEE ALSO
mandoc_malloc(3), catman(8)