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. 下载编译工具
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版本)
svn co https://svn.r-project.org/R/trunk ~/R-devel
3. 替换R-devel/config.site
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. 编译
cd R-devel ./configure --with-x=no --without-recommended-packages make
这里–without-recommended-packages会省略一些R的packages(例如boot,nlme,Matrix) 以提升编译速度。如果不用这个选项,我发现Matrix package总是没法编译
5. 建立~/.R/Makevars
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
R CMD build seqminer/ R CMD check seqminer_2.7.tar.gz
UBSAN测试的结果会显示在:seqminer.Rcheck/tests/tests.Rout
如果有错误,你会看很长的一行, runtime error….
其他技巧
检测内存还可以用valgrind:
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