AddressSanitizer 語言、組建和偵錯參考

本文中的各節說明 AddressSanitizer 語言規格、編譯程式選項和鏈接器選項。 它們也會描述控制 AddressSanitizer 專屬 Visual Studio 調試程式整合的選項。

如需 AddressSanitizer 運行時間的詳細資訊,請參閱 運行時間參考。 其中包含攔截函式的相關信息,以及如何攔截自定義配置器。 如需從 AddressSanitizer 失敗儲存損毀傾印的詳細資訊,請參閱 損毀傾印參考

語言規格

__SANITIZE_ADDRESS__

__SANITIZE_ADDRESS__預處理器宏定義為1設定時/fsanitize=address。 此宏適用於進階使用者,可有條件地指定 AddressSanitizer 運行時間的原始程式碼。

#include <cstdio>

int main() {
    #ifdef __SANITIZE_ADDRESS__
        printf("Address sanitizer enabled");
    #else
        printf("Address sanitizer not enabled");
    #endif
    return 1;
}

__declspec(no_sanitize_address)

__declspec(no_sanitize_address)規範可用來選擇性地停用函式、局部變數或全域變數上的清理工具。 這__declspec會影響編譯程序行為,而不是運行時間行為。

__declspec(no_sanitize_address)
void test1() {
    int x[100];
    x[100] = 5; // ASan exception not caught
}

void test2() {
    __declspec(no_sanitize_address) int x[100];
    x[100] = 5; // ASan exception not caught
}

__declspec(no_sanitize_address) int g[100];
void test3() {
    g[100] = 5; // ASan exception not caught
}

編譯器

/fsanitize=address 編譯器選項

編譯程式 /fsanitize=address 選項會檢測程序代碼中的記憶體參考,以攔截運行時間的記憶體安全性錯誤。 檢測攔截會載入、儲存、範圍和 allocaCRT函式。 它可以偵測隱藏的錯誤,例如超出範圍、無後使用、使用后範圍等等。 如需在運行時間偵測到的錯誤非Exhaustive 清單,請參閱 AddressSanitizer 錯誤範例

/fsanitize=address與所有現有的 C++ 或 C 優化層級相容(例如 、/Od/O1/O2/O2 /GL、 和設定檔引導式優化)。 使用此選項所產生的程式代碼適用於靜態和動態CCT(例如、 /MD/MDd/MT/MTd)。 這個編譯程式選項可用來建立以 x86 或 x64 為目標的.EXE或.DLL。 針對呼叫堆疊的最佳格式設定,需要偵錯資訊。

如需示範數種錯誤偵測的程式碼範例,請參閱 AddressSanitizer 錯誤範例

/fsanitize=fuzzer 編譯程式選項 (實驗性)

編譯程式選項會將 /fsanitize=fuzzer LibFuzzer 新增至預設連結庫清單。 它也會設定下列清理工具涵蓋範圍選項:

建議您搭配 /fsanitize=fuzzer使用 /fsanitize=address

當您指定 /fsanitize=fuzzer時,這些連結庫會新增至預設連結庫清單:

運行時間選項 LibFuzzer 連結庫
/MT clang_rt.fuzzer_MT-{arch}
/MD clang_rt.fuzzer_MD-{arch}
/MTd clang_rt.fuzzer_MTd-{arch}
/MDd clang_rt.fuzzer_MDd-{arch}

您也可以使用省略函式的 main LibFuzzer 連結庫。 您必須負責定義 main 和呼叫 LLVMFuzzerInitialize ,以及 LLVMFuzzerTestOneInput 使用這些連結庫時。 若要使用下列其中一個連結庫,請指定 /NODEFAULTLIB 並明確連結至對應至運行時間和架構的下列連結庫:

運行時間選項 LibFuzzer no_main 連結庫
/MT clang_rt.fuzzer_no_main_MT-{arch}
/MD clang_rt.fuzzer_no_main_MD-{arch}
/MTd clang_rt.fuzzer_no_main_MTd-{arch}
/MDd clang_rt.fuzzer_no_main_MDd-{arch}

如果您指定 /NODEFAULTLIB 且未指定其中一個連結庫,您將會收到無法解析的外部符號連結錯誤。

/fsanitize-address-use-after-return 編譯程式選項 (實驗性)

根據預設,MSVC 編譯程式 (不同於 Clang) 不會產生程式代碼來設定堆積中的框架,以攔截傳回後使用的錯誤。 若要使用 AddressSanitizer 攔截這些錯誤,您必須:

  1. 使用 /fsanitize-address-use-after-return 選項進行編譯。
  2. 在執行程式之前,請執行 set ASAN_OPTIONS=detect_stack_use_after_return=1 以設定運行時間檢查選項。

當局部變數被視為「取得位址」時,選項/fsanitize-address-use-after-return會導致編譯程式產生程序代碼,以在堆積中使用雙堆疊框架。此程式代碼比單獨使用/fsanitize=address得多。 如需詳細資訊和範例,請參閱 錯誤: stack-use-after-return

堆積中的雙堆疊框架會保留在從建立堆積的函式傳回之後。 假設在傳回之後,會使用配置給堆積中位置的本機位址。 與假堆積框架相關聯的陰影位元組包含值0xF9。 0xF9表示運行時間報告錯誤時,堆疊使用後傳回錯誤。

堆疊框架會配置在堆積中,並保留在函式傳回之後。 運行時間會使用垃圾收集,在特定時間間隔之後,以異步方式釋放這些假的呼叫框架物件。 局部變數的位址會傳輸至堆積中的永續性框架。 這是系統如何在定義函式傳回之後偵測到何時使用局部變數。 如需詳細資訊,請參閱 Google 所記載傳回 之後堆疊使用的演算法。

連結器

/INFERASANLIBS[:NO] 連結器選項

編譯 /fsanitize=address 程式選項會標記 物件,以指定要連結至可執行檔的 AddressSanitizer 連結庫。 連結庫的名稱開頭為 clang_rt.asan*。 鏈接 /INFERASANLIBS 器選項(預設為開啟)會自動從其預設位置連結這些連結庫。 以下是選擇的連結庫,並自動連結。

注意

在下表中, {arch}i386x86_64。 這些連結庫會針對架構名稱使用 Clang 慣例。 MSVC 慣例通常是 x86x64 而不是 i386x86_64。 它們指的是相同的架構。

CRT 選項 AddressSanitizer 運行時間連結庫 (.lib) 位址執行時間二進位檔 (.dll)
/MT/MTd clang_rt.asan_dynamic-{arch}, clang_rt.asan_static_runtime_thunk-{arch} clang_rt.asan_dynamic-{arch}
/MD/MDd clang_rt.asan_dynamic-{arch}, clang_rt.asan_dynamic_runtime_thunk-{arch} clang_rt.asan_dynamic-{arch}

連結器選項 /INFERASANLIBS:NO 可防止連結器從預設位置連結 clang_rt.asan* 連結庫檔案。 如果您使用此選項,請在組建腳本中新增連結庫路徑。 否則,連結器會報告未解析的外部符號錯誤。

舊版

在 Visual Studio 17.7 Preview 3 之前,靜態連結的 (/MT/MTd) 組建未使用 DLL 相依性。 相反地,AddressSanitizer 運行時間是以靜態方式連結至使用者的 EXE。 DLL 項目接著會從使用者的 EXE 載入匯出,以存取 ASan 功能。 此外,動態連結的專案 (/MD/MTd) 會根據專案是否已設定偵錯或發行,使用不同的連結庫和 DLL。 如需這些變更及其動機的詳細資訊,請參閱 MSVC 位址清理器 – 所有運行時間組態的一個 DLL。

CRT 執行時間選項 DLL 或 EXE AddressSanitizer 運行時間連結庫
/MT EXE clang_rt.asan-{arch}, clang_rt.asan_cxx-{arch}
/MT DLL clang_rt.asan_dll_thunk-{arch}
/MD clang_rt.asan_dynamic-{arch}, clang_rt.asan_dynamic_runtime_thunk-{arch}
/MTd EXE clang_rt.asan_dbg-{arch}, clang_rt.asan_dbg_cxx-{arch}
/MTd DLL clang_rt.asan_dbg_dll_thunk-{arch}
/MDd clang_rt.asan_dbg_dynamic-{arch}, clang_rt.asan_dbg_dynamic_runtime_thunk-{arch}

Visual Studio 整合

/fno-sanitize-address-vcasan-lib 編譯器選項

/fsanitize=address擲回 AddressSanitizer 例外狀況時,可改善 Visual Studio 偵錯體驗的額外連結庫中的選項連結。 這些連結庫稱為 VCAsan。 連結庫可讓 Visual Studio 在您的原始程式碼上顯示 AddressSanitizer 錯誤。 它們也會讓可執行檔在建立 AddressSanitizer 錯誤報告時產生損毀傾印。 如需詳細資訊,請參閱 Visual Studio AddressSanitizer擴充功能連結庫

選擇的連結庫取決於編譯程序選項,而且會自動連結至 中。

運行時間選項 VCAsan 版本
/MT libvcasan.lib
/MD vcasan.lib
/MTd libvcasand.lib
/MDd vcasand.lib

不過,如果您使用 編譯 /Zl (省略默認連結庫名稱),則必須手動指定連結庫。 如果沒有,您將會收到無法解析的外部符號連結錯誤。 以下是一些一般範例:

error LNK2001: unresolved external symbol __you_must_link_with_VCAsan_lib
error LNK2001: unresolved external symbol ___you_must_link_with_VCAsan_lib

您可以使用 選項,在編譯階段停用改善的 /fno-sanitize-address-vcasan-lib 偵錯。

ASAN_VCASAN_DEBUGGING 環境變數

編譯 /fsanitize=address 程式選項會產生二進位檔,以在運行時間公開記憶體安全性 Bug。 從命令行啟動二進位檔時,運行時間會報告錯誤,它會列印錯誤詳細數據。 然後,它會結束程式。 ASAN_VCASAN_DEBUGGING環境變數可以設定為在運行時間回報錯誤時立即啟動Visual Studio IDE。 此編譯程式選項可讓您在造成錯誤的精確行和數據行上檢視錯誤,並加疊於原始程式碼上。

若要啟用此行為,請在執行應用程式之前執行 命令 set ASAN_VCASAN_DEBUGGING=1 。 您可以執行 set ASAN_VCASAN_DEBUGGING=0來停用增強的偵錯體驗。

另請參閱

AddressSanitizer 概觀
AddressSanitizer 已知問題
AddressSanitizer 運行時間參考
AddressSanitizer 陰影位元組
AddressSanitizer 雲端或分散式測試
AddressSanitizer 調試程式整合
AddressSanitizer 錯誤範例