M1 Mac Monterey clang使用Memory/Leak Sanitizer报错解决
你碰到的clang: error: unsupported option '-fsanitize=memory' for target 'arm64-apple-darwin21.2.0'报错,核心原因是Apple官方提供的系统Clang从未支持MemorySanitizer(MSan),Homebrew源内旧版本LLVM也默认未编译适配arm64 Darwin平台的MSan运行时;LeakSanitizer(LSan)在M1芯片的macOS上也需要额外配置环境变量才能正常运行,并非安装完LLVM即可直接调用。
系统自带Clang永远无法支持MSan,首先要确保终端默认调用的是Homebrew安装的LLVM:
- 执行
which clang检查当前Clang路径,如果返回/usr/bin/clang,说明当前调用的是系统自带Clang,需要先把Homebrew LLVM路径加入PATH优先级最高的位置。 - 编辑zsh(macOS Monterey默认Shell)配置文件
~/.zshrc,加入以下配置:export PATH="/opt/homebrew/opt/llvm/bin:$PATH" - 保存后执行
source ~/.zshrc,再执行clang --version,确认输出为Homebrew分发的LLVM版本,而非Apple clang版本即可。如果版本低于14.0,先执行brew upgrade llvm升级到最新版,低版本对arm64平台的sanitizer支持存在已知Bug。
MSan要求所有和程序链接的依赖库(包括C/C标准库)都必须经过MSan插桩编译,否则会出现大量假阳性报错,Homebrew版LLVM默认携带的libc未做MSan插桩,需要自行编译:
- 创建临时编译目录,拉取LLVM运行时编译配置:
mkdir -p ~/llvm-msan-build && cd ~/llvm-msan-build cmake -G Ninja /opt/homebrew/opt/llvm/lib/cmake/llvm \ -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi" \ -DCMAKE_BUILD_TYPE=Release \ -DLLVM_USE_SANITIZER=MemoryWithOrigins \ -DCMAKE_PREFIX_PATH=/opt/homebrew/opt/llvm - 执行编译,等待生成插桩版的libc++、libc++abi文件:
ninja cxx cxxabi - 编译自己的C/C++程序时,指定使用刚才编译的插桩版标准库,示例命令:
clang -fsanitize=memory -fno-omit-frame-pointer -g \ -stdlib=libc++ \ -nostdinc++ -I$HOME/llvm-msan-build/include/c++/v1 \ -L$HOME/llvm-msan-build/lib -Wl,-rpath,$HOME/llvm-msan-build/lib \ test.c -o test_msan
注意:程序依赖的所有第三方动态库、静态库,都必须使用相同的MSan编译参数重新构建,否则检测结果不具备参考价值。
LSan不需要额外编译运行时,最新版Homebrew LLVM已经自带适配arm64 Monterey的LSan组件,仅需两个配置即可正常使用:
- 编译程序时加上LSan参数,示例:
clang -fsanitize=leak -g -fno-omit-frame-pointer test.c -o test_lsan - 运行编译好的程序前,先执行以下命令关闭系统内存分配器的nano zone特性,避免权限问题导致的检测失败或假阳性:
export MallocNanoZone=0
如果不需要专门检测未初始化内存读取这类只有MSan能覆盖的问题,日常内存问题排查优先使用AddressSanitizer(ASan):该工具在M1 Mac上被系统Clang和Homebrew LLVM直接支持,不需要额外编译任何依赖,加-fsanitize=address参数即可编译使用,可覆盖释放后使用、堆溢出、栈溢出等绝大多数内存错误,也可以直接和LSan组合使用,参数为-fsanitize=address,leak,配置成本远低于MSan。
内容的提问来源于stack exchange,提问作者AMara

