Example 21: Debugging
For a more in-depth discussion of debugging with MOOSE see the Debugging Documentation
It's inevitable: at some point in your MOOSE application development career, you will create a bug.
Sometimes, print statements are sufficient to help you determine the cause of the error.
For more complex bugs, a debugger can be more effective than print statements in helping to pinpoint the problem.
Many debuggers exist: LLDB, GDB, Totalview, ddd, Intel Debugger, etc.
It's typically best to use a debugger that is associated with your compiler, if one is available.
Here we focus on LLDB/GDB since it is relatively simple to use and is included in the MOOSE binary redistributable package.
A "Segmentation fault," "Segfault," or "Signal 11" error denotes a memory bug (often array access out of bounds).
In your terminal you will see a message like:
Segmentation fault: 11`
A segfault is a "good" error to have, because a debugger can easily pinpoint the problem.
Debugging Example Problem
This example is similar to Example 3, except that a common error has been introduced.
In
ExampleDiffusion.h
, aVariableValue
that should be declared as a reference is not:const VariableValue _coupled_coef
Not storing this as a reference will cause a copy** of the
VariableValue
to be made.That copy will never be resized, nor will it ever have values written to it.
Attempting to access that
VariableValue
results in a segfault when running in optimized mode:
Time Step 0, time = 0
dt = 0
Time Step 1, time = 0.1
dt = 0.1
Segmentation fault: 11
We can use a debugger to help us find the problem.
Debug Executable
To use a debugger with a MOOSE-based application, you must compile your application in something other than optimized mode (opt). We highly recommend debug (dbg) mode so that you'll get full line number information in your stack traces:
cd ~/projects/moose/examples/ex21_debugging
METHOD=dbg make -j8
You will now have a "debug version" of your application called
ex21-dbg
.Next, you need to run your application using either GDB (gcc) or LLDB (clang):
gdb --args ./ex21-dbg -i ex21.i
lldb -- ./ex21-dbg -i ex21.i
When using either of these tools, the command line arguments to the application appear after the
--
separator.This will start debugger, load your executable, and leave you at the debugger command prompt.
Using GDB or LLDB
At any prompt in GDB or LLDB, you can type
h
and hit enter to get help.We set a "breakpoint" in
MPI_Abort
so that the code pauses (maintaining the stack trace) before exiting.
b MPI_Abort
To run your application, type
r
and hit enter.If your application hits the breakpoint in
MPI_Abort
you know it has crashed.Type
where
(orbt
) to see a backtrace.
frame #0: 0x0000000106b14a20 libmpi.12.dylib`MPI_Abort
frame #1: 0x00000001000d8e78 libex21-dbg.0.dylib`MooseArray<double>::operator[](this=0x0000000108852680, i=0) const + 2200 at MooseArray.h:267
frame #2: 0x00000001000d85ab libex21-dbg.0.dylib`ExampleDiffusion::computeQpResidual(this=0x0000000108852000) + 43 at ExampleDiffusion.C:40
frame #3: 0x0000000100c2affb libmoose-dbg.0.dylib`Kernel::computeResidual(this=0x0000000108852000) + 443 at Kernel.C:57
.....
This backtrace shows that, in
ExampleDiffusion::computeQpResidual()
we tried to access entry 0 of aMooseArray
with 0 entries.If we look at the relevant line of code, we'll see:
return _coupled_coef[_qp]*Diffusion::computeQpResidual();
There is only one thing we're indexing into on that line:
_coupled_coef
.Therefore, we can look at how
_coupled_coef
was declared, realize that we forgot an ampersand (&
), and fix it!