Next: Profiling, Previous: Efficiency, Up: MPIR Basics [Index]
Depending on the system, a segmentation violation or bus error might be the only indication of stack overflow. See ‘--enable-alloca’ choices in Build Options, for how to address this.
In new enough versions of GCC, ‘-fstack-check’ may be able to ensure an overflow is recognised by the system before too much damage is done, or ‘-fstack-limit-symbol’ or ‘-fstack-limit-register’ may be able to add checking if the system itself doesn’t do any (see Options for Code Generation in Using the GNU Compiler Collection (GCC)). These options must be added to the ‘CFLAGS’ used in the MPIR build (see Build Options), adding them just to an application will have no effect. Note also they’re a slowdown, adding overhead to each function call and each stack allocation.
The most likely cause of application problems with MPIR is heap corruption.
Failing to init
MPIR variables will have unpredictable effects, and
corruption arising elsewhere in a program may well affect MPIR. Initializing
MPIR variables more than once or failing to clear them will cause memory leaks.
In all such cases a malloc
debugger is recommended. On a GNU or BSD
system the standard C library malloc
has some diagnostic facilities,
see Allocation Debugging in The GNU C Library
Reference Manual, or ‘man 3 malloc’. Other possibilities, in no
particular order, include
http://dmalloc.com/ http://www.perens.com/FreeSoftware/ (electric fence) http://www.gnupdate.org/components/leakbug/ http://wwww.gnome.org/projects/memprof
The MPIR default allocation routines in memory.c also have a simple
sentinel scheme which can be enabled with #define DEBUG
in that file.
This is mainly designed for detecting buffer overruns during MPIR development,
but might find other uses.
On some systems the compiler options MPIR uses by default can interfere with debugging. In particular on x86 and 68k systems ‘-fomit-frame-pointer’ is used and this generally inhibits stack backtracing. Recompiling without such options may help while debugging, though the usual caveats about it potentially moving a memory problem or hiding a compiler bug will apply.
A sample .gdbinit is included in the distribution, showing how to call some undocumented dump functions to print MPIR variables from within GDB. Note that these functions shouldn’t be used in final application code since they’re undocumented and may be subject to incompatible changes in future versions of MPIR.
MPIR has multiple source files with the same name, in different directories. For example mpz, mpq and mpf each have an init.c. If the debugger can’t already determine the right one it may help to build with absolute paths on each C file. One way to do that is to use a separate object directory with an absolute path to the source directory.
cd /my/build/dir /my/source/dir/gmp-3.0.0/configure
This works via VPATH
, and might require GNU make
.
Alternately it might be possible to change the .c.lo
rules
appropriately.
The build option --enable-assert is available to add some consistency checks to the library (see Build Options). These are likely to be of limited value to most applications. Assertion failures are just as likely to indicate memory corruption as a library or compiler bug.
Applications using the low-level mpn
functions, however, will benefit
from --enable-assert since it adds checks on the parameters of most
such functions, many of which have subtle restrictions on their usage. Note
however that only the generic C code has checks, not the assembler code, so
CPU ‘none’ should be used for maximum checking.
The build option --enable-alloca=debug arranges that each block of
temporary memory in MPIR is allocated with a separate call to malloc
(or
the allocation function set with mp_set_memory_functions
).
This can help a malloc debugger detect accesses outside the intended bounds,
or detect memory not released. In a normal build, on the other hand,
temporary memory is allocated in blocks which MPIR divides up for its own use,
or may be allocated with a compiler builtin alloca
which will go
nowhere near any malloc debugger hooks.
To summarize the above, an MPIR build for maximum debuggability would be
./configure --disable-shared --enable-assert \ --enable-alloca=debug --host=none CFLAGS=-g
For C++, add ‘--enable-cxx CXXFLAGS=-g’.
The GCC checker (http://savannah.gnu.org/projects/checker/) can be used with MPIR. It contains a stub library which means MPIR applications compiled with checker can use a normal MPIR build.
A build of MPIR with checking within MPIR itself can be made. This will run very very slowly. On GNU/Linux for example,
./configure --host=none-pc-linux-gnu CC=checkergcc
‘--host=none’ must be used, since the MPIR assembler code doesn’t support the checking scheme. The MPIR C++ features cannot be used, since current versions of checker (0.9.9.1) don’t yet support the standard C++ library.
The valgrind program (http://valgrind.org/) is a memory checker for x86s. It translates and emulates machine instructions to do strong checks for uninitialized data (at the level of individual bits), memory accesses through bad pointers, and memory leaks.
Recent versions of Valgrind are getting support for MMX and SSE/SSE2 instructions, for past versions MPIR will need to be configured not to use those, ie. for an x86 without them (for instance plain ‘i486’).
Any suspected bug in MPIR itself should be isolated to make sure it’s not an application problem, see Reporting Bugs.
Next: Profiling, Previous: Efficiency, Up: MPIR Basics [Index]