簡體   English   中英

我怎么應該在鏗鏘聲中使用消毒殺菌劑?

[英]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 ++實現時檢測到未定義的行為? 我提到了幾個工具: STACKkcc ,當然還有Frama-C

顯然clang允許你使用--analyze來運行它的靜態檢查器,但似乎它最終可能被禁用,運行它的正確方法是通過scan-build

同樣在我自我回答的問題中為什么常量表達式排除了未定義的行為? 我展示了如何使用constexprs在編譯時捕獲未定義的行為。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM