AddressSanitizer 執行時間

AddressSanitizer 執行時間程式庫會攔截常見的記憶體配置函式和作業,以檢查記憶體存取。 有數個不同的執行時間程式庫支援編譯器可能會產生的各種可執行檔案類型。 只要您在編譯時期傳遞 /fsanitize=address 選項,編譯器和連結器就會自動連結適當的執行時間程式庫。 您可以在連結時使用 /NODEFAULTLIB 選項來覆寫預設行為。 如需詳細資訊,請參閱AddressSanitizer 語言、組建和偵錯參考連結一節。

以下是連結至 AddressSanitizer 執行時間的執行時間程式庫清查,其中 {arch}i386x86_64

注意

這些程式庫會保留架構名稱的 Clang 慣例。 MSVC 慣例通常是 x86 和 x64,而不是 i386 和 x86_64。 它們是指相同的架構。

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}
MT EXE YES clang_rt.asan_dbg-{arch}, clang_rt.asan_dbg_cxx-{arch}
MT DLL YES clang_rt.asan_dbg_dll_thunk-{arch}
MD 任一 YES clang_rt.asan_dbg_dynamic-{arch}, clang_rt.asan_dbg_dynamic_runtime_thunk-{arch}

使用 cl /fsanitize=address 編譯時,編譯器會產生管理及檢查 陰影位元組的指示。 您的程式會使用此檢測來檢查堆疊、堆積或全域範圍中的記憶體存取。 編譯器也會產生描述堆疊和全域變數的中繼資料。 此中繼資料可讓執行時間產生精確的錯誤診斷:原始程式碼中的函式名稱、行和資料行。 結合時,編譯器檢查和執行時間程式庫可以在執行時間遇到許多類型的 記憶體安全性錯誤 時精確診斷。

函式攔截

AddressSanitizer 可透過許多熱修補技術來達成函式攔截。 這些技術 最好記載在原始程式碼本身內

執行時間程式庫會攔截許多常見的記憶體管理和記憶體操作函式。 如需清單,請參閱 已攔截函式的 AddressSanitizer 清單。 配置攔截器會管理與每個配置呼叫相關的中繼資料和陰影位元組。 每次呼叫 或 deletemalloc CRT 函式時,攔截器都會在 AddressSanitizer 陰影記憶體區域中設定特定值,以指出這些堆積位置目前是否可存取,以及配置界限為何。 這些陰影位元組允許編譯器產生的 陰影位元組 檢查,以判斷負載或存放區是否有效。

攔截不保證成功。 如果函式序言太短而 jmp 無法寫入,攔截可能會失敗。 如果發生攔截失敗,程式會 debugbreak 擲回 並停止。 如果您附加偵錯工具,則會清除攔截問題的原因。 如果您有此問題, 請回報錯誤

注意

使用者可以選擇性地將環境變數 ASAN_WIN_CONTINUE_ON_INTERCEPTION_FAILURE 設定為任何值,以嘗試繼續通過失敗的攔截。 繼續發生攔截失敗可能會導致該函式遺漏的錯誤報表。

自訂配置器和 AddressSanitizer 執行時間

AddressSanitizer 執行時間透過) 提供通用配置器介面 、 malloc/freedeleteHeapFree/HeapAllocnew/ (RtlAllocateHeap/RtlFreeHeap 的攔截器。 許多程式都基於一個或另一個原因而使用自訂配置器,例如任何使用 dlmalloc 的程式,或是使用 std::allocator 介面和 VirtualAlloc() 的解決方案。 編譯器無法自動將陰影記憶體管理呼叫新增至自訂配置器。 使用者必須負責使用 提供的手動有害介面。 此 API 可讓這些配置器使用現有的 AddressSanitizer 執行時間和 陰影位元組 慣例正常運作。

手動 AddressSanitizer 有害介面

啟用的介面很簡單,但它會對使用者施加對齊限制。 使用者可藉由匯 sanitizer/asan_interface.h 入 來匯入這些原型。 以下是介面函式原型:

void __asan_poison_memory_region(void const volatile *addr, size_t size);
void __asan_unpoison_memory_region(void const volatile *addr, size_t size);

為了方便起見, AddressSanitizer 介面標頭檔 會提供包裝函式宏。 這些宏會檢查 AddressSanitizer 功能是否在編譯期間啟用。 它們可讓您的原始程式碼在不需要時省略有害函式呼叫。 這些宏應該優先于直接呼叫上述函式:

#define ASAN_POISON_MEMORY_REGION(addr, size)
#define ASAN_UNPOISON_MEMORY_REGION(addr, size)

AddressSanitizer 有害的對齊需求

陰影位元組的任何手動有害都必須考慮對齊需求。 如有必要,使用者必須新增填補,讓陰影位元組結束于陰影記憶體中的位元組界限。 AddressSanitizer 陰影記憶體中的每個位都會編碼應用程式記憶體中單一位元組的狀態。 此編碼表示每個配置的大小總計,包括任何填補,都必須對齊 8 位元組界限。 如果不符合對齊需求,可能會導致錯誤報表不正確。 不正確的報告可能會顯示為遺漏的報告, (誤判) ,或回報非錯誤 (誤判) 。

如需對齊需求和潛在問題的圖例,請參閱提供的 ASan 對齊範例。 其中一個是小型程式,顯示手動陰影記憶體有害可能會發生錯誤。 第二個是使用 介面手動有害的範例實作 std::allocator

執行時間選項

Microsoft C/C++ (MSVC) 會根據 llvm-project 存放庫中的 Clang AddressSanitizer 運行時間,使用執行時間。 因此,大部分的執行時間選項會在兩個版本之間共用。 這裡提供公用 Clang 執行時間選項的完整清單。 我們會記載下列各節的一些差異。 如果您發現未如預期運作的選項, 請回報錯誤

不支援的 AddressSanitizer 選項

  • detect_container_overflow
  • unmap_shadow_on_exit

注意

AddressSanitizer 執行時間選項 halt_on_error 無法以您預期的方式運作。 在 Clang 和 MSVC 執行時間程式庫中,許多錯誤類型都會被視為 不可持續性,包括大部分的記憶體損毀錯誤。

如需詳細資訊,請參閱 Clang 12.0 的差異 一節。

MSVC 特定的 AddressSanitizer 執行時間選項

  • windows_hook_legacy_allocators布林值,設定為 true 以啟用 和 LocalAlloc 配置器的攔截 GlobalAlloc

注意

本文撰寫時,公用 llvm-project 執行時間無法使用此選項 windows_hook_legacy_allocators 。 選項最終可能會貢獻回公用專案;不過,它取決於程式碼檢閱和社群接受。

在 AddressSanitizer 為實驗性時,先前是加入宣告功能的選項 windows_hook_rtl_allocators ,現在預設會啟用。

  • iat_overwrite 字串,預設設定為 "error" 。 其他可能的值為 "protect""ignore" 。 某些模組可能會覆寫 import address table 其他模組的 ,以自訂特定函式的實作。 例如,驅動程式通常會針對特定硬體提供自訂實作。 選項 iat_overwrite 會管理 AddressSanitizer 執行時間的保護,以防止特定 memoryapi.h 函式的覆寫。 執行時間目前會追蹤 VirtualAllocVirtualProtectVirtualQuery 函式以保護。 此選項適用于 Visual Studio 2022 17.5 版 Preview 1 和更新版本。 下列 iat_overwrite 值可控制在覆寫受保護函式時執行時間如何回應:

    • 如果設定為 "error" (預設) ,則每當偵測到覆寫時,執行時間就會報告錯誤。
    • 如果設定為 "protect" ,執行時間會嘗試避免使用覆寫的定義並繼續進行。 實際上,函式的原始 memoryapi 定義是從執行時間內部使用,以避免無限遞迴。 進程中的其他模組仍會使用覆寫的定義。
    • 如果設定為 "ignore" ,執行時間不會嘗試更正任何覆寫的函式,並繼續執行。

Windows) (攔截函式的 AddressSanitizer 清單

AddressSanitizer 執行時間經常性修補許多函式,可在執行時間啟用記憶體安全性檢查。 以下是 AddressSanitizer 執行時間所監視之函式的非詳盡清單。

預設攔截器

選擇性攔截器

只有在啟用 AddressSanitizer 執行時間選項時,才會安裝此處所列的攔截器。 設定 windows_hook_legacy_allocatorstrue 以啟用舊版配置器攔截。 set ASAN_OPTIONS=windows_hook_legacy_allocators=true

另請參閱

AddressSanitizer 概觀
AddressSanitizer 已知問題
AddressSanitizer 組建和語言參考
AddressSanitizer 陰影位元組
AddressSanitizer 雲端或分散式測試
AddressSanitizer 偵錯工具整合
AddressSanitizer 錯誤範例