如何为Ruby Nokogiri Gem正确启用Address Sanitizer
正确为Ruby及Nokogiri Gem启用Address Sanitizer的方法
我来帮你梳理一套能解决问题的完整流程——你之前遇到的符号未定义、ASan加载顺序错误,核心原因是Ruby、libxml2、libxslt、Nokogiri这几个组件必须用完全一致的ASan编译参数构建,不能只给其中一部分加ASan。下面是分步操作:
第一步:编译带ASan的Ruby
首先得让Ruby本身链接ASan运行时,不然后续扩展加载时肯定会出问题。这里以Ruby 2.5.0为例(你可以换成自己需要的版本):
# 进入Ruby源码目录 cd ruby-2.5.0 # 配置编译参数:禁用共享库避免冲突,用clang编译(ASan对clang支持更好) ./configure --disable-shared \ CFLAGS="-fsanitize=address,undefined -ggdb -O0" \ CXXFLAGS="-fsanitize=address,undefined -ggdb -O0" \ LDFLAGS="-fsanitize=address,undefined" \ CC=clang CXX=clang++ # 编译安装,-j$(nproc)是用满CPU核心加速 make -j$(nproc) sudo make install
小贴士:加
-O0是为了关闭优化,让ASan的错误报告更准确;--disable-shared能避免动态链接带来的ASan版本冲突问题。
第二步:编译带ASan的libxml2和libxslt
这两个库必须和Ruby用一样的ASan参数,而且最好安装到独立路径,别覆盖系统默认库:
编译libxml2
cd libxml2-2.9.3 ./configure \ --prefix=/usr/local/asan-libs \ # 指定独立安装路径 CFLAGS="-fsanitize=address,undefined -ggdb -O0 -Wformat -Werror=format-security -Werror=array-bounds" \ CXXFLAGS="-fsanitize=address,undefined -ggdb -O0 -Wformat -Werror=format-security -Werror=array-bounds" \ LDFLAGS="-fsanitize=address,undefined" \ CC=clang CXX=clang++ make -j$(nproc) sudo make install
编译libxslt
cd libxslt-1.1.28 ./configure \ --prefix=/usr/local/asan-libs \ --with-libxml-prefix=/usr/local/asan-libs \ # 依赖我们刚编译的带ASan的libxml2 CFLAGS="-fsanitize=address,undefined -ggdb -O0" \ CXXFLAGS="-fsanitize=address,undefined -ggdb -O0" \ LDFLAGS="-fsanitize=address,undefined" \ CC=clang CXX=clang++ make -j$(nproc) sudo make install
第三步:安装带ASan的Nokogiri
现在用刚编译好的Ruby来装Nokogiri,指定用我们自己编译的带ASan的库:
# 确保用的是刚装的Ruby的gem命令,可先用which gem确认路径是/usr/local/bin/gem gem install nokogiri --version 1.8.0 \ -- --use-system-libraries \ --with-xml2-include=/usr/local/asan-libs/include/libxml2 \ --with-xml2-lib=/usr/local/asan-libs/lib \ --with-xslt-include=/usr/local/asan-libs/include \ --with-xslt-lib=/usr/local/asan-libs/lib \ --with-cflags="-fsanitize=address,undefined -ggdb -O0" \ --with-ldflags="-fsanitize=address,undefined"
注意:这里不用手动加
-lasan或-lubsan,-fsanitize=address,undefined会自动帮你链接对应的运行时库。
第四步:运行脚本验证
直接用刚编译的Ruby运行脚本就行,不需要手动设LD_PRELOAD(因为Ruby已经自带ASan运行时了):
# 如果你的ASan库路径没在系统默认搜索里,先加一下 export LD_LIBRARY_PATH=/usr/local/asan-libs/lib:$LD_LIBRARY_PATH # 运行脚本 /usr/local/bin/ruby script.rb
如果一切正常,ASan会在检测到内存泄漏、越界等问题时输出详细报告。
针对你遇到的问题的额外说明
ASan runtime does not come first in initial library list:这是因为你之前用的是系统Ruby(没链接ASan),预加载ASan会导致加载顺序混乱。解决方法就是用自己编译的带ASan的Ruby,从根源避免这个问题。undefined symbol: __asan_init:这个是因为有的组件(比如Ruby、libxml2或Nokogiri)没加ASan编译,导致符号不匹配。必须确保所有相关组件都用同样的ASan参数编译。- 编译Ruby时ASan报内存泄漏:旧版本Ruby本身可能存在一些已知的内存泄漏,这是正常的,只要Ruby能编译完成就不用管,我们的目标是用ASan检测Nokogiri的问题。
内容的提问来源于stack exchange,提问作者dev
相关产品推荐
相关产品推荐

