AddressSanitizer
概觀
C 和 C++ 語言功能強大,但可能會遭受影響程式正確性和程式安全性的一類 Bug。 從 Visual Studio 2019 16.9 版開始,Microsoft C/C++ 編譯程式 (MSVC) 和 IDE 支援 AddressSanitizer 清理工具。 AddressSanitizer (ASan) 是編譯程式和運行時間技術,可公開許多難以尋找的 Bug,且沒有誤判:
- Alloc/dealloc 不符和/
new
delete
類型不符 - 堆積的配置太大
calloc
溢位 和alloca
溢位- 免費雙精度 浮點數, 並在免費後使用
- 全域變數溢位
- 堆積緩衝區溢位
- 對齊值無效
memcpy
和strncat
參數重疊- 堆疊緩衝區溢位 和 下溢
- 堆疊在之後
return
使用,並在 範圍之後使用 - 記憶體使用量在中毒后使用
使用 AddressSanitizer 減少花費的時間:
- 基本正確性
- 跨平臺可移植性
- 安全性
- 壓力測試
- 整合新的程序代碼
AddressSanitizer 最初 由 Google 引進,提供運行時間錯誤尋找技術,直接使用您現有的組建系統和現有的測試資產。
AddressSanitizer 會與 Visual Studio 項目系統、CMake 建置系統和 IDE 整合。 專案可以藉由設定項目屬性,或使用一個額外的編譯程式選項來啟用 AddressSanitizer: /fsanitize=address
。 新的選項與 x86 和 x64 的所有優化和組態層級相容。 不過,它與編輯和繼續、累加連結和 /RTC
不相容。
從 Visual Studio 2019 16.9 版開始,Microsoft的 AddressSanitizer 技術可讓您與 Visual Studio IDE 整合。 當清理器在運行時間發現 Bug 時,此功能可以選擇性地建立損毀傾印檔案。 如果您在執行程式之前設定 ASAN_SAVE_DUMPS=MyFileName.dmp
環境變數,則會使用額外的元數據來建立損毀傾印檔案,以有效 進行精確診斷 Bug 的驗屍 偵錯。 這些傾印檔案可讓您更輕鬆地使用 AddressSanitizer:
- 本機計算機測試
- 內部部署分散式測試
- 用於測試的雲端式工作流程
安裝 AddressSanitizer
C++Visual Studio 安裝程式 中的工作負載預設會安裝 AddressSanitizer 連結庫和 IDE 整合。 不過,如果您要從舊版Visual Studio 2019升級,請使用安裝程式在升級之後啟用 ASan 支援。 您可以透過 [工具取得工具和>功能],從 Visual Studio 主功能表開啟安裝程式...從 Visual Studio 安裝程式 選擇 [修改],在現有的Visual Studio安裝上選取 [修改],以進入下列畫面。
注意
如果您在新的更新上執行 Visual Studio,但尚未安裝 ASan,當您執行程式代碼時會收到錯誤:
LNK1356:找不到連結庫 'clang_rt.asan_dynamic-i386.lib'
使用 AddressSanitizer
使用下列任何常見的開發方法,開始使用 /fsanitize=address
編譯程式選項來建置可執行檔:
- 命令行組建
- Visual Studio 專案系統
- Visual Studio CMake 整合
重新編譯,然後正常執行程式。 此程式代碼產生會 公開許多精確診斷的錯誤類型。 這些錯誤會以三種方式回報:在調試程式 IDE 中、命令行上,或儲存在新類型的傾印檔案中,以進行精確的離線處理。
Microsoft建議您在這三個標準工作流程中使用 AddressSanitizer:
開發人員內部迴圈
CI/CD - 持續整合/持續開發
- 錯誤報告 - 新增 AddressSanitizer 傾印檔案
模糊 - 使用 libFuzzer 包裝函式建置
- Azure OneFuzz
- 本機電腦
本文涵蓋啟用先前列出的三個工作流程所需的資訊。 此資訊專屬於 AddressSanitizer 的平臺相依 Windows 10 實作(及更新版本)。 本檔補充Google、Apple和 GCC 已發佈的優秀檔。
注意
支援僅限於 Windows 10 和更新版本上的 x86 和 x64。 請傳送意見反應 給我們,以瞭解您想要在未來版本中看到的內容。 您的意見反應可協助我們排定未來其他清理程式的優先順序,例如 /fsanitize=thread
、 /fsanitize=leak
、 /fsanitize=memory
、 /fsanitize=undefined
或 /fsanitize=hwaddress
。 如果您遇到問題,您可以 在這裡 回報 Bug。
從開發人員命令提示字元使用 AddressSanitizer
在/fsanitize=address
開發人員命令提示字元中使用編譯程式選項,以啟用 AddressSanitizer 運行時間的編譯。 此選項/fsanitize=address
與所有現有的C++或 C 優化層級相容(例如 、/Od
、/O1
/O2
、、 /O2 /GL
和 PGO
)。 此選項適用於靜態和動態CCT(例如、/MD
/MDd
、 /MT
和 /MTd
)。 不論您是建立 EXE 還是 DLL,它都適用。 針對呼叫堆疊的最佳格式設定,需要偵錯資訊。 在下列範例中, cl /fsanitize=address /Zi
會在命令行上傳遞。
AddressSanitizer 連結庫 (.lib 檔案) 會自動為您連結。 如需詳細資訊,請參閱 AddressSanitizer 語言、組建和偵錯參考。
範例 - 基本全域緩衝區溢位
// basic-global-overflow.cpp
#include <stdio.h>
int x[100];
int main() {
printf("Hello!\n");
x[100] = 5; // Boom!
return 0;
}
使用 Visual Studio 2019 的開發人員命令提示字元,使用 編譯main.cpp
/fsanitize=address /Zi
當您在命令行執行產生的 main.exe
時,它會建立下列格式化的錯誤報告。
請考慮重繪的紅色方塊,以醒目提示七個主要資訊:
錯誤報告中有七個紅色醒目提示可識別關鍵資訊片段。 它們會對應至此螢幕快照後面的編號清單。 編號方塊反白顯示下列文字:1) global-buffer-overflow 2) 大小為 4 3) basic-global-overflow.cpp 7 4) 在 'basic-global-overflow.cpp:3:8' 5) 大小為 400 6) 00 00 00[f9]f9 7) 方塊的右方,位於陰影位元組圖例區域,並包含全域紅色區域: f9
紅色醒目提示,從上到下
- 記憶體安全性 Bug 是全域緩衝區溢位。
- 儲存在任何使用者定義變數外部的 4 個字節 (32 位)。
- 存放區是在第 7 行檔案中定義的函
main()
basic-global-overflow.cpp
式中發生。 - 名為
x
的變數定義於第 3 行的 basic-global-overflow.cpp,從數據行 8 開始 - 這個全域變數
x
的大小為 400 個字節 - 描述商店目標地址的確切 陰影位元組 具有 值
0xf9
- 陰影位元組圖例說
0xf9
是右邊填補的區域int x[100]
注意
呼叫堆疊中的函式名稱是透過 運行時間在錯誤時叫用的 LLVM 符號化程式 所產生。
在 Visual Studio 中使用 AddressSanitizer
AddressSanitizer 已與 Visual Studio IDE 整合。 若要開啟 MSBuild 專案的 AddressSanitizer,請以滑鼠右鍵按兩下 方案總管 中的項目,然後選擇 [屬性]。 在 [屬性頁] 對話框中,選取 [組態屬性>C/C++>General],然後修改 [啟用 AddressSanitizer] 屬性。 選取 [確定] 儲存您的變更。
若要從 IDE 建置,請退出宣告任何 不相容的選項。 針對使用 /Od
(或偵錯模式編譯的現有專案),您可能需要關閉下列選項:
- 關閉 編輯並繼續
- 關閉
/RTC1
(執行時間檢查) - 關閉
/INCREMENTAL
(累加連結)
若要建置並執行調試程式,請按 F5。 Visual Studio 中會出現例外 狀況擲回 視窗:
從 Visual Studio 使用 AddressSanitizer:CMake
若要為建立目標 Windows 的 CMake 專案啟用 AddressSanitizer,請遵循下列步驟:
開啟 IDE 頂端工具列中的 [組態] 下拉式清單,然後選取 [管理組態]。
這會開啟 CMake 專案設定編輯器,以反映專案
CMakeSettings.json
檔案的內容。選擇編輯器中的 [ 編輯 JSON] 連結。 此選取範圍會將檢視切換為原始 JSON。
在 中
"configurePresets":
將下列代碼段新增至"windows-base"
預設,以開啟 Address Sanitizer:"environment": { "CFLAGS": "/fsanitize=address", "CXXFLAGS": "/fsanitize=address" }
"configurePresets"
看起來會像這樣,之後:"configurePresets": [ { "name": "windows-base", "hidden": true, "generator": "Ninja", "binaryDir": "${sourceDir}/out/build/${presetName}", "installDir": "${sourceDir}/out/install/${presetName}", "cacheVariables": { "CMAKE_C_COMPILER": "cl.exe", "CMAKE_CXX_COMPILER": "cl.exe" }, "condition": { "type": "equals", "lhs": "${hostSystemName}", "rhs": "Windows" }, "environment": { "CFLAGS": "/fsanitize=address", "CXXFLAGS": "/fsanitize=address" } },
如果指定 [編輯後繼續],位址清理程式將無法運作。
/ZI
新 CMake 專案預設會啟用此專案。 在 中CMakeLists.txt
,將開頭為 的行批注化 (前置詞set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT"
為#
)。 之後,該行看起來會像這樣:# set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<IF:$<AND:$<C_COMPILER_ID:MSVC>,$<CXX_COMPILER_ID:MSVC>>,$<$<CONFIG:Debug,RelWithDebInfo>:EditAndContinue>,$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>>")
輸入 Ctrl+S 以儲存此 JSON 檔案
從 Visual Studio 選單選擇來清除 CMake 快取目錄,然後重新設定:專案>刪除快取和重新設定。 當提示出現清除快取目錄並重新設定時,請選擇 [是 ]。
以下欄內容取代原始程式檔的內容(例如
CMakeProject1.cpp
, ) :// CMakeProject1.cpp : Defines the entry point for the application #include <stdio.h> int x[100]; int main() { printf("Hello!\n"); x[100] = 5; // Boom! return 0; }
選擇 F5 以重新編譯並在調試程式下執行。
此螢幕快照會從 CMake 組建擷取錯誤。
AddressSanitizer 損毀傾印
我們在 AddressSanitizer 中引進了新功能,以搭配雲端和分散式工作流程使用。 此功能允許在 IDE 中離線檢視 AddressSanitizer 錯誤。 錯誤會覆寫在您的來源之上,就像您在即時偵錯會話中遇到的一樣。
分析 Bug 時,這些新的傾印檔案可能會導致效率。 您不需要重新執行,或尋找遠端數據,或尋找離線的電腦。
若要產生新類型的傾印檔案,可在 Visual Studio 中於稍後於另一部電腦上檢視:
set ASAN_SAVE_DUMPS=MyFileName.dmp
從 Visual Studio 16.9 開始,您可以在原始程式碼之上顯示 精確診斷的錯誤,並儲存在檔案 *.dmp
中。
這項新的損毀傾印功能 可啟用雲端式工作流程或分散式測試。 它也可以用來在任何案例中提出詳細的可採取動作的錯誤。
範例錯誤
AddressSanitizer 可以偵測數種記憶體誤用錯誤。 以下是當您使用 AddressSanitizer (/fsanitize=address
) 編譯程式選項編譯的二進位檔時所回報的許多運行時錯誤:
alloc-dealloc-mismatch
allocation-size-too-big
calloc-overflow
double-free
dynamic-stack-buffer-overflow
global-buffer-overflow
heap-buffer-overflow
heap-use-after-free
invalid-allocation-alignment
memcpy-param-overlap
new-delete-type-mismatch
stack-buffer-overflow
stack-buffer-underflow
stack-use-after-return
stack-use-after-scope
strncat-param-overlap
use-after-poison
如需範例的詳細資訊,請參閱 AddressSanitizer 錯誤範例。
Clang 12.0 的差異
MSVC 目前在兩個功能區域中與 Clang 12.0 不同:
- stack-use-after-scope - 此設定預設為開啟,且無法關閉。
- stack-use-after-return - 這項功能需要額外的編譯程序選項,而且無法透過設定
ASAN_OPTIONS
來使用。
這些決策是為了減少傳遞此第一個版本所需的測試矩陣。
未包含可能導致 Visual Studio 2019 16.9 誤判的功能。 該專業領域在考慮具有數十年現有程序代碼的 Interop 時,強制執行了所需的有效測試完整性。 後續版本可能會考慮更多功能:
如需詳細資訊,請參閱 使用 MSVC 建置 AddressSanitizer。
現有的產業檔
AddressSanitizer 技術的這些語言和平臺相依實作已存在廣泛的檔。
這篇關於 AddressSanitizer (external) 的開創性檔描述實作。
另請參閱
AddressSanitizer 已知問題
AddressSanitizer 組建和語言參考
AddressSanitizer 運行時間參考
AddressSanitizer 陰影位元組
AddressSanitizer 雲端或分散式測試
AddressSanitizer 調試程式整合
AddressSanitizer 錯誤範例