我正在尝试将ASAN(Google的/ 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 vs clang ++。
为什么它的事件有问题,我们不能使用clang ++吗? 我们使用bazel,它使用CC编译器而不是CXX,因为一些blah-balh原因。我们不能盲目强制使用它CXX,因为我们有CC依赖,无法通过CXX构建。所以...
知道如何在与clang和clang ++一起使用时获得相同的ASAN输出吗?或者,如何让Bazel使用clang ++进行C ++目标并为C目标进行铿锵?
答案 0 :(得分:0)
这似乎是Clang中的一个错误,您可以在their tracker中提交错误报告吗? (编辑:这是[已解决为非错误](Asan开发人员https://github.com/google/sanitizers/issues/872),因此很可能需要由Bazel开发人员修复。
一些细节:当您使用普通clang
时,它决定不链接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
的拦截器,因此这可以解释当您与clang
而不是clang++
链接时它缺失的原因。从积极的方面来说,您应该可以通过在标记中添加-fsanitize-link-c++-runtime
来解决此问题。
对于borked堆栈,默认情况下,Asan使用基于框架指针的展开器展开堆栈,这会在通过代码展开时出现问题,而代码并非由-fno-omit-frame-pointer
构建(在您的情况下与libstdc++.so
一样)。参见例如this answer了解此类行为的另一个示例和可用的解决方法。