You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Clang AddressSanitizer未检测到代码中的释放后使用问题?

为什么Clang AddressSanitizer未检测到已释放缓冲区的访问?

问题背景

我尝试使用Clang AddressSanitizer检测内存错误,但遇到了一个奇怪的情况:以下示例代码中rel_filename指向已释放的缓冲区内部,将其传入printf后却未触发异常,这是否合理?

测试代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char **argv) {
    char *dir;
    char *abs_filename;
    char *rel_filename;

    abs_filename = (char *) malloc( strlen(argv[1]) + 1 );
    strcpy( abs_filename, argv[1] );

    if (strchr( abs_filename, '/' )) {
        char *tmp = strrchr( abs_filename, '/' );
        dir = (char *) malloc( tmp-abs_filename+1 );
        *tmp = 0;
        strcpy( dir, abs_filename );
        rel_filename = tmp+1;
        free(abs_filename);
    } else {
        rel_filename = abs_filename;
        dir = NULL;
    }

    if (dir) printf("directory is: %s\n",dir);
    if (rel_filename) printf("filenmae is: %s\n",rel_filename);

    return 0;
}

编译与调用步骤

编译成目标文件:

$ clang -O1 -g -fsanitize=address -fno-omit-frame-pointer -c main.c -o main.o

链接生成可执行文件:

$ clang -g -fsanitize=address main.o -o main

运行结果(未触发任何异常):

$ ./main /home/oren/ggg.txt
directory is: /home/oren
filenmae is: ggg.txt

环境信息

  • Clang版本:
$ clang --version
clang version 3.4.2 (tags/RELEASE_342/final 322618)
Target: x86_64-unknown-linux-gnu
Thread model: posix
  • 操作系统:
Ubuntu 14.04.5 (LTS) 64 bit

问题分析与解答

你遇到的这个情况确实反直觉——从代码逻辑来看,rel_filename明确指向了已被free的abs_filename缓冲区内部,属于典型的use-after-free内存错误,理论上AddressSanitizer(ASan)应该触发异常。但实际运行没报错,主要原因如下:

1. Clang 3.4的ASan版本过于陈旧

你使用的Clang 3.4是2014年的老版本,而ASan是一个持续迭代优化的工具。早期版本的ASan对某些use-after-free场景的检测存在遗漏,尤其是当访问的是已释放内存块的中间部分时,可能没有被正确标记为“有毒”内存。后续的Clang版本(比如Clang 10及以上)对这类场景的检测做了大量改进,基本能稳定捕获这类错误。

2. 优化级别与ASan的交互问题

你使用了-O1优化,虽然ASan通常和-O1兼容,但旧版本的编译器可能在优化过程中,对指针的跟踪出现偏差,导致ASan无法正确识别这个use-after-free操作。你可以尝试改用-O0重新编译运行,看看是否能触发检测。

3. 验证ASan是否正常工作

为了确认你的ASan环境是否正常,可以先写一个简单的use-after-free测试用例:

#include <stdlib.h>
int main() {
    char* ptr = malloc(10);
    free(ptr);
    *ptr = 'a'; // 明确的use-after-free
    return 0;
}

用同样的编译命令编译运行,如果这个例子能触发ASan报错,说明你的ASan环境是正常的,问题就出在旧版本对特定场景的检测遗漏上。

解决建议

最直接的解决方案是升级你的Clang版本,比如安装Ubuntu仓库中的较新版本(或者通过LLVM官网下载预编译包)。新版本的ASan不仅能捕获这类use-after-free错误,还能提供更清晰的错误堆栈信息,帮助你定位问题。

另外,你也可以尝试在free(abs_filename)之后,手动写入一些数据到abs_filename指向的内存(虽然这本身也是未定义行为,但可以验证ASan是否能检测到后续的访问):

free(abs_filename);
memset(abs_filename, 0, strlen(argv[1]) + 1); // 写入已释放内存

如果这样操作后ASan触发了错误,也能侧面说明旧版本对原场景的检测不够敏感。


内容的提问来源于stack exchange,提问作者OrenIshShalom

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:22:54