clang和clang ++与ASAN产生不同的输出

时间:2017-10-19 18:45:30

标签: c++ clang clang++ bazel address-sanitizer

我正在尝试将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目标进行铿锵?

1 个答案:

答案 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");

SanitizerArgs.cpp

LinkCXXRuntimes =
    Args.hasArg(options::OPT_fsanitize_link_cxx_runtime) || D.CCCIsCXX();

(请注意D.CCCIsCXX部分,它会检查clangclang++,而他们需要检查文件类型。)

运行时的C ++部分包含operator new的拦截器,因此这可以解释当您与clang而不是clang++链接时它缺失的原因。从积极的方面来说,您应该可以通过在标记中添加-fsanitize-link-c++-runtime来解决此问题。

对于borked堆栈,默认情况下,Asan使用基于框架指针的展开器展开堆栈,这会在通过代码展开时出现问题,而代码并非由-fno-omit-frame-pointer构建(在您的情况下与libstdc++.so一样)。参见例如this answer了解此类行为的另一个示例和可用的解决方法。