使用 Conan 的编译器消毒器¶
为了更好地说明 Conan 与消毒器的集成,本节提供使用地址消毒器 (ASan) 和未定义行为消毒器 (UBSan) 的实际示例,使用简单的 C++ 程序。
作为第一步,请克隆源代码以重新创建此项目。您可以在 GitHub 上的 examples2 仓库 中找到它们
git clone https://github.com/conan-io/examples2.git
cd examples2/examples/security/sanitizers/compiler_sanitizers
在本示例中,我们将看到如何准备 Conan 以不同的方式使用消毒器。
为了展示如何在构建中使用消毒器,让我们考虑两个示例。
地址消毒器:越界索引¶
在本示例中,我们将构建一个简单的 C++ 程序,该程序有意访问数组中的越界索引,这应该在运行程序时触发 ASan。我们将使用 Conan profile 来启用 ASan
[settings]
arch=x86_64
os=Linux
build_type=Debug
compiler=gcc
compiler.cppstd=gnu20
compiler.libcxx=libstdc++11
compiler.version=15
compiler.sanitizer=Address
[conf]
tools.build:cflags=['-fsanitize=address']
tools.build:cxxflags=['-fsanitize=address']
tools.build:exelinkflags=['-fsanitize=address']
tools.build:sharedlinkflags+=["-fsanitize=address"]
[runenv]
ASAN_OPTIONS=halt_on_error=1:detect_leaks=1
请注意,在此 profile 中,我们设置了 compiler.sanitizer=Address 并未定义使用哪些编译器标志,但这是一个设置,用于明确 ASan 和 UBSan 打算一起使用。
为了进一步说明,我们还使用环境变量 ASAN_OPTIONS=halt_on_error=1:detect_leaks=1 进行运行时配置,以管理 ASan 在第一个错误时停止执行,并在程序退出时检测内存泄漏。
#include <iostream>
#include <cstdlib>
int main() {
#ifdef __SANITIZE_ADDRESS__
std::cout << "Address sanitizer enabled\n";
#else
std::cout << "Address sanitizer not enabled\n";
#endif
int foo[100];
foo[100] = 42; // Out-of-bounds write
return EXIT_SUCCESS;
}
注意: 上面的预处理器检查可移植于 GCC、Clang 和 MSVC。当 ASan 处于活动状态时,存在 __SANITIZE_ADDRESS__ 定义;
要使用 Conan 构建并运行此示例
cd index_out_of_bounds/
conan build . -pr ../profiles/gcc_asan
build/Debug/index_out_of_bounds
预期输出(缩写)
Address sanitizer enabled
==32018==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fffbe04a6d0 ...
WRITE of size 4 at 0x7fffbe04a6d0 thread T0
#0 ... in main .../index_out_of_bounds+0x12ea
...
SUMMARY: AddressSanitizer: stack-buffer-overflow ... in main
This frame has 1 object(s):
[48, 448) 'foo' (line 11) <== Memory access at offset 448 overflows this variable
未定义行为消毒器:有符号整数溢出¶
本示例演示如何使用 UBSan 检测有符号整数溢出。它结合了 ASan 和 UBSan。创建一个专用的 profile
[settings]
arch=x86_64
os=Linux
build_type=Debug
compiler=gcc
compiler.cppstd=gnu20
compiler.libcxx=libstdc++11
compiler.version=15
compiler.sanitizer=AddressUndefinedBehavior
[conf]
tools.build:cflags+=["-fsanitize=address,undefined", "-fno-omit-frame-pointer"]
tools.build:cxxflags+=["-fsanitize=address,undefined", "-fno-omit-frame-pointer"]
tools.build:exelinkflags+=["-fsanitize=address,undefined"]
tools.build:sharedlinkflags+=["-fsanitize=address,undefined"]
它受 GCC 和 Clang 支持。MSVC 不支持 UBSan。
源代码
#include <iostream>
#include <cstdlib>
#include <climits>
int main() {
#ifdef __SANITIZE_ADDRESS__
std::cout << "Address sanitizer enabled\n";
#else
std::cout << "Address sanitizer not enabled\n";
#endif
int x = INT_MAX;
x += 42; // signed integer overflow
return EXIT_SUCCESS;
}
构建并运行
cd signed_integer_overflow/
conan build . -pr ../profiles/gcc_asan_ubsan
build/Debug/signed_integer_overflow
预期输出(缩写)
Address sanitizer enabled
.../main.cpp:16:9: runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int'
执行示例应用程序时,UBSan 检测到有符号整数溢出并按预期报告。