clang 和 clang++ 与 ASAN 生成不同的输出
clang and clang++ with ASAN generate different output
我正在尝试将 ASAN(Google's/Clang 的地址清理)添加到我们的项目中,但遇到了这个问题。
例如,我们有这个简单的 C++ 代码
#include <iostream>
int main() {
std::cout << "Started Program\n";
int* i = new int();
*i = 42;
std::cout << "Expected i: " << *i << std::endl;
}
然后,我用 clang++ 构建它
clang++-3.8 -o memory-leak++ memory_leak.cpp -fsanitize=address -fno-omit-frame-pointer -g
程序给出了这个输出
Started Program
Expected i: 42
=================================================================
==14891==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 4 byte(s) in 1 object(s) allocated from:
#0 0x4f2040 in operator new(unsigned long) (memory-leak+++0x4f2040)
#1 0x4f4f00 in main memory_leak.cpp:4:11
#2 0x7fae13ce6f44 in __libc_start_main /build/eglibc-SvCtMH/eglibc-2.19/csu/libc-start.c:287
SUMMARY: AddressSanitizer: 4 byte(s) leaked in 1 allocation(s).
太棒了,它起作用了,符号器也提供了有意义的信息。
现在,我用 clang 构建这个
clang-3.8 -o memory-leak memory_leak.cpp -std=c++11 -fsanitize=address -fno-omit-frame-pointer -g -lstdc++
程序给出了这个输出
Started Program
Expected i: 42
=================================================================
==14922==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 4 byte(s) in 1 object(s) allocated from:
#0 0x4c3bc8 in malloc (memory-leak+0x4c3bc8)
#1 0x7f024a8e4dac in operator new(unsigned long) (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0x5edac)
#2 0x7f0249998f44 in __libc_start_main /build/eglibc-SvCtMH/eglibc-2.19/csu/libc-start.c:287
SUMMARY: AddressSanitizer: 4 byte(s) leaked in 1 allocation(s).
好的,它检测到内存泄漏,但堆栈跟踪看起来很奇怪,它并不真正包括 memory_leak.cpp:4:11 行。
我花了很长时间试图在我们的代码库中缩小这个问题的范围,最终,唯一的区别是 clang 与 clang++。
为什么会出现问题,我们不能使用 clang++ 吗?
我们使用 bazel,出于一些废话原因,它使用 CC 编译器而不是 CXX。我们不能盲目地强制使用它 CXX,因为我们有 CC 依赖项,无法通过 CXX 构建。所以...
知道如何在与 clang 和 clang++ 一起使用时获得相同的 ASAN 输出吗?或者,如何使 Bazel 对 C++ 目标使用 clang++ 而对 C 目标使用 clang?
这似乎是 Clang 中的错误,您能否在 their tracker? (EDIT: this was [resolved as not-a-bug](Asan developers https://github.com/google/sanitizers/issues/872 中提交错误报告)所以可能需要由 Bazel 开发人员修复)。
一些细节:当你使用普通 clang
时,它决定不 link Asan 运行时的 C++ 部分,如 Tools.cpp:
中所示
if (SanArgs.linkCXXRuntimes())
StaticRuntimes.push_back("asan_cxx");
LinkCXXRuntimes =
Args.hasArg(options::OPT_fsanitize_link_cxx_runtime) || D.CCCIsCXX();
(注意 D.CCCIsCXX
部分,它检查 clang
与 clang++
而他们需要检查文件类型)。
运行时的 C++ 部分包含 operator new
的拦截器,因此这可以解释为什么当您 link 使用 clang
而不是 clang++
时它会丢失。从积极的方面来说,您应该可以通过在标志中添加 -fsanitize-link-c++-runtime
来解决这个问题。
至于 borked 堆栈,默认情况下 Asan 使用基于帧指针的展开器展开堆栈,这在通过不是使用 -fno-omit-frame-pointer
构建的代码展开时存在问题(如您的情况下的 libstdc++.so
)。参见例如 此类行为和可用解决方法的另一个示例。
我正在尝试将 ASAN(Google's/Clang 的地址清理)添加到我们的项目中,但遇到了这个问题。
例如,我们有这个简单的 C++ 代码
#include <iostream>
int main() {
std::cout << "Started Program\n";
int* i = new int();
*i = 42;
std::cout << "Expected i: " << *i << std::endl;
}
然后,我用 clang++ 构建它
clang++-3.8 -o memory-leak++ memory_leak.cpp -fsanitize=address -fno-omit-frame-pointer -g
程序给出了这个输出
Started Program
Expected i: 42
=================================================================
==14891==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 4 byte(s) in 1 object(s) allocated from:
#0 0x4f2040 in operator new(unsigned long) (memory-leak+++0x4f2040)
#1 0x4f4f00 in main memory_leak.cpp:4:11
#2 0x7fae13ce6f44 in __libc_start_main /build/eglibc-SvCtMH/eglibc-2.19/csu/libc-start.c:287
SUMMARY: AddressSanitizer: 4 byte(s) leaked in 1 allocation(s).
太棒了,它起作用了,符号器也提供了有意义的信息。
现在,我用 clang 构建这个
clang-3.8 -o memory-leak memory_leak.cpp -std=c++11 -fsanitize=address -fno-omit-frame-pointer -g -lstdc++
程序给出了这个输出
Started Program
Expected i: 42
=================================================================
==14922==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 4 byte(s) in 1 object(s) allocated from:
#0 0x4c3bc8 in malloc (memory-leak+0x4c3bc8)
#1 0x7f024a8e4dac in operator new(unsigned long) (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0x5edac)
#2 0x7f0249998f44 in __libc_start_main /build/eglibc-SvCtMH/eglibc-2.19/csu/libc-start.c:287
SUMMARY: AddressSanitizer: 4 byte(s) leaked in 1 allocation(s).
好的,它检测到内存泄漏,但堆栈跟踪看起来很奇怪,它并不真正包括 memory_leak.cpp:4:11 行。
我花了很长时间试图在我们的代码库中缩小这个问题的范围,最终,唯一的区别是 clang 与 clang++。
为什么会出现问题,我们不能使用 clang++ 吗? 我们使用 bazel,出于一些废话原因,它使用 CC 编译器而不是 CXX。我们不能盲目地强制使用它 CXX,因为我们有 CC 依赖项,无法通过 CXX 构建。所以...
知道如何在与 clang 和 clang++ 一起使用时获得相同的 ASAN 输出吗?或者,如何使 Bazel 对 C++ 目标使用 clang++ 而对 C 目标使用 clang?
这似乎是 Clang 中的错误,您能否在 their tracker? (EDIT: this was [resolved as not-a-bug](Asan developers https://github.com/google/sanitizers/issues/872 中提交错误报告)所以可能需要由 Bazel 开发人员修复)。
一些细节:当你使用普通 clang
时,它决定不 link Asan 运行时的 C++ 部分,如 Tools.cpp:
if (SanArgs.linkCXXRuntimes())
StaticRuntimes.push_back("asan_cxx");
LinkCXXRuntimes =
Args.hasArg(options::OPT_fsanitize_link_cxx_runtime) || D.CCCIsCXX();
(注意 D.CCCIsCXX
部分,它检查 clang
与 clang++
而他们需要检查文件类型)。
运行时的 C++ 部分包含 operator new
的拦截器,因此这可以解释为什么当您 link 使用 clang
而不是 clang++
时它会丢失。从积极的方面来说,您应该可以通过在标志中添加 -fsanitize-link-c++-runtime
来解决这个问题。
至于 borked 堆栈,默认情况下 Asan 使用基于帧指针的展开器展开堆栈,这在通过不是使用 -fno-omit-frame-pointer
构建的代码展开时存在问题(如您的情况下的 libstdc++.so
)。参见例如