Attention: Here be dragons
This is the latest
(unstable) version of this documentation, which may document features
not available in or compatible with released stable versions of Godot.
Checking the stable version of the documentation...
使用 Sanitizer
什麼是 Sanitizer?
Sanitizer 是一種靜態檢測工具,能夠協助找出傳統除錯器通常無法發現的錯誤。這在持續整合流程中,與 單元測試 結合時特別有用。
可於 Windows、macOS 與 Linux 上,透過 Clang(LLVM)、GCC 或 Visual Studio 編譯器使用 Sanitizer。部分平台 也可能提供其專屬的 Sanitizer。同一種 Sanitizer 若由不同編譯器提供,其輸出結果與行為可能會略有差異。
在 Godot 中使用 Sanitizer
Sanitizer 必須 重新編譯執行檔,這表示無法直接用官方 Godot 執行檔來運作 Sanitizer。
啟用任一種 Sanitizer 進行 編譯 時,產生的執行檔名稱會加上 .san 後綴,以和未啟用 Sanitizer 的版本做區分。
由於需要進行許多額外的執行時檢查,因此會影響效能,記憶體用量也會增加。部分 Sanitizer 可以於單一建置中同時啟用多種組合,但需注意同時啟用多個 Sanitizer 會大幅降低效能,導致產生的執行檔運作極慢。
某些選項可以透過環境變數傳遞給 Sanitizer,無需重新編譯執行檔。
位址 Sanitizer(ASAN)
適用於 Clang 與 GCC。
支援平台: Linux、macOS、Windows(Visual Studio)、Web
Address Sanitizer 通常是最常用的工具。它可以偵測像是緩衝區溢位或越界存取等問題。如果引擎當機並顯示像是 free(): invalid pointer 的訊息,通常就是緩衝區溢位所導致的。(這個訊息是由 C 執行時環境印出的,不是 Godot 印出的。)
在某些情況下(如偵測未初始化的記憶體讀取),位址 Sanitizer 並不適用,請改用 記憶體 Sanitizer(MSAN)。
你也可以在*執行* Godot 前(非編譯時)設定 ASAN_OPTIONS=detect_stack_use_after_return=1 環境變數,來偵測函式返回後的存取行為。此功能會增加位址 Sanitizer 的執行時負擔,建議僅在必要時啟用。
如需在 Godot 編譯時啟用位址 Sanitizer,請於編譯指令加入 use_asan=yes SCons 參數。啟用 ASAN 通常會讓產生的執行檔效能降低約兩倍。
警告
由於 設計決策,位址、記憶體及執行緒 Sanitizer 彼此互斥,單一執行檔僅能啟用其中之一。
洩漏 Sanitizer(LSAN)
適用於 Clang 與 GCC。
支援平台: Linux、Web
洩漏 Sanitizer 能偵測記憶體洩漏,也就是程式已經不再使用、但未釋放的記憶體。如果程式長時間執行,最終可能造成記憶體耗盡。由於 Godot 可能會運作於 專用伺服器 上數月甚至數年不重啟,因此發現洩漏時務必修正。
如需於 Godot 建置啟用洩漏 Sanitizer,請於編譯指令加入 use_lsan=yes SCons 參數。啟用 LSAN 對效能影響很小,但程式結束時因進行洩漏檢查,結束速度會明顯變慢。
記憶體 Sanitizer(MSAN)
僅支援 Clang,不支援 GCC。
支援平台: Linux
記憶體 Sanitizer 補足了 位址 Sanitizer(ASAN) 的不足。與位址 Sanitizer 不同,MSAN 能偵測未初始化記憶體的讀取行為。
如需在 Godot 建置時啟用記憶體 Sanitizer,請在編譯時加入 use_msan=yes SCons 參數。啟用 MSAN 通常會讓產生的執行檔效能降低約三倍。
警告
由於 設計決策,位址、記憶體及執行緒 Sanitizer 彼此互斥,單一執行檔僅能啟用其中之一。
執行緒 Sanitizer(TSAN)
適用於 Clang 與 GCC。
支援平台: Linux、macOS
執行緒 Sanitizer 用於追蹤多執行緒運作時的競爭條件。競爭條件是指多個執行緒同時嘗試修改同一份資料。作業系統排程執行緒的順序是不可預測的,這會導致僅偶發的不正確行為,因此也很難追蹤。為避免競爭條件,需加上鎖定,確保同一時間僅有一個執行緒能存取共享資料。
如需於 Godot 建置啟用執行緒 Sanitizer,請於編譯時加入 use_tsan=yes SCons 參數。啟用 TSAN 通常會讓執行檔效能降低約 10 倍,且記憶體使用量大幅增加(約 8 倍)。
警告
由於 設計決策,位址、記憶體及執行緒 Sanitizer 彼此互斥,單一執行檔僅能啟用其中之一。
備註
在 Linux 上,如果你遇到以下錯誤:
FATAL: ThreadSanitizer: unexpected memory mapping
你可能需要暫時降低系統中的位址空間配置隨機化(ASLR)熵值,可以執行以下指令:
sudo sysctl vm.mmap_rnd_bits=28
或者建議直接完全停用 ASLR,可以執行:
sudo sysctl kernel.randomize_va_space=0
等你完成 ThreadSanitizer 的使用後,請用下列指令提高 ASLR 熵值:
sudo sysctl vm.mmap_rnd_bits=32
或用下列指令重新啟用 ASLR:
sudo sysctl kernel.randomize_va_space=2
重新啟動你的電腦也會將 ASLR 狀態恢復為預設值。
請儘快還原這些設定,因為降低 ASLR 熵值或完全停用 ASLR 會帶來安全風險。
未定義行為 Sanitizer(UBSAN)
適用於 Clang 與 GCC。
支援平台: Linux、macOS、Web
未定義行為 Sanitizer 用於追蹤程式出現隨機或不可預期行為的情境。這通常源於被編譯器接受、但並不*正確*的 C/C++ 程式碼。使用不同最佳化選項編譯,同樣的未定義行為也可能導致不同執行結果。
如需於 Godot 建置啟用未定義行為 Sanitizer,請於編譯時加入 use_ubsan=yes SCons 參數。啟用 UBSAN 對效能影響極小。
特定平台 Sanitizer
Web
當你 為 Web 編譯 時,還有另外兩個可用的 Sanitizer SCons 選項:
use_assertions=yes會啟用 Emscripten 執行時斷言,可用於偵測各類錯誤。use_safe_heap=yes會啟用 Emscripten 的 SAFE_HEAP Sanitizer。其功能類似於 ASAN,但專注於 WebAssembly 特有的問題。SAFE_HEAP無法保證和同一執行檔內的 ASAN 與 UBSAN 相容,因此可能需分開建置。