Debugging in R

These web pages describe various issues involved in debugging code written for the open source statistical package R. It is particularly aimed at Windows programmers, but many of the techniques work more widely.

For instructions particular to other platforms, and non-compiler-specific details, see the Writing R Extensions manual in the docs subdirectory of the R installation.

Other web pages with debugging help:

Using R's exception handling

See the ?tryCatch help topic for lots of detail on R's exception handling. The withCallingHandlers() function gives a flexible way to debug warning and error conditions. The general syntax is
 withCallingHandlers(expr, ...)
where the expr can be any statement or expression (or list of statements enclosed in braces {}). The ... arguments establish handlers for whichever conditions you want to catch. By default, R defines the warning and error conditions, which are signalled by warning() and stop() respectively. Users may define their own conditions and signal them using signalCondition(); see its man page for details. Typical debugging usage to trap on a warning message would be something like this:
> foo <- function(x) {
+     if (x > 0) return("positive")
+     else return("negative")
+ }
> 
> foo(1:5)
[1] "positive"
Warning message:
the condition has length > 1 and only the first element will be used in: if (x > 0) return("positive") else return("negative") 

Where did that warning come from? Use withCallingHandlers to find out...

> withCallingHandlers(foo(1:5), warning=function(c) recover())

Enter a frame number, or 0 to exit   

1: withCallingHandlers(foo(1:5), warning = function(c) recover())
2: foo(1:5)
3: .signalSimpleWarning("the condition has length > 1 and only the first element wi
4: withRestarts({
5: withOneRestart(expr, restarts[[1]])
6: doWithOneRestart(return(expr), restart)
7: function (c) 

Selection: 2
Called from: eval(expr, envir, enclos)
Browse[1]> x
[1] 1 2 3 4 5
Browse[1]> 

Enter a frame number, or 0 to exit   

1: withCallingHandlers(foo(1:5), warning = function(c) recover())
2: foo(1:5)
3: .signalSimpleWarning("the condition has length > 1 and only the first element wi
4: withRestarts({
5: withOneRestart(expr, restarts[[1]])
6: doWithOneRestart(return(expr), restart)
7: function (c) 

Selection: 0
[1] "positive"
Warning message:
the condition has length > 1 and only the first element will be used in: if (x > 0) return("positive") else return("negative") 
> 

Just-in-time debugging

The Dr. Mingw "just-in-time" debugger from the mingw-utils bundle on http://www.mingw.org will display a stack dump at the time of a crash. If the crash occurs in R itself, you'll need to have built R with debugging information to get useful information.

Debugging R itself

To build R with debugging information, install the R source code, assemble the tools necessary to build it, then in the RHOME/src/gnuwin32 directory, execute
make clean
make DEBUG=T
This will build R with full source-level debugging information. Then running gdb or Insight as described above will let you debug the R internals.

Using other debuggers

R can run DLLs built with any Win32 compiler. Most commercial compilers (e.g. those by Borland or Microsoft) come with source level debuggers. These are unlikely to be able to debug R internals (because they won't understand the debugging information installed by gcc), but they can debug your DLL. How to do so depends on the particular tools you are using, but it is likely to be something like this:
  1. Compile and link your DLL with debug information.
  2. Declare Rgui to be the host application for your DLL, and run it from within the debugger; OR, run Rgui from outside the debugger, then tell the debugger to attach to the Rgui.exe process.
At this point, you should be able to set breakpoints, examine variables, etc. in your DLL.

Detailed information for Borland Delphi is given here.

If you have worked out instructions for other debuggers, please send them to me.


Last modified: Fri 20 Aug 2010, by Duncan Murdoch