9

I am trying to debug Rcpp compiled code at run-time. I have been trying to get this to work unsuccessfully, for a very long time. A very similar question was asked here: Debugging (line by line) of Rcpp-generated DLL under Windows which asks the same question, but both the question and the answer are far beyond my understanding.

Here is what I have:

Windows 7 Pro SP1
R 3.5
Rstudio 1.1.463 with Rcpp.
Rbuild Tools from Rstudio. (c++ compiler)

Procedure: In Rstudio File->New File->C++ File (creates a sample file with a timesTwo function.)

I added a new function in this file:

// [[Rcpp::export]]
NumericVector timesTwo2(NumericVector x) {
  for(int ii = 0; ii <= x.size(); ii++)
  {
    x.at(ii) = x.at(ii) * 2;
  }
  return x;
}

I checked Source on Save and saved the file as RcppTest.cpp which sources or complies the file successfully.

Run code in Rstudio:

data = c(1:10)
data
[1]  1  2  3  4  5  6  7  8  9 10
timesTwo2(data)
Error in timesTwo2(data) : Index out of bounds: [index=10; extent=10].

The error is because in the for loop is <= x.size() so the result is a run-time error.

The question is how can get a debug output about this error that reasonably tells me what happened? At the very least I would like to know the line in the code that triggered the exception and with which parameters. Furthermore, I would really like to execute the code line-by-line to just before the exception so I can monitor exactly what is happening.

I can install any additional programs or apply any other settings as long as I can find precise details on how to do it. For now I am starting from scratch just to get it working. Thank you.

Update: I found this site: Debugging Rcpp c++ code using gdb I installed the latest gcc 8.1 with gdb

I found the CXXFLAGS in the makeconf file located in C:\Program Files\R\R-3.5.1\etc\x64 Then I started the Rgui as suggested, but when I try Rcpp:::sourceCpp I get an error:

> library(Rcpp)
> Rcpp::sourceCpp('Rcpptest.cpp')
C:/PROGRA~1/R/R-35~1.1/etc/x64/Makeconf:230: warning: overriding recipe for target '.m.o'
C:/PROGRA~1/R/R-35~1.1/etc/x64/Makeconf:223: warning: ignoring old recipe for target '.m.o'
c:/Rtools/mingw_64/bin/g++  -I"C:/PROGRA~1/R/R-35~1.1/include" -DNDEBUG   -I"C:/Users/Michael/Documents/R/win-library/3.5/Rcpp/include" -I"C:/PROGRA~1/R/R-35~1.1/bin/x64"        -ggdb -O0 -Wall -gdwarf-2 -mtune=generic -c Rcpptest.cpp -o Rcpptest.o
process_begin: CreateProcess(NULL, c:/Rtools/mingw_64/bin/g++ -IC:/PROGRA~1/R/R-35~1.1/include -DNDEBUG -IC:/Users/Michael/Documents/R/win-library/3.5/Rcpp/include -IC:/PROGRA~1/R/R-35~1.1/bin/x64 -ggdb -O0 -Wall -gdwarf-2 -mtune=generic -c Rcpptest.cpp -o Rcpptest.o, ...) failed.
make (e=2): The system cannot find the file specified.

make: *** [C:/PROGRA~1/R/R-35~1.1/etc/x64/Makeconf:215: Rcpptest.o] Error 2
Error in Rcpp::sourceCpp("Rcpptest.cpp") : 
  Error 1 occurred building shared library.

WARNING: The tools required to build C++ code for R were not found.

Please download and install the appropriate version of Rtools:

http://cran.r-project.org/bin/windows/Rtools/

It looks like it is loading the new CXXFLAGS and it is using DEBUG, but it seems that it still cannot compile. Anybody know why from the error?

I tried running Rstudio the same way as Rgui and it started with many threads showing in the gdb window, but everything in Rstudio ran exactly as before with no additional debug information from Rstudio or gdb.

Update 2: As the error above states that Rgui did not have Rtools for compiling so I installed the Rtools from the provide link. It installed in C:\Rtools while Rstudio installed in C:\RBuildTools. So I now have 3 compilers, Rtools, RbuildTools and gcc with gdb. It compiles now, but still gives the same error as I did in Rstudio. I would like to at least get better error output, like the line and value passed. The instruction say Rgui should have a spot for a break-point, but I cannot find such an option.

Update 3 I was finally able to set up and run a Linux install (Ubuntu 16.04.05). First here are my CXXFLAGS:

$ R CMD config CXXFLAGS
-g -O0 -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g

I had to create a .R folder in my home directory and a Makevar file in it with just the line

CXXFLAGS = -g -O0 -Wall -pedantic -fstack-protector-strong -D_FORTIFY_SOURCE=2

This alone took hours as nowhere did it actually say make the folder and file.

Then I executed the commands as Ralf posted, at the break point:

> timesTwo2(d1)

Thread 1 "R" hit Breakpoint 1, timesTwo2 (x=...) at RcppTest.cpp:19
19  NumericVector timesTwo2(NumericVector x) {
(gdb) n
20    for (int ii = 0; ii <= x.size(); ii++)
(gdb) n
22      x.at(ii) = x.at(ii) * 2;
(gdb) display ii
1: ii = 0
(gdb) n
20    for (int ii = 0; ii <= x.size(); ii++)
1: ii = 0
(gdb) n
22      x.at(ii) = x.at(ii) * 2;
1: ii = 1
(gdb) n
20    for (int ii = 0; ii <= x.size(); ii++)
1: ii = 1
(gdb) display x.at(ii)
2: x.at(ii) = <error: Attempt to take address of value not located in memory.>
(gdb) n
22      x.at(ii) = x.at(ii) * 2;
1: ii = 2
2: x.at(ii) = <error: Attempt to take address of value not located in memory.>
(gdb) 

And finally at n = 10:

1: ii = 10
2: x.at(ii) = <error: Attempt to take address of value not located in memory.>
(gdb) n
0x00007ffff792d762 in Rf_applyClosure () from /usr/lib/R/lib/libR.so
(gdb) 

This is definitely the furthest I have come to debugging, but this is a very basic function and the debug output and even the error output was not very useful. It gave me the line it was executing and it could display ii, but I could not display the array value or the entire array. Is it possible to create a more specific break point such that it only breaks when ii == 10? Ideally I would like this in Rstudio or some other GUI that can display the entire vector. Still doing more testing.

Ðаn
  • 10,934
  • 11
  • 59
  • 95
MichaelE
  • 763
  • 8
  • 22
  • 5
    See _Writing R Extensions_ on invoking a debugger. Far from ideal but we have, apart from good old `print` statements. – Dirk Eddelbuettel Dec 05 '18 at 00:49
  • 7
    my cpp files are littered with `Rcpp::Rcout << thistestobj << std::endl;` statements while I'm developing them. – SymbolixAU Dec 05 '18 at 01:43
  • 4
    Sometimes, when I'm having trouble with `Rcpp`, I try to convert everything to pure `c++` (e.g. something like `NumericVector -->> std::vector`) and use the debugger in Visual Studio. It is a lot of work, but sometimes, it is just really hard to track down elusive errors with just `print` statements. – Joseph Wood Dec 05 '18 at 01:52
  • The Rcpp::Rcput << ii << std::endl; works great. I have never been able to get Rcpp to print until now. It is a huge step in debugging. – MichaelE Dec 06 '18 at 16:46
  • Joseph, how would converting to c++ and Visual Studio help? A while ago I was able to set up Eclipse so I could write code in Eclipse, but I still could not debug in it and it eventually became unstable so back to Rstudio. If in my small example I used vector instead of Numeric vector how would I continue? Thank you. – MichaelE Dec 06 '18 at 16:50
  • You can also find a nice step-by-step description here: http://lists.r-forge.r-project.org/pipermail/rcpp-devel/2014-September/008036.html – R Yoda Nov 09 '19 at 17:47
  • @MichaelE The link to [Debugging Rcpp c++ code using gdb](https://support.rstudio.com/hc/en-us/community/posts/200655937-Debugging-Rcpp-c-code-using-gdb) seems to be dead or behind a pay wall. Would it be possible for you to add the essential parts to your question? THX :-) – R Yoda Dec 07 '19 at 09:39

2 Answers2

7

The usual approach R -d gdb, which I also suggested in my original answer below, does not work on Windows:

--debugger=name
-d name

(UNIX only) Run R through debugger name. For most debuggers (the exceptions are valgrind and recent versions of gdb), further command line options are disregarded, and should instead be given when starting the R executable from inside the debugger.

https://cran.r-project.org/doc/manuals/r-release/R-intro.html#Invoking-R-from-the-command-line

Alternative:

  1. Start R in debugger: gdb.exe Rgui.exe
  2. Set break point: break TimesTwo2
  3. Run R: run
  4. Source file: Rcpp::sourceCpp("debug.cpp")
  5. Use next, print, display to step through the code.

An alternative to step 1. would be to start R, get the PID with Sys.getpid(), attach debugger with gdb -p <pid>. You will than have to use continue instead of run.


I don't have a Windows machine right now, so the following was done on Linux. I hope it is transferable, though. Let's start with a simple cpp file (debug.cpp in my case) that contains your code:

#include <Rcpp.h>
using Rcpp::NumericVector;

// [[Rcpp::export]]
NumericVector timesTwo2(NumericVector x) {
  for(int ii = 0; ii <= x.size(); ii++)
  {
    x.at(ii) = x.at(ii) * 2;
  }
  return x;
}

/*** R
data = c(1:10)
data
timesTwo2(data)
*/

I can reproduce the error by calling R on the command line:

$ R -e "Rcpp::sourceCpp('debug.cpp')"

R version 3.5.1 (2018-07-02) -- "Feather Spray"
[...]

> Rcpp::sourceCpp('debug.cpp')

> data = c(1:10)

> data
 [1]  1  2  3  4  5  6  7  8  9 10

> timesTwo2(data)
Error in timesTwo2(data) : Index out of bounds: [index=10; extent=10].
Calls: <Anonymous> ... source -> withVisible -> eval -> eval -> timesTwo2 -> .Call
Execution halted

Next we can start R with gdb as debugger (c.f. Writing R Extensions as Dirk said):

$ R -d gdb -e "Rcpp::sourceCpp('debug.cpp')"
GNU gdb (Debian 8.2-1) 8.2
[...]
(gdb) break timesTwo2
Function "timesTwo2" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (timesTwo2) pending.
(gdb) run
[...]
> Rcpp::sourceCpp('debug.cpp')
[Thread 0xb40d3b40 (LWP 31793) exited]
[Detaching after fork from child process 31795]

> data = c(1:10)

> data
 [1]  1  2  3  4  5  6  7  8  9 10

> timesTwo2(data)

Thread 1 "R" hit Breakpoint 1, 0xb34f3310 in timesTwo2(Rcpp::Vector<14, Rcpp::PreserveStorage>)@plt ()
   from /tmp/RtmphgrjLg/sourceCpp-i686-pc-linux-gnu-1.0.0/sourcecpp_7c2d7f56744b/sourceCpp_2.so
(gdb)

At this point you can single step through the program using next (or just n) and output variables using print (or just p). A useful command is also display:

Thread 1 "R" hit Breakpoint 1, timesTwo2 (x=...) at debug.cpp:5
5   NumericVector timesTwo2(NumericVector x) {
(gdb) n
6     for(int ii = 0; ii <= x.size(); ii++)
(gdb) n
8       x.at(ii) = x.at(ii) * 2;
(gdb) display ii
2: ii = 0
(gdb) n
8       x.at(ii) = x.at(ii) * 2;
2: ii = 0

[...]

2: ii = 9
(gdb) 
46          inline proxy ref(R_xlen_t i) { return start[i] ; }
2: ii = 9
(gdb) 
6     for(int ii = 0; ii <= x.size(); ii++)
2: ii = 10
(gdb) 
8       x.at(ii) = x.at(ii) * 2;
2: ii = 10
(gdb) 
Error in timesTwo2(data) : Index out of bounds: [index=10; extent=10].
Calls: <Anonymous> ... source -> withVisible -> eval -> eval -> timesTwo2 -> .Call
Execution halted
[Detaching after fork from child process 32698]
[Inferior 1 (process 32654) exited with code 01]

BTW, I used the following compile flags:

$ R CMD config CXXFLAGS
-g -O2 -Wall -pedantic -fstack-protector-strong -D_FORTIFY_SOURCE=2

You might want to switch to -O0.

R Yoda
  • 8,358
  • 2
  • 50
  • 87
Ralf Stubner
  • 26,263
  • 3
  • 40
  • 75
  • Thanks, I think this only works for linux. When I have a chance I will try setting up linux box and then follow your example. If it works I might start debugging in linux when needed. – MichaelE Dec 06 '18 at 16:44
  • @MichaelE What result do you get on Windows? – Ralf Stubner Dec 06 '18 at 16:45
  • I can run the code in cmd directly with Rtools installed. It first says ARGUMENT 'gdb' __ignored__ and then it continues to run the code and give the same error as before. So it seems gdb works differently in windows. – MichaelE Dec 06 '18 at 18:49
  • @MichaelE Interesting. See the updated answer for an alternative (still untested). – Ralf Stubner Dec 06 '18 at 19:58
  • I did the break TimesTwo2 exactly as you suggested. It said: No symbol table is loaded. Use the "file" command. Make breakepoint pending on future shared library load? (y or [n]) Breakepoint 1 (TimesTwo2) pending. When I run it runs rgui just as before and still results with the same error and no breaks. Thanks. – MichaelE Dec 06 '18 at 20:21
  • I finally set up Ubuntu and executed exactly as you did and I got the same result with the line, but not much more error details. This can't be the best there is? The sample is only 10 lines, how do I reasonably go thorough thousands or millions of lines? Thank you. – MichaelE Dec 13 '18 at 20:58
  • @MichaelE the above commands where meant to get you started. See the [gdb documentation](http://sourceware.org/gdb/current/onlinedocs/gdb/) for things like conditional breakpoints etc. – Ralf Stubner Dec 14 '18 at 10:36
3

It can be done with Visual Studio Code, since it can handle both R and C++. This allows you to step through your Rcpp code one line at a time in a GUI environment.

See this demo to get started.

James Hirschorn
  • 7,032
  • 5
  • 45
  • 53
  • Thanks, is there a specific version I need? I have 2012 Pro which did not work for me, but it has been a while. Can I use mine or do I have to upgrade? Thanks again. – MichaelE Mar 25 '20 at 19:54
  • @MichaelE I'm not familiar with "2012 Pro". I just started using VS Code for this particular problem, and my software says Version: 1.43.1. I am on Ubuntu (Linux) btw, but it should work on Windows. Note this is VS *Code*, and not the MS Visual Studio IDE. – James Hirschorn Mar 26 '20 at 04:54
  • I did not realize that. I thought VS Code was just a newer version MS Visual Studio. Thanks, I will try it and update if I get it working. Thanks again. – MichaelE Mar 27 '20 at 18:58
  • @MichaelE did you get **any** of the methods to work? I have gotten as far, as succesfully activating the debugger using the tiny example in "Writing R Extensions" (not in a Dll), and I can get VS code working on standard c++ code but not dll's executed through R. Even changing makeconf/makevars/makevars.win removing -DNDEBUG and adding -g does not seem to do much. – Oliver Dec 29 '20 at 18:59
  • It's been a while but yes, I do believe I got the demo to successfully debug. – James Hirschorn Jan 03 '21 at 16:12
  • Worked like a charm today. – James Hirschorn Nov 23 '21 at 17:57