Skip to content

Instantly share code, notes, and snippets.

@knausb
Last active March 19, 2019 15:27
Show Gist options
  • Save knausb/0787d74bdbe3195cd02a48d30ee9c73b to your computer and use it in GitHub Desktop.
Save knausb/0787d74bdbe3195cd02a48d30ee9c73b to your computer and use it in GitHub Desktop.
rocker_asan
.Rproj.user
.Rhistory
.RData
.Ruserdata
*.html
---
title: Address sanitizer in Rocker
author: Brian J. Knaus
license: GPL (>= 2)
output:
html_document:
toc: true
toc_float: true
---
I was informed by CRAN that my R package had a *stack overflow* problem and that I needed to address this.
This error was not produced during typical compilation or when using valgrind.
I was pretty sure my only path was to use the address sanitizer.
However, I had no experience doing this sort of thing.
Here I've tried to document the process I took with the hope it may help others.
## Links
[Dirk's sanitizers](http://dirk.eddelbuettel.com/code/sanitizers.html)
[Kevin's lldb](http://kevinushey.github.io/blog/2015/04/13/debugging-with-lldb/)
[RMS's gdb tutorial](http://www.unknownroad.com/rtfm/gdbtut/gdbtoc.html)
[rocker-org](https://github.com/rocker-org)
[Debugging_with_AddressSanitizer](https://xstack.exascale-tech.com/wiki/index.php/Debugging_with_AddressSanitizer)
## Why Rocker?
CRAN has documentated use of the address sanitizer in their Writing R extensions document [Using-Address-Sanitizer](https://cran.r-project.org/doc/manuals/r-devel/R-exts.html#Using-Address-Sanitizer).
An important part of enabling the address sanitizer is that R must be built from source with this option enabled.
This is a bit of work.
Docker provides the option of creating a containerized version of R, independent of your system R, for development.
Rocker contains Docker images that are relevant to R, including ones built with the address sanitizer.
So this appears to be an excellent option.
## Docker
The [Docker site](https://docs.docker.com/) has information on installing Docker.
Here we'll assume you have Docker installed.
In Debian-like Linux (including Ubuntu) this can be done as follows.
```{bash, eval = FALSE}
sudo apt install docker.io
```
Once installed, you'll have to make sure the daemon is running.
This can be accomplished with tht below commands.
```{bash, eval = FALSE}
service docker status
service docker start
service docker stop
```
Once running you can test your Docker system with the below commands.
```{bash, eval = FALSE}
sudo docker version
sudo docker ps # Installed images.
sudo docker run hello-world
```
Help can be found by adding 'help' to a command.
```{bash, eval = FALSE}
sudo docker --help
sudo docker run --help
```
And search for rocker on Docker Hub.
```{bash, eval = FALSE}
sudo docker search rocker
```
When we find an image we're interested in we can run it with the following.
```{bash, eval = FALSE}
sudo docker run --name=my-r-base --rm -ti rocker/r-base /bin/bash
```
This command included a few options.
The `run` command runs the image.
If it is not found locally, or needs to be updated, it is done automatically for you.
The `--name=` option allows you to assign a name to the container.
If you don't assign one it will be done automatically for you.
The `--rm` option automatically removes the container for you when you exit.
The `-ti` options allocates a pseudo-TTY and provides an interactive session.
The name of the image we want to run as a container is `rocker/r-base` and once its started we'll want to execute `/bin/bash` (our shell).
When we've finished our work we can quit with the following.
```{bash, eval = FALSE}
exit
```
Note that when we quit that no changes were made to the image.
If you decide you would like to remove an image it can be done using `rmi`.
```{bash, eval = FALSE}
sudo docker rmi rocker/r-base
```
We typically want to share some data between our host and our container.
Using the `-v` option we can mount a host directory.
Here mount the git repository for my R package as a data volume in the container.
```{bash, eval = FALSE}
sudo docker run --name=my-r-base -v ~/gits/vcfR:/RSource/vcfR --rm -ti rocker/r-base /bin/bash
```
More help on Docker can be found at these links.
[understanding-docker](https://docs.docker.com/engine/understanding-docker/)
[Find and run the whalesay image](https://docs.docker.com/engine/getstarted/step_three/)
[dockervolumes](https://docs.docker.com/engine/tutorials/dockervolumes/)
## Rocker
The Rocker project includes containers for running R.
Some of this is documented here: [Docker for R](http://dirk.eddelbuettel.com/blog/2014/10/23/).
There is also a [Rocker Github](https://github.com/rocker-org/rocker) site for the images and documentation is on the [Rocker wiki](https://github.com/rocker-org/rocker/wiki).
First we may want to make sure we have the most current version of the image.
```{bash, eval = FALSE}
docker pull rocker/r-devel-san
```
We can now start the image.
```{bash, eval = FALSE}
sudo docker run --name=r-devel-san -v ~/gits/vcfR:/RSource/vcfR --rm -ti r-devel-san /bin/bash
```
## Test address sanitizer (ASAN)
Before we invest time in trying to get the address wsanitizer to work within R its a good idea to validate it is working independently of R.
This also provides us with an exampel of its use and behaviour.
On my container we did not appear to have the required software.
We can check for the software as follows.
```{bash, eval = FALSE}
which llvm-symbolizer-3.8
```
Note that your version number may be different than reported here.
Tab completion should work here, if llvm-symbolizer is installed.
So you really only need to type the begining of the word.
If 'which' doesn't find anything then you probably need to install it.
To install the software we can use `apt`.
```{bash, eval = FALSE}
apt-get update
apt-get install llvm
```
And you may need to add a generic link to your version.
```{bash, eval = FALSE}
ln -s /usr/bin/llvm-symbolizer-3.8 /usr/bin/llvm-symbolizer
```
A nice example for learning ASAN can be found [here](http://tsdgeos.blogspot.com/2014/03/asan-and-gcc-how-to-get-line-numbers-in.html).
This example is based on it.
First, we'll create a text file.
```{bash, eval = FALSE}
cat main.cpp
int main(int, char **)
{
int a[3];
a[3] = 4;
return 0;
}
```
Then build it with options to enable the address sanitizer.
```{bash, eval = FALSE}
g++ -fno-omit-frame-pointer -fsanitize=address main.cpp
```
And execute.
```{bash, eval = FALSE}
./a.out
```
At which point a large amount of error information should be printed to the screen.
This illustrates an important difference between using ASAN relative to looking for compile time errors or using valgrind: the program compiles and it is not until execution that it throws the error.
In an R package this means that the package may build but the error may not be be generated until the running of the vignettes, examples or unit tests.
Another issue this should point out is that no line numbers are reported to help us find the error in our source code.
In theory, this is an option we should be able to turn on.
For me, adding `-g3` to increase the debug level seemed to work.
```{bash, eval = FALSE}
g++ -g3 -fno-omit-frame-pointer -fsanitize=address main.cpp
```
And I received line numbers.
## Installing software
Once running I typically find I need to install a few extra applications.
This is done in a similar fashion as you would on a local machine.
```{bash, eval = FALSE}
apt-get update
apt-get install pandoc
apt-get install qpdf
```
If this doess not install the most current version of R you may try [this link])https://askubuntu.com/a/436491).
These help build vignettes.
The installation of llvm should help make our address sanitizer errors more readable.
We can then enter R to install packages.
This may include dependencies of the package we are trying to test.
Note that here we'll use the development verions instead of the stable version by using `Rdevel`.
```{bash, eval = FALSE}
Rdevel
```
Once in R we can install packages as usual.
```{bash, eval = FALSE}
install.packages('poppr')
install.packages('Rcpp')
install.packages('knitr')
install.packages('memuse')
install.packages('rmarkdown')
install.packages('pinfsc50')
install.packages('viridisLite')
install.packages('testthat')
install.packages('tidyr')
```
Once we have all the dependencies we think we need we can exit to the shell.
We could similarly install the packages from the command line.
```{bash, eval = FALSE}
R -e 'install.packages(c("ape", "dplyr", "knitr", "poppr", "Rcpp", "memuse", "pinfsc50", "rmarkdown", "testthat", "tidyr", "vegan", "viridisLite"), lib = "/usr/local/lib/R/library")'
```
### A package finding error
I generated a curious error that took me a bit to track down.
When trying to build my package I generate the below error.
```{bash, eval = FALSE}
Error in loadNamespace(j <- i[[1L]], c(lib.loc, .libPaths()), versionCheck = vI[[j]]) :
there is no package called ‘lattice’
ERROR: lazy loading failed for package ‘vcfR’
```
I say this is curious because when I enter R and try to load this package interactively it seems to work fine.
For some reason it is not found during the build invocation.
I find I can circumvent this issue by moving packages to a specific location.
On my system packages may be located at several locations.
```{bash, eval = FALSE}
.libPaths()
"/usr/local/lib/R/site-library"
"/usr/local/lib/R/library"
"/usr/lib/R/library"
```
I can remove packages and install them to a specific location like this.
```{bash, eval = FALSE}
find.package('lattice')
remove.packages('lattice', lib = "/usr/lib/R/library")
find.package('lattice')
install.packages('lattice', lib = "/usr/local/lib/R/site-library")
```
I find that this issue affects more than one package, so I tend to move everything I can.
Note that you don't want to move the base packages, so I omit them.
```{bash, eval = FALSE}
# base packages, and should not be updated
myBase <- c('base', 'compiler', 'datasets', 'graphics', 'grDevices', 'grid', 'methods', 'parallel', 'splines', 'stats', 'stats4', 'tcltk', 'tools', 'utils')
# First directory
miss.pkgs <- list.files("/usr/lib/R/library")
miss.pkgs <- grep(paste(myBase, collapse = "|"), miss.pkgs, value = TRUE, invert = TRUE)
remove.packages(miss.pkgs, lib = "/usr/lib/R/library")
install.packages(miss.pkgs, lib = "/usr/local/lib/R/library")
# Second directory
miss.pkgs <- list.files("/usr/local/lib/R/site-library")
miss.pkgs <- grep(paste(myBase, collapse = "|"), miss.pkgs, value = TRUE, invert = TRUE)
remove.packages(miss.pkgs, lib = "/usr/local/lib/R/site-library")
install.packages(miss.pkgs, lib = "/usr/local/lib/R/library")
```
Once we have the required dependencies we can build and check our package.
## Build and test package
If you have not mounted a volume containing the package you could download it from CRAN.
```{r, eval = FALSE}
mkdir RSource
cd RSource
wget https://cran.r-project.org/src/contrib/vcfR_1.4.0.tar.gz
tar -xvzf vcfR_1.4.0.tar.gz
cd ..
```
Build and test the package as follows.
```{r, eval = FALSE}
Rdevel CMD build vcfR/
Rdevel CMD check --as-cran vcfR_1.4.0.9000.tar.gz
```
```{}
# Rdevel CMD INSTALL vcfR_1.4.0.9000.tar.gz
# RD CMD build /RSource/vcfR
# RD CMD check --as-cran vcfR_1.4.0.9000.tar.gz
# RD CMD check --no-build-vignettes vcfR_1.4.0.9000.tar.gz
```
I use `testthat` for unit testing.
One of my tests failed.
I can find that output in my tests directory.
```{bash, eval = FALSE}
less vcfR.Rcheck/tests/testthat.Rout.fail
```
This should allow us to reproduce any error reported to us from CRAN.
If we can reproduce the error we should be able to fix it.
If there is a question about how the compiler was called we can check in the log files.
In the file `00install.out` we can validate that the compilation included the correct options.
```{bash, eval = FALSE}
-fsanitize=address -fno-omit-frame-pointer
```
In order to isolate the problem we can install the built package and try to execute the script that threw the error.
```{r, eval = FALSE}
Rdevel CMD INSTALL vcfR_1.4.0.tar.gz
Rscript RSource/vcfR/tests/testthat/test_3_extract_gt.R
```
```{bash, eval = FALSE}
root@f91ccb9ab8cf:/# Rscriptdevel RSource/vcfR/tests/testthat/test_3_extract_gt.R
***** *** vcfR *** *****
This is vcfR 1.4.0
browseVignettes('vcfR') # Documentation
citation('vcfR') # Citation
***** ***** ***** *****
=================================================================
==6066==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffe1d3c3f83 at pc 0x7f22cb00bec0 bp 0x7ffe1d3c3650 sp 0x7ffe1d3c3648
READ of size 1 at 0x7ffe1d3c3f83 thread T0
#0 0x7f22cb00bebf in gt2alleles(Rcpp::String, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >) (/usr/local/lib/R/site-library/vcfR/libs/vcfR.so+0x30bebf)
#1 0x7f22cb014ea1 in extract_GT_to_CM2(Rcpp::Matrix<16, Rcpp::PreserveStorage>, Rcpp::Matrix<16, Rcpp::PreserveStorage>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, int, int) (/usr/local/lib/R/site-library/vcfR/libs/vcfR.so+0x314ea1)
#2 0x7f22cafde0dd in vcfR_extract_GT_to_CM2 (/usr/local/lib/R/site-library/vcfR/libs/vcfR.so+0x2de0dd)
#3 0x7f22da6f126b in do_dotcall (/usr/local/lib/R/lib/libR.so+0xa8226b)
#4 0x7f22da7ed244 in bcEval (/usr/local/lib/R/lib/libR.so+0xb7e244)
#5 0x7f22da82f22f in Rf_eval (/usr/local/lib/R/lib/libR.so+0xbc022f)
#6 0x7f22da839d41 in R_execClosure (/usr/local/lib/R/lib/libR.so+0xbcad41)
#7 0x7f22da82f700 in Rf_eval (/usr/local/lib/R/lib/libR.so+0xbc0700)
#8 0x7f22da843c56 in do_set (/usr/local/lib/R/lib/libR.so+0xbd4c56)
#9 0x7f22da82fc98 in Rf_eval (/usr/local/lib/R/lib/libR.so+0xbc0c98)
#10 0x7f22da83d36d in do_begin (/usr/local/lib/R/lib/libR.so+0xbce36d)
#11 0x7f22da82fc98 in Rf_eval (/usr/local/lib/R/lib/libR.so+0xbc0c98)
#12 0x7f22da847beb in do_eval (/usr/local/lib/R/lib/libR.so+0xbd8beb)
#13 0x7f22da7ed244 in bcEval (/usr/local/lib/R/lib/libR.so+0xb7e244)
#14 0x7f22da82f22f in Rf_eval (/usr/local/lib/R/lib/libR.so+0xbc022f)
#15 0x7f22da839d41 in R_execClosure (/usr/local/lib/R/lib/libR.so+0xbcad41)
#16 0x7f22da8009b7 in bcEval (/usr/local/lib/R/lib/libR.so+0xb919b7)
#17 0x7f22da82f22f in Rf_eval (/usr/local/lib/R/lib/libR.so+0xbc022f)
#18 0x7f22da8323b4 in forcePromise (/usr/local/lib/R/lib/libR.so+0xbc33b4)
#19 0x7f22da833643 in getvar (/usr/local/lib/R/lib/libR.so+0xbc4643)
#20 0x7f22da7fe132 in bcEval (/usr/local/lib/R/lib/libR.so+0xb8f132)
#21 0x7f22da82f22f in Rf_eval (/usr/local/lib/R/lib/libR.so+0xbc022f)
#22 0x7f22da839d41 in R_execClosure (/usr/local/lib/R/lib/libR.so+0xbcad41)
#23 0x7f22da8009b7 in bcEval (/usr/local/lib/R/lib/libR.so+0xb919b7)
#24 0x7f22da82f22f in Rf_eval (/usr/local/lib/R/lib/libR.so+0xbc022f)
#25 0x7f22da8323b4 in forcePromise (/usr/local/lib/R/lib/libR.so+0xbc33b4)
#26 0x7f22da833643 in getvar (/usr/local/lib/R/lib/libR.so+0xbc4643)
#27 0x7f22da7fe132 in bcEval (/usr/local/lib/R/lib/libR.so+0xb8f132)
#28 0x7f22da82f22f in Rf_eval (/usr/local/lib/R/lib/libR.so+0xbc022f)
#29 0x7f22da8323b4 in forcePromise (/usr/local/lib/R/lib/libR.so+0xbc33b4)
#30 0x7f22da833643 in getvar (/usr/local/lib/R/lib/libR.so+0xbc4643)
#31 0x7f22da7fe132 in bcEval (/usr/local/lib/R/lib/libR.so+0xb8f132)
#32 0x7f22da82f22f in Rf_eval (/usr/local/lib/R/lib/libR.so+0xbc022f)
#33 0x7f22da8323b4 in forcePromise (/usr/local/lib/R/lib/libR.so+0xbc33b4)
#34 0x7f22da833643 in getvar (/usr/local/lib/R/lib/libR.so+0xbc4643)
#35 0x7f22da7fe132 in bcEval (/usr/local/lib/R/lib/libR.so+0xb8f132)
#36 0x7f22da82f22f in Rf_eval (/usr/local/lib/R/lib/libR.so+0xbc022f)
#37 0x7f22da8323b4 in forcePromise (/usr/local/lib/R/lib/libR.so+0xbc33b4)
#38 0x7f22da833643 in getvar (/usr/local/lib/R/lib/libR.so+0xbc4643)
#39 0x7f22da7fe132 in bcEval (/usr/local/lib/R/lib/libR.so+0xb8f132)
#40 0x7f22da82f22f in Rf_eval (/usr/local/lib/R/lib/libR.so+0xbc022f)
#41 0x7f22da8323b4 in forcePromise (/usr/local/lib/R/lib/libR.so+0xbc33b4)
#42 0x7f22da833643 in getvar (/usr/local/lib/R/lib/libR.so+0xbc4643)
#43 0x7f22da7fe132 in bcEval (/usr/local/lib/R/lib/libR.so+0xb8f132)
#44 0x7f22da82f22f in Rf_eval (/usr/local/lib/R/lib/libR.so+0xbc022f)
#45 0x7f22da839d41 in R_execClosure (/usr/local/lib/R/lib/libR.so+0xbcad41)
#46 0x7f22da8009b7 in bcEval (/usr/local/lib/R/lib/libR.so+0xb919b7)
#47 0x7f22da82f22f in Rf_eval (/usr/local/lib/R/lib/libR.so+0xbc022f)
#48 0x7f22da839d41 in R_execClosure (/usr/local/lib/R/lib/libR.so+0xbcad41)
#49 0x7f22da8009b7 in bcEval (/usr/local/lib/R/lib/libR.so+0xb919b7)
#50 0x7f22da82f22f in Rf_eval (/usr/local/lib/R/lib/libR.so+0xbc022f)
#51 0x7f22da839d41 in R_execClosure (/usr/local/lib/R/lib/libR.so+0xbcad41)
#52 0x7f22da8009b7 in bcEval (/usr/local/lib/R/lib/libR.so+0xb919b7)
#53 0x7f22da82f22f in Rf_eval (/usr/local/lib/R/lib/libR.so+0xbc022f)
#54 0x7f22da8323b4 in forcePromise (/usr/local/lib/R/lib/libR.so+0xbc33b4)
#55 0x7f22da833643 in getvar (/usr/local/lib/R/lib/libR.so+0xbc4643)
#56 0x7f22da7fe132 in bcEval (/usr/local/lib/R/lib/libR.so+0xb8f132)
#57 0x7f22da82f22f in Rf_eval (/usr/local/lib/R/lib/libR.so+0xbc022f)
#58 0x7f22da8323b4 in forcePromise (/usr/local/lib/R/lib/libR.so+0xbc33b4)
#59 0x7f22da833643 in getvar (/usr/local/lib/R/lib/libR.so+0xbc4643)
#60 0x7f22da7fe132 in bcEval (/usr/local/lib/R/lib/libR.so+0xb8f132)
#61 0x7f22da82f22f in Rf_eval (/usr/local/lib/R/lib/libR.so+0xbc022f)
#62 0x7f22da839d41 in R_execClosure (/usr/local/lib/R/lib/libR.so+0xbcad41)
#63 0x7f22da8009b7 in bcEval (/usr/local/lib/R/lib/libR.so+0xb919b7)
#64 0x7f22da82f22f in Rf_eval (/usr/local/lib/R/lib/libR.so+0xbc022f)
#65 0x7f22da839d41 in R_execClosure (/usr/local/lib/R/lib/libR.so+0xbcad41)
#66 0x7f22da8009b7 in bcEval (/usr/local/lib/R/lib/libR.so+0xb919b7)
#67 0x7f22da82f22f in Rf_eval (/usr/local/lib/R/lib/libR.so+0xbc022f)
#68 0x7f22da839d41 in R_execClosure (/usr/local/lib/R/lib/libR.so+0xbcad41)
#69 0x7f22da8009b7 in bcEval (/usr/local/lib/R/lib/libR.so+0xb919b7)
#70 0x7f22da82f22f in Rf_eval (/usr/local/lib/R/lib/libR.so+0xbc022f)
#71 0x7f22da839d41 in R_execClosure (/usr/local/lib/R/lib/libR.so+0xbcad41)
#72 0x7f22da8009b7 in bcEval (/usr/local/lib/R/lib/libR.so+0xb919b7)
#73 0x7f22da82f22f in Rf_eval (/usr/local/lib/R/lib/libR.so+0xbc022f)
#74 0x7f22da839d41 in R_execClosure (/usr/local/lib/R/lib/libR.so+0xbcad41)
#75 0x7f22da82f700 in Rf_eval (/usr/local/lib/R/lib/libR.so+0xbc0700)
#76 0x7f22da83d36d in do_begin (/usr/local/lib/R/lib/libR.so+0xbce36d)
#77 0x7f22da82fc98 in Rf_eval (/usr/local/lib/R/lib/libR.so+0xbc0c98)
#78 0x7f22da839d41 in R_execClosure (/usr/local/lib/R/lib/libR.so+0xbcad41)
#79 0x7f22da82f700 in Rf_eval (/usr/local/lib/R/lib/libR.so+0xbc0700)
#80 0x7f22da8d651d in Rf_ReplIteration (/usr/local/lib/R/lib/libR.so+0xc6751d)
#81 0x7f22da8d7218 in R_ReplConsole (/usr/local/lib/R/lib/libR.so+0xc68218)
#82 0x7f22da8d7327 in run_Rmainloop (/usr/local/lib/R/lib/libR.so+0xc68327)
#83 0x55bbbebad9f9 in main (/usr/local/lib/R/bin/exec/R+0x9f9)
#84 0x7f22d89ae2b0 in __libc_start_main (/usr/lib/x86_64-linux-gnu/libc.so.6+0x202b0)
#85 0x55bbbebada49 in _start (/usr/local/lib/R/bin/exec/R+0xa49)
Address 0x7ffe1d3c3f83 is located in stack of thread T0 at offset 579 in frame
#0 0x7f22cb0082af in gt2alleles(Rcpp::String, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >) (/usr/local/lib/R/site-library/vcfR/libs/vcfR.so+0x3082af)
This frame has 9 object(s):
[32, 36) 'unphased_as_na'
[96, 100) 'allele_number'
[160, 168) '__size'
[224, 232) '__osize'
[288, 312) 'gt_vector'
[352, 376) 'delim_vector'
[416, 448) 'sep'
[480, 512) 'na_allele'
[544, 576) 'gt2' <== Memory access at offset 579 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow (/usr/local/lib/R/site-library/vcfR/libs/vcfR.so+0x30bebf) in gt2alleles(Rcpp::String, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >)
Shadow bytes around the buggy address:
0x100043a707a0: 00 00 00 00 00 00 00 00 f1 f1 f1 f1 04 f4 f4 f4
0x100043a707b0: f2 f2 f2 f2 04 f4 f4 f4 f2 f2 f2 f2 00 f4 f4 f4
0x100043a707c0: f2 f2 f2 f2 00 f4 f4 f4 f2 f2 f2 f2 00 00 00 f4
0x100043a707d0: f2 f2 f2 f2 00 00 00 f4 f2 f2 f2 f2 00 00 00 00
0x100043a707e0: f2 f2 f2 f2 00 00 00 00 f2 f2 f2 f2 00 00 00 00
=>0x100043a707f0:[f3]f3 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00
0x100043a70800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100043a70810: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100043a70820: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100043a70830: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100043a70840: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Heap right redzone: fb
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack partial redzone: f4
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==6066==ABORTING
root@f91ccb9ab8cf:/#
```
This reproduces the error we're looking for.
(We knew which file it was from the report on CRAN.)
We should now be able to isolate the offending commands in this file.
This tells us at least two important issues with our code.
First, the problem is in the function `gt2alleles()`.
Second, the issue is with the object `gt2`.
However, this does not pinpoint the problem.
In order to accomplish that, we'll need to use a debugger.
```{bash, eval = FALSE}
shell> Rdevel -d gdb
(gdb) run
R> library(vcfR)
<Crtl + c>
(gdb) b gt2alleles
(gdb) c
```
We can now copy and paste our offending code into the terminal.
```{bash, eval = FALSE}
R> data(vcfR_example)
R> chrom <- create.chromR(name="Chrom", vcf=vcf, seq=dna, ann=gff, verbose=FALSE)
R> chrom <- masker(chrom, min_DP = 1e3, max_DP = 2e3)
R> # This is where our problem is.
R> gt <- extract.gt(chrom, element="GT", return.alleles = TRUE)
(gdb) s
(gdb) n
info args
print gt
print allele_vector
(gdb) fr v
(gdb) finish
(gdb) quit
```
```{bash, eval = FALSE}
quit
```
We can enter the R environment and copy and paste the lines of our test into the console until we generate our error.
```{bash, eval = FALSE}
Rdevel
#Rscriptdevel -e ''
#Rscriptdevel -e 'library(vcfR); '
```
Once we have found the offending line we'll want to use a debugger to step isolate the code at issue.
Kevin Ushey has put together a nice post called [Debugging with LLDB](http://kevinushey.github.io/blog/2015/04/13/debugging-with-lldb/) which addresses the use of lldb which is very similar to gdb.
[GDB with Python 2.7 in Ubuntu](https://gist.github.com/posquit0/93200f7ca1ad3d0c943c)
[PPA for eric fortin ](https://code.launchpad.net/~nitrof22/+archive/ubuntu/ppa)
```{bash, eval = FALSE}
sudo docker run --name=my-r-devel-ubsan-clang -v ~/gits/vcfR:/RSource/vcfR --rm -ti rocker/r-devel-ubsan-clang /bin/bash
apt-get update
apt-get install gdb
R -d lldb
```
Version: 1.0
RestoreWorkspace: Default
SaveWorkspace: Default
AlwaysSaveHistory: Default
EnableCodeIndexing: Yes
UseSpacesForTab: Yes
NumSpacesForTab: 2
Encoding: UTF-8
RnwWeave: Sweave
LaTeX: pdfLaTeX
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment