在 CMake 中启用 UB 清理的惯用方法是什么?

What's the idiomatic way of enabling UB sanitization in CMake?

提问人:einpoklum 提问时间:8/2/2021 最后编辑:einpoklum 更新时间:8/3/2021 访问量:1380

问:

我想为我的一个存储库构建一个测试程序,其中启用了未定义的行为清理(至少使用 GCC 和 clang)。我知道如何手动执行此操作:

  • 添加到编译标志-fsanitize=undefined
  • 添加到链接标志-lubsan
  • 确保安装了适当版本的 。libubsan

现在,在 CMake 中,我希望像这样的东西可以工作:

find_package(ubsan)
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU"   OR
    CMAKE_CXX_COMPILER_ID STREQUAL "Clang" )
    target_compile_options(my_test PRIVATE "-fsanitize=undefined")
endif()

target_link_libraries(ubsan::ubsan)

...但是没有这样的版本(从 CMake 3.21.0-rc2 开始)。那么,我应该怎么做呢?从某个地方获取 FindUBSan.cmake?也许做点别的事情?

PS - 这个问题同样适用于 C

GCC cmake clang 成语 ubsan

评论

0赞 KamilCuk 8/3/2021
but there is no such version版本... ? 你是什么意思? 应该与编译器一起分发,至少在我的发行版中它是包的一部分。Make sure an appropriate version of libubsan is installed.libubsan.sogcc-libs

答:

4赞 Alex Reinking 8/3/2021 #1

一切都需要在启用清理程序的情况下进行编译(通常无法混合和匹配),并且启用清理器是特定于编译器的;因此,它是一个工具链选项。

在工具链文件中,包括以下内容:

set(CMAKE_C_FLAGS_INIT "-fsanitize=undefined")
set(CMAKE_CXX_FLAGS_INIT "-fsanitize=undefined")

您也可以在命令行中将 .CMAKE_<LANG>_FLAGS-fsanitize=undefined


完整示例:

alex@alex-ubuntu:~/test$ tree
.
├── CMakeLists.txt
├── main.cpp
└── ubsan.cmake

0 directories, 3 files

alex@alex-ubuntu:~/test$ cat CMakeLists.txt 
cmake_minimum_required(VERSION 3.21)
project(test)

add_executable(main main.cpp)

alex@alex-ubuntu:~/test$ cat main.cpp 
int main () { return 0; }

alex@alex-ubuntu:~/test$ cat ubsan.cmake 
set(CMAKE_C_FLAGS_INIT "-fsanitize=undefined")
set(CMAKE_CXX_FLAGS_INIT "-fsanitize=undefined")

alex@alex-ubuntu:~/test$ cmake -G Ninja -S . -B build --toolchain ubsan.cmake 
-- The C compiler identification is GNU 9.3.0
-- The CXX compiler identification is GNU 9.3.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/alex/test/build

alex@alex-ubuntu:~/test$ cmake --build build/ -- -v
[1/2] /usr/bin/c++   -fsanitize=undefined -MD -MT CMakeFiles/main.dir/main.cpp.o -MF CMakeFiles/main.dir/main.cpp.o.d -o CMakeFiles/main.dir/main.cpp.o -c /home/alex/test/main.cpp
[2/2] : && /usr/bin/c++ -fsanitize=undefined  CMakeFiles/main.dir/main.cpp.o -o main   && :

alex@alex-ubuntu:~/test$ ldd build/main 
    linux-vdso.so.1 (0x00007ffc9dd75000)
    libubsan.so.1 => /lib/x86_64-linux-gnu/libubsan.so.1 (0x00007f79a4b52000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f79a4960000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f79a495a000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f79a4937000)
    libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f79a4755000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f79a4738000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f79a550a000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f79a45e9000)

评论

0赞 einpoklum 8/3/2021
我相信你在猜测......因为以上是行不通的。即海湾合作委员会通常还需要 libubsan 才能使卫生工作发挥作用。从理论上讲,该库可以引入编译器标志。另外,其他编译器呢?
0赞 Alex Reinking 8/3/2021
这对 GCC 9.3.0 有用。这些标志 ( via ) 也会在喜欢时传递给编译器,并且生成的 basic 二进制文件确实链接到 libubsan。-fsanitize=undefinedCMAKE_<LANG>_FLAGSint main () { return 0; }
0赞 einpoklum 8/3/2021
所有让我得到的都是来自 libubsan 的未定义符号。但是,我正在使用 GCC 10.2
0赞 Alex Reinking 8/3/2021
@einpoklum - 我刚刚用 10.3(来自 Ubuntu 存储库)尝试过,可执行文件仍然链接到这个答案(刚刚添加和 C 等同于工具链)。你能提供MRE吗?libubsanset(CMAKE_CXX_COMPILER g++-10)
1赞 einpoklum 8/3/2021
我会很快尝试(但可能不会在周末之前)。
2赞 KamilCuk 8/3/2021 #2

在 CMake 中启用 UB 清理的惯用方法是什么?

没有“惯用方式”——它是特定于编译器的。狐狸

  • 将 -fsanitize=undefined 添加到编译标志中
target_compile_options(my_test PUBLIC -fsanitize=undefined)
target_link_options(my_test PUBLIC -fsanitize=undefined)

您可以使用 检查该选项是否受支持。CheckCXXCompilerFlag

评论

1赞 Alex Reinking 8/3/2021
如果您采用这种方法,您还需要致电...我试过了,它没有链接到,因为链接行缺少此标志。target_link_optionslibubsan
0赞 einpoklum 8/3/2021
这基本上就是我说的我正在做的事情,没有你缺少的库依赖关系。