Last active
March 19, 2019 15:27
-
-
Save knausb/0787d74bdbe3195cd02a48d30ee9c73b to your computer and use it in GitHub Desktop.
rocker_asan
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.Rproj.user | |
.Rhistory | |
.RData | |
.Ruserdata | |
*.html |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- | |
title: Address sanitizer in Rocker | |
author: Brian J. Knaus | |
license: GPL (>= 2) | |
--- | |
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. | |
## 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 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 one 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 uopdated, 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} | |
quit | |
``` | |
Note that when we quit that no changes made to the container are made to the image. | |
If you decide you would like to remove an image it can be done as follows. | |
```{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 my git repository, 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 here. | |
[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). | |
### Running a Rocker image | |
```{bash, eval = FALSE} | |
sudo docker run --name=my-r-devel-san -v ~/gits/vcfR:/RSource/vcfR --rm -ti rocker/r-devel-san /bin/bash | |
``` | |
### Test ASAN | |
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). | |
Create a text file. | |
```{bash, eval = FALSE} | |
cat main.cpp | |
int main(int, char **) | |
{ | |
int a[3]; | |
a[3] = 4; | |
return 0; | |
} | |
``` | |
Build. | |
```{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 versus looking for compile time errors or using valgrind: the program compiles and it is not untill execution that it throws the error. | |
In an R package this means that the package may build but the error may be generated when building 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. | |
In the file `00install.out` we can validate that the compilation included | |
```{bash, eval = FALSE} | |
-fsanitize=address -fno-omit-frame-pointer | |
``` | |
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 application. | |
This is done in a similar fashion as you would on a local machine. | |
```{bash, eval = FALSE} | |
apt-get install qpdf | |
# apt-get install pandoc | |
# apt-get install llvm | |
``` | |
The installation of llvm should help make our address sanitizer errors more readable. | |
We can then enter R to install packages. | |
Note that here we'll use the development verions instead of the stable version by using `RD`. | |
```{bash, eval = FALSE} | |
RD | |
``` | |
Now 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') | |
``` | |
Or from the command line. | |
```{bash, eval = FALSE} | |
R -e 'install.packages(c("poppr", "Rcpp", "knitr", "memuse", "rmarkdown", "pinfsc50", "viridisLite", "testthat", "tidyr"))' | |
``` | |
Once we have all the dependencies we think we need we can exit to the shell. | |
We can now build and check our package. | |
```{bash, eval = FALSE} | |
# ASAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolizer-3.8 | |
ln -s /usr/bin/llvm-symbolizer-3.8 /usr/bin/llvm-symbolizer | |
# ASAN_OPTIONS=symbolize=1 | |
# ASAN_SYMBOLIZER_PATH=$(which llvm-symbolizer) | |
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 | |
``` | |
Hmm, periods in code chuncks appear to be a problem. | |
Commenting the lines circumvents the issue for now. | |
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 file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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