[英]How can I link to thread sanitizer with a newer version of clang than the system provides?
[英]How I'm supposed to use the sanitizer in clang?
我很抱歉,如果這是一個超級簡單的概念,但我發現很難獲得正確的心態,以便正確使用clang
提供的消毒劑。
float foo(float f) { return (f / 0); }
我編譯這個小片段
clang++ -fsanitize=float-divide-by-zero -std=c++11 -stdlib=libc++ -c source.cpp -o osan
而且我還在不使用消毒劑的情況下編譯了我的對象的“正常”版本
clang++ -std=c++11 -stdlib=libc++ -c source.cpp -o onorm
我期待一些冗長的輸出,或者來自控制台的一些錯誤,但是當用nm
檢查文件時,我發現只有1個區別
nm o* --demangle
onorm:
0000000000000000 T foo(float)
osan:
U __ubsan_handle_divrem_overflow
0000000000000000 T foo(float)
所以在清理版本中有一個未定義的符號,其名稱類似於我在編譯時使用的清潔劑; 但是一切都是“沉默的”,而且從鏗鏘的前端根本沒有輸出。
我應該如何使用消毒劑以及什么是正確的工作流程? 那個未定義的符號有什么意義?
未定義的符號是實現清潔劑檢查的功能。 如果你看一下生成的代碼:
沒有消毒劑:
_Z3foof: # @_Z3foof
.cfi_startproc
# BB#0:
xorps %xmm1, %xmm1
divss %xmm1, %xmm0
ret
使用消毒劑:
_Z3foof: # @_Z3foof
.cfi_startproc
.long 1413876459 # 0x54460aeb
.quad _ZTIFffE
# BB#0:
pushq %rax
.Ltmp1:
.cfi_def_cfa_offset 16
movss %xmm0, 4(%rsp) # 4-byte Spill
movd %xmm0, %esi
movl $__unnamed_1, %edi
xorl %edx, %edx
callq __ubsan_handle_divrem_overflow
xorps %xmm1, %xmm1
movss 4(%rsp), %xmm0 # 4-byte Reload
divss %xmm1, %xmm0
popq %rax
ret
您看到它添加了使用該功能進行檢查的代碼。
編譯器應自動鏈接到相應的清理程序庫中,然后為我完成以下完整程序:
float foo(float f) { return (f / 0); }
int main() {
foo(1.0f);
}
執行時生成以下輸出:
main.cpp:1:32: runtime error: division by zero
我使用命令clang++ -fsanitize=undefined main.cpp && ./a.out
構建並運行
如果要進行編譯時檢查,則需要啟用更多編譯器警告或靜態分析器。 但是,似乎沒有任何警告或靜態分析檢查浮點被零除錯誤。
這是一個生成分析報告的程序:
#include <malloc.h>
int main() {
int *i = (int*) malloc(sizeof(int));
}
使用clang++ -std=c++11 main.cpp
編譯它不會產生任何診斷,但是使用clang++ -std=c++11 --analyze main.cpp
它會報告以下內容:
main.cpp:4:10: warning: Value stored to 'i' during its initialization is never read
int *i = (int*) malloc(sizeof(int));
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:5:1: warning: Potential leak of memory pointed to by 'i'
}
^
也可以使用-Weverything [-Wunused-value]檢測死存儲,但只能通過分析器檢測泄漏。
默認情況下,完整分析結果將寫入plist文件。 您還可以使用以下命令運行分析器:
clang++ --analyze -Xanalyzer -analyzer-output=text main.cpp
clang++ --analyze -Xanalyzer -analyzer-output=html -o html-dir main.cpp
要分別在標准輸出或通過帶注釋的源代碼的html顯示中詳細了解檢測到的問題,而不是在plist中。
請注意,為了最好地工作,分析器需要分析整個程序,這意味着它需要綁定到構建系統。 通常的界面是通過IDE(Xcode)或帶有make的scan-build
工具。 CMake有一些鏗鏘的功能,比如生成clang JSON編譯數據庫文件,但如果CMake對clang分析器有任何內置支持,我不確定。
因此,如果我們查看控制代碼生成中的文檔,它會說( 強調我的 ):
打開運行時檢查各種形式的未定義或可疑行為。
此選項控制Clang是否為各種形式的未定義或可疑行為添加運行時檢查,並且默認情況下處於禁用狀態。 如果檢查失敗, 則會在運行時生成診斷消息,說明問題 。
所以這些是運行時檢查而不是編譯時間檢查。 因此,如果您在代碼中使用了foo
,那么您將看到以下輸出:
運行時錯誤:除以零
使用-fsanitize=undefined
查看此示例實時 :
float foo(float f) { return (f / 0); }
int main()
{
int x = 1 << 100 ;
foo( 2.0f ) ;
}
它會生成兩個運行時消息:
main.cpp:6:19:運行時錯誤:移位指數100對於32位類型'int'來說太大了
main.cpp:2:36:運行時錯誤:除以零
更新
關於靜態檢查器,我在回答A C ++實現時檢測到未定義的行為? 我提到了幾個工具: STACK , kcc ,當然還有Frama-C 。
顯然clang
允許你使用--analyze來運行它的靜態檢查器,但似乎它最終可能被禁用,運行它的正確方法是通過scan-build 。
同樣在我自我回答的問題中為什么常量表達式排除了未定義的行為? 我展示了如何使用constexprs
在編譯時捕獲未定義的行為。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.