什麼是靜態分析#

靜態分析(Static Analysis)是指在不執行程式的情況下掃描原始碼,自動找出潛在缺陷的技術。許多現代編譯器和直譯器已內建基本的靜態分析功能,而獨立的專業工具(如 GrammaTech CodeSonarCoverity Code AdvisorFindBugsPolyspace 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";
Perluse strict; use warnings;

逐步消除警告的策略#

  1. 選擇不會淹沒你的最高警告等級
  2. 系統性地移除所有警告
  3. 達到零警告後,啟用 -Werror(GCC)或 /WX(MSVC),將警告視為錯誤
  4. 這能防止新警告被淹沒在冗長的編譯輸出中

指定較高的最佳化等級(如 -O2)也會啟動額外的分析,產生更多有用的警告。

引入專業靜態分析工具#

當編譯器警告都處理完後,進一步導入專業工具:

  • Wikipedia 的 static analysis tools 列表有超過 100 個工具
  • 有些專注於特定領域,如安全漏洞並行問題
  • 不同工具偵測的缺陷類型不完全重疊,可以組合使用多個工具
  • 投入時間調校設定,關閉不適用於你的程式風格的檢查,減少 false positives

整合到建置流程#

  • 將靜態分析納入 build system,讓所有開發者能一致地執行檢查
  • 納入 CI/CD pipeline,自動攔截被遺漏的問題
  • 避免常見的反模式:團隊花大力氣清理靜態分析錯誤,然後失去興趣,讓新錯誤再度累積

重點回顧#

  • 專業靜態分析工具能找出比編譯器警告更多的潛在缺陷
  • 先善用編譯器本身的警告選項,再引入獨立工具
  • 將靜態分析納入 build 與 CI 流程,確保問題不會悄悄溜進程式碼庫