2017-10-19 246 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