R package的UBSAN测试
How to perform UBSAN tests on R packages
最近需要提交一个R package (seqminer)到CRAN,我们需要保证这个包代码通过UBSAN 测试(Undefined bahavior sanitizer tests,详见这个链接).
这个测试可以有效的检测结果不确定的指令(例如打印INT_MAX+1)。
目前只有Clang(版本3.3以后)才能支持UBSAN。为了对R package进行UBSAN测试,我们首先需要一个特殊的R版本,即用打开UBSAN支持(-fsanitize=undefined)的Clang编译的R。参考了网上一篇Blog,写一下简单步骤:
1. 下载编译工具
1 2 | sudo apt-get install valgrind subversion r-base-dev clang-3.4 texlive-fonts-extra texlive-latex-extra sudo apt-get build-dep cran-base |
2. 下载R源代码(devel版本)
1 | svn co https: //svn .r-project.org /R/trunk ~ /R-devel |
3. 替换R-devel/config.site
1 2 3 4 5 6 7 8 | CC= "clang -std=gnu99 -fsanitize=undefined" CFLAGS= "-fno-omit-frame-pointer -Wall -pedantic -mtune=native" F77= "gfortran" LIBnn= "lib64" LDFLAGS= "-L/usr/local/lib64 -L/usr/local/lib" CXX= "clang++ -std=c++11 -fsanitize=undefined" CXXFLAGS= "-fno-omit-frame-pointer -Wall -pedantic -mtune=native" FC=${F77} |
4. 编译
1 2 3 | cd R-devel . /configure --with-x=no --without-recommended-packages make |
这里–without-recommended-packages会省略一些R的packages(例如boot,nlme,Matrix) 以提升编译速度。如果不用这个选项,我发现Matrix package总是没法编译
5. 建立~/.R/Makevars
1 2 3 | CC = clang -std=gnu99 -fsanitize=undefined -fno-omit-frame-pointer CXX = clang++ -fsanitize=undefined -fno-omit-frame-pointer PKG_LIBS = /usr/lib/llvm-3 .4 /lib/clang/3 .4 /lib/linux/libclang_rt .ubsan_cxx-x86_64.a |
这里CXX 一定要用clang++,如果用clang的话会出现链接错误,比如找不到这个符号: _ZTVN10__cxxabiv117__class_type_infoE
这里还需要指定PKG_LIBS包括LLVM的库文件,不然就找不到UBSAN的符号。
6. 测试package
1 2 | R CMD build seqminer/ R CMD check seqminer_2.7. tar .gz |
UBSAN测试的结果会显示在:seqminer.Rcheck/tests/tests.Rout
如果有错误,你会看很长的一行, runtime error….
其他技巧
检测内存还可以用valgrind:
1 2 3 | R CMD check --use-valgrind seqminer_2.7. tar .gz R -d valgrind --vanilla < mypkg-Ex.R R -d "valgrind --tool=memcheck --leak-check=full" --vanilla < mypkg-Ex.R |