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
選項會檢測程序代碼中的記憶體參考,以攔截運行時間的記憶體安全性錯誤。 檢測攔截會載入、儲存、範圍和 alloca
CRT函式。 它可以偵測隱藏的錯誤,例如超出範圍、無後使用、使用后範圍等等。 如需在運行時間偵測到的錯誤非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 新增至預設連結庫清單。 它也會設定下列清理工具涵蓋範圍選項:
- Edge 檢測點 (
/fsanitize-coverage=edge
), - 內嵌8位計數器 (
/fsanitize-coverage=inline-8bit-counters
), - 比較 (
/fsanitize-coverage=trace-cmp
)、 和 - 整數除法 (
/fsanitize-coverage=trace-div
)。
建議您搭配 /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 攔截這些錯誤,您必須:
- 使用
/fsanitize-address-use-after-return
選項進行編譯。 - 在執行程式之前,請執行
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}
是 i386
或 x86_64
。
這些連結庫會針對架構名稱使用 Clang 慣例。 MSVC 慣例通常是 x86
, x64
而不是 i386
和 x86_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 錯誤範例