什麼是靜態分析#
靜態分析(Static Analysis)是指在不執行程式的情況下掃描原始碼,自動找出潛在缺陷的技術。許多現代編譯器和直譯器已內建基本的靜態分析功能,而獨立的專業工具(如 GrammaTech CodeSonar、Coverity Code Advisor、FindBugs、Polyspace Bug Finder 及各種 lint 工具)則能偵測更多種類的問題。
這些工具基於 形式化方法(formal methods)與 啟發式規則(heuristics)運作,理想上應在開發過程中持續執行,而非只在除錯時才使用。
靜態分析能偵測的常見缺陷#
- Null dereferences — 物件可能為 null 時仍呼叫其方法
- 並行錯誤與 race conditions — 例如 Java 中未使用
volatile的 spin-wait 迴圈,編譯器可能將欄位讀取提升到迴圈外 - 拼字錯誤(在不需宣告變數的語言中)— 測試
colour卻設定color - 陣列與緩衝區索引越界 — 經典的 off-by-one 錯誤
- 不可達程式碼 — 無窮迴圈後的
return永遠不會執行 - 未處理的例外 — catch 區塊中忽略了例外
- 未使用的變數與函式
- 數學錯誤 — 如除以零
- 程式碼重複
- 缺少樣板實作 — 如 C++ 的 Rule of Three/Rule of 0、Java 的
equals/hashCode不一致 - 資源洩漏 — 開啟的檔案未關閉
- 安全漏洞 — 如使用
gets()導致 buffer overflow - 語言陷阱 — 如 Java 中用
==比較字串物件
靜態分析工具可能同時存在 false negatives(漏報真正的 bug)和 false positives(對正確程式碼發出警告)。沒有任何工具能完美偵測所有問題,因為某些底層問題本質上是 不可判定的(undecidable)。
從編譯器警告開始#
善用編譯器本身的靜態檢查是最低成本的第一步:
| 語言/編譯器 | 建議選項 |
|---|---|
| GCC / ghc / clang | -Wall -Wextra -Wshadow |
| MSVC (C/C++) | /Wall /W4 |
| JavaScript | "use strict"; |
| Perl | use strict; use warnings; |
逐步消除警告的策略#
- 選擇不會淹沒你的最高警告等級
- 系統性地移除所有警告
- 達到零警告後,啟用
-Werror(GCC)或/WX(MSVC),將警告視為錯誤 - 這能防止新警告被淹沒在冗長的編譯輸出中
指定較高的最佳化等級(如
-O2)也會啟動額外的分析,產生更多有用的警告。
引入專業靜態分析工具#
當編譯器警告都處理完後,進一步導入專業工具:
- Wikipedia 的 static analysis tools 列表有超過 100 個工具
- 有些專注於特定領域,如安全漏洞或並行問題
- 不同工具偵測的缺陷類型不完全重疊,可以組合使用多個工具
- 投入時間調校設定,關閉不適用於你的程式風格的檢查,減少 false positives
整合到建置流程#
- 將靜態分析納入 build system,讓所有開發者能一致地執行檢查
- 納入 CI/CD pipeline,自動攔截被遺漏的問題
- 避免常見的反模式:團隊花大力氣清理靜態分析錯誤,然後失去興趣,讓新錯誤再度累積
重點回顧#
- 專業靜態分析工具能找出比編譯器警告更多的潛在缺陷
- 先善用編譯器本身的警告選項,再引入獨立工具
- 將靜態分析納入 build 與 CI 流程,確保問題不會悄悄溜進程式碼庫