AddressSanitizer拦截__isoc99_sprintf时栈溢出崩溃的解决办法
问题解决方案与分析
核心问题根源
你遇到的崩溃是由于混合编译的ELF文件包含GCC 4.4.7(早于ASAN集成的GCC 4.8版本)编译的代码,导致libasan在拦截__isoc99_sprintf符号时,触发了dlsym/_dlerror_run/free的递归调用循环——ASAN尝试查找原函数时调用了dlsym,而dlsym依赖的free又被ASAN拦截,进而再次触发符号查找,最终栈溢出崩溃。
具体解决方法
1. 修正ASAN_OPTIONS的函数拦截排除配置
之前取消拦截失败大概率是参数格式错误,尝试以下两种正确配置:
- 直接禁用
sprintf系列函数的拦截:ASAN_OPTIONS=intercept_sprintf=0 LD_PRELOAD=/usr/lib64/libasan.so.5 ./your_program - 精确排除
__isoc99_sprintf:
注:ASAN_OPTIONS=exclude_functions=__isoc99_sprintf LD_PRELOAD=/usr/lib64/libasan.so.5 ./your_programlibasan.so.5对应GCC 8.5版本的ASAN库,路径需根据实际系统调整。
2. 重新编译老代码模块(最彻底方案)
将所有用GCC 4.4.7编译的代码模块,改用GCC 8.5重新编译,并添加ASAN编译选项:
gcc -fsanitize=address -O1 -g your_old_module.c -c -o your_old_module.o
然后重新链接整个程序,确保所有模块都与GCC 8.5的libasan兼容——老GCC编译的代码无ASAN instrumentation,与新libasan的符号拦截逻辑天然冲突,重编译可彻底消除这类问题。
3. 调整动态加载顺序避免递归循环
尝试让系统libdl优先于libasan加载,避免ASAN拦截dlsym时触发递归:
LD_PRELOAD=/lib64/libdl.so.2:/usr/lib64/libasan.so.5 ./your_program
可配合LD_DEBUG=symbols查看符号解析过程,确认是否存在符号优先级冲突:
LD_DEBUG=symbols ASAN_OPTIONS=verbosity=2 LD_PRELOAD=/lib64/libdl.so.2:/usr/lib64/libasan.so.5 ./your_program
4. 使用静态链接的ASAN
编译时改用静态链接ASAN,避免动态加载时的符号冲突:
gcc -fsanitize=address -static-libasan your_program.c -o your_program
静态链接会将ASAN逻辑直接嵌入程序,减少动态符号解析的不确定性,但需注意静态链接可能不支持某些系统功能(如动态加载其他库)。
其他可能的排查方向
- 检查符号版本冲突:用
readelf -s your_program | grep __isoc99_sprintf查看该符号的版本信息,确认是否存在新旧GCC版本的符号共存问题,可通过LD_VERSION_MASK环境变量限制符号版本。 - 排查自定义重载函数:用
nm your_program | grep -E 'dlsym|free'检查程序是否重载了dlsym或free,这类自定义函数会与ASAN的拦截逻辑直接冲突,需修改代码移除重载。
内容的提问来源于stack exchange,提问作者joepol
相关产品推荐
相关产品推荐

