如何在Rust中重写AddressSanitizer回调函数__asan_on_error?
在Rust中重写AddressSanitizer回调函数的问题与解决方法
问题分析
你遇到的核心问题是:Rust代码中标记了#[no_mangle]和pub extern "C"的__asan_on_error函数未被ASan识别,等价C++代码却能正常触发自定义回调。这是因为Rust的链接顺序与ASan库的初始化逻辑冲突——ASan的默认实现会优先于你的自定义函数被链接,从而覆盖了你的实现。
解决方案
可以在Rust中重写ASan回调,只需调整编译链接规则,确保自定义函数优先被ASan库加载:
1. 修正函数签名
ASan的__asan_on_error标准签名返回类型为void,修正后的Rust代码如下:
use std::hint::black_box; use libc; #[no_mangle] pub extern "C" fn __asan_on_error() { std::process::abort(); } fn main() { let ptr = Box::into_raw(Box::new(1)); unsafe { drop(Box::from_raw(ptr)) }; black_box(unsafe { *black_box(ptr) } + 1); }
2. 调整编译链接选项
针对aarch64-apple-darwin目标,需要通过链接参数强制优先加载你的自定义符号。修改运行命令为:
RUSTFLAGS="-Z sanitizer=address -Clink-arg=-Wl,-force_load,$(rustc --print sysroot)/lib/rustlib/aarch64-apple-darwin/lib/librustc_driver-*.dylib" cargo run --profile=dev --target aarch64-apple-darwin
-Wl,-force_load参数会告诉macOS的ld64链接器强制加载指定库中的符号,确保你的__asan_on_error优先于ASan库的默认实现被解析。
3. 验证效果
修改后运行程序,ASan检测到错误时会立即触发abort(),不会输出完整的错误日志,行为与C++版本一致。
原因说明
C++编译时,自定义回调函数在主编译单元中,链接器会优先选择当前单元的符号;而Rust编译流程中,ASan库的链接时机更早,默认实现被优先使用。通过强制加载自定义符号,就能覆盖ASan的默认回调。
你调用__asan_describe_address等函数正常工作,是因为这些是主动调用ASan库的API,不存在符号覆盖的链接顺序问题。
内容的提问来源于stack exchange,提问作者Jeonghyeon Kim
相关产品推荐
相关产品推荐

