使用MinGW-w64的Clang 8:如何使用地址和UB消毒器?

Hol*_*Cat 9 c++ clang mingw-w64 address-sanitizer ubsan

Clang 8发行说明中有以下内容:

  • 允许在MinGW上使用Address Sanitizer和Undefined Behavior Sanitizer。

但是,我无法弄清楚如何正确使用它们。

我将Clang 8.0.0与MSYS2 MinGW GCC结合使用。确切的细节在问题的底部。

我正在尝试编译以下最少的代码:

1.cpp

#include <iostream>

int main()
{
    // Testing ubsan
    int x = 0x7fffffff;
    x++;
    std::cout << x << std::endl;

    // Testing asan
    int *y = new int;
    delete y;
    std::cout << *y << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

以下是结果-fsanitize=address

# /z/Lander/LLVM/bin/clang++ -target x86_64-w64-windows-gnu -fsanitize=address 1.cpp
Z:\Lander\msys2\mingw64\bin\ld.exe: cannot find Z:\Lander\LLVM\lib\clang\8.0.0\lib\windows\libclang_rt.asan_dynamic-x86_64.dll.a: No such file or directory
Z:\Lander\msys2\mingw64\bin\ld.exe: cannot find Z:\Lander\LLVM\lib\clang\8.0.0\lib\windows\libclang_rt.asan_dynamic_runtime_thunk-x86_64.a: No such file or directory
Z:\Lander\msys2\mingw64\bin\ld.exe: cannot find Z:\Lander\LLVM\lib\clang\8.0.0\lib\windows\libclang_rt.asan_dynamic_runtime_thunk-x86_64.a: No such file or directory
clang++: error: linker command failed with exit code 1 (use -v to see invocation)
Run Code Online (Sandbox Code Playgroud)

这里是-fsanitize=undefined

# /z/Lander/LLVM/bin/clang++ -target x86_64-w64-windows-gnu -fsanitize=undefined 1.cpp
Warning: corrupt .drectve at end of def file
Z:\Lander\msys2\tmp\1-13f09e.o:1.cpp:(.text+0x9f): undefined reference to `__ubsan_handle_add_overflow'
Z:\Lander\msys2\tmp\1-13f09e.o:1.cpp:(.text+0xef): undefined reference to `__ubsan_handle_type_mismatch_v1'
Z:\Lander\msys2\tmp\1-13f09e.o:1.cpp:(.text+0x148): undefined reference to `__ubsan_handle_type_mismatch_v1'
Z:\Lander\msys2\tmp\1-13f09e.o:1.cpp:(.text+0x196): undefined reference to `__ubsan_handle_type_mismatch_v1'
Z:\Lander\msys2\tmp\1-13f09e.o:1.cpp:(.text+0x1df): undefined reference to `__ubsan_handle_type_mismatch_v1'
Z:\Lander\msys2\tmp\1-13f09e.o:1.cpp:(.text+0x22c): undefined reference to `__ubsan_handle_type_mismatch_v1'
clang++: error: linker command failed with exit code 1 (use -v to see invocation)
Run Code Online (Sandbox Code Playgroud)

以下是Z:\Lander\LLVM\lib\clang\8.0.0\lib\windows\查找库的内容:

clang_rt.asan-preinit-x86_64.lib
clang_rt.asan-x86_64.lib
clang_rt.asan_cxx-x86_64.lib
clang_rt.asan_dll_thunk-x86_64.lib
clang_rt.asan_dynamic-x86_64.dll
clang_rt.asan_dynamic-x86_64.lib
clang_rt.asan_dynamic_runtime_thunk-x86_64.lib
clang_rt.builtins-x86_64.lib
clang_rt.fuzzer-x86_64.lib
clang_rt.fuzzer_no_main-x86_64.lib
clang_rt.profile-x86_64.lib
clang_rt.stats-x86_64.lib
clang_rt.stats_client-x86_64.lib
clang_rt.ubsan_standalone-x86_64.lib
clang_rt.ubsan_standalone_cxx-x86_64.lib
Run Code Online (Sandbox Code Playgroud)

这看起来不对,因为MinGW GCC通常与.a库一起使用,而不是与库一起使用.lib

我试图从该目录手动链接各种库。

对于asan,我设法摆脱了编译器错误,但是asan本身似乎没有发出任何诊断信息:

# /z/Lander/LLVM/bin/clang++ -target x86_64-w64-windows-gnu -fsanitize=address 1.cpp -c
# /z/Lander/LLVM/bin/clang++ -target x86_64-w64-windows-gnu 1.o /z/Lander/LLVM/lib/clang/8.0.0/lib/windows/clang_rt.asan_dynamic-x86_64.lib
# ./a.exe
-2147483648
5089296         <- expected a diagnostic here
Run Code Online (Sandbox Code Playgroud)

对于ubsan,我尝试进行链接clang_rt.ubsan_standalone-x86_64.lib,但得到了更多未定义的引用和几个Warning: corrupt .drectve at end of def file

我对进行了一些研究Warning: corrupt .drectve at end of def file这个问题表明我正在链接不兼容的MSVC库。

这里发生了什么?我应该如何使用asan和ubsan?


上面的所有命令均从Windows 7 x64上的MSYS2终端运行。

我的目标是x86_64,并使用MSYS2中提供的最新GCC:

# g++ --version
g++.exe (Rev2, Built by MSYS2 project) 8.3.0
Run Code Online (Sandbox Code Playgroud)

来自MSYS2的Clang似乎没有捆绑asan和ubsan库,因此我使用的是llvm.org的官方版本:

# /z/Lander/LLVM/bin/clang++ --version
clang version 8.0.0 (tags/RELEASE_800/final)
Target: x86_64-pc-windows-msvc
Thread model: posix
InstalledDir: Z:\Lander\LLVM\bin
Run Code Online (Sandbox Code Playgroud)

我正在使用,-target x86_64-w64-windows-gnu因为否则Clang会尝试使用MSVC安装,而我没有安装。这个特定的三元组是MSYS2叮当响应的报告--version

Hol*_*Cat 6

我找到了一种让 UBsan 工作的方法,但不是 Asan。

事实证明,即使没有 libubsan,UBsan 也能运行。您需要使用以下标志:

-fsanitize=undefined -fsanitize-undefined-trap-on-error
Run Code Online (Sandbox Code Playgroud)

这样,错误是通过“非法指令”崩溃来报告的,而不是通过发出漂亮的诊断信息,但总比没有好。

GCC 和 Clang 都支持该标志。

海湾合作委员会手册:

-fsanitize-undefined-trap-on-error

该选项指示编译器使用而不是 libubsan 库例程-fsanitize-undefined-trap-on-error来报告未定义的行为。__builtin_trap这样做的优点是不需要并且不链接 libubsan 库,因此即使在独立环境中也可以使用。


Ran*_*ane 6

在 Windows 上支持清理程序(地址、UB 等)的编译器

从现在(2023 年 3 月)起,为了能够在 Windows 上使用消毒剂,您需要:

按照上面的指南,Visual Studio AddressSanitizer 或 Clang 安装应该很容易。WSL 还提供来自 Microsoft 和其他第三方网站的大量指南。因此,我只会在 MSYS2 上进行安装,因为它有一些障碍。MSYS2 包含许多不同的环境,每个环境都有自己的clang包,并且这些 clang 变体 (libc++) 中只有一种支持清理程序。

如何使用地址和 UB 清理程序安装 MSYS2 clang

  1. 按照MSYS2 入门指南使用安装程序安装 MSYS2 。请注意,如果您勾选“立即运行 MSYS2”框,则默认情况下安装程序会启动一个消毒剂不兼容的环境 UCRT64 。
  2. 从“开始”菜单启动MSYS2 CLANG64终端环境。正确的终端具有前缀<username>@<computer_name> CLANG64
  3. 使用包管理器更新 MSYS2 pacman -Syu此处为 MSYS2 更新指南
  4. 在某些情况下,尤其是首次安装时,更新过程需要关闭终端才能更新某些核心包。如果发生这种情况,请再次启动 CLANG64 终端并pacman -Syu 再次运行以更新非核心包。
  5. 接下来,我们需要安装正确的clang变体。这是通过包管理器命令完成的pacman -S mingw-w64-clang-x86_64-clang
  6. 安装后,通过运行检查您是否安装了正确的版本clang --version
  7. 如果您遇到错误-bash: clang: command not found或类似的情况,您很可能处于错误的环境中。切换到 CLANG64 环境,因为mingw-w64-clang-x86_64-clang包会在那里安装 clang。

现在,在 CLANG64 MSYS2 环境中,您可以使用 或 编译器的选项来编译带有地址和 UB 清理-fsanitize=address程序-fsanitize=undefinedclang代码clang++。例如,我们可以使用以下程序测试AddressSanitizer:

int main()
{
    int* const heapOverflow = new int[5]{};
    heapOverflow[5] = 0;
}
Run Code Online (Sandbox Code Playgroud)

编译并clang++运行,你应该得到一个 AddressSanitizer 错误:

$ clang++ -fsanitize=address heapoverflow.cpp -o heapoverflow`
$./heapoverflow

=================================================================
==17384==ERROR: AddressSanitizer: heap-buffer-overflow on address
...
Run Code Online (Sandbox Code Playgroud)