2017-10-19 266 views
2

我想添加ASAN(谷歌的/ Clang的地址消毒)到我们的项目,并坚持在这个问题。铿锵和铿锵与ASAN ++产生不同的输出

例如,我们有这个简单的C++代码

#include <iostream> 
int main() { 
    std::cout << "Started Program\n"; 
    int* i = new int(); 
    *i = 42; 
    std::cout << "Expected i: " << *i << std::endl; 
} 

然后,我铿锵++

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-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来达到一些糟糕的理由。我们不能盲目强制使用CXX,因为我们拥有无法由CXX构建的CC依赖关系。所以...

任何想法如何获得相同的ASAN输出时使用铿锵和铿锵++?或者,如何让Bazel为C++目标使用clang ++和Cng目标?

+0

这可能没有帮助,但是在使用clang 5.0.0时,我看到的输出与clang ++相同。 – Rakete1111

+0

我可以用clang3.8重现你的问题。在我的系统上,关键的区别在于不同的链接器命令 - 如果使用clang调用,某些asan-stuff会丢失。对我来说看起来像一个bug。 – ead

+0

我从来没有使用bazel,但你可能可以定义连接器命令行与正确的库 – ead

回答

0

这似乎是叮当中的一个错误,你可以在their tracker中提交错误报告吗? (编辑:这是[解决不是一个错误](牙山开发人员https://github.com/google/sanitizers/issues/872),所以很可能需要由Bazel开发人员修复)。

一些细节:当您使用普通clang,决定不链接阿三运行的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有关此类行为和可用解决方法的另一个示例。

+0

感谢yugr。Bug创建:https://github.com/google/sanitizers/issues/872 – user1767432