一個 bug 通常不是獨一無二的#
一個地方的錯誤很可能在其他地方也存在,原因包括:
- 開發者以同樣的方式犯錯
- 某個容易被誤用的 API
- 有問題的程式碼被複製貼上到其他地方
在成熟的開發文化和安全關鍵的工作中,修復一個 defect 後不會就此停止。目標是修復整個類別的 defect,並確保類似的問題不會在未來再次出現。
搜尋同類型的問題#
例如你修復了一個除以零的問題:
double a = getWeight(subNode) / totalWeight;接下來應該搜尋所有其他除以 totalWeight 的地方:
grep -r '/ *totalWeight' .然後考慮是否有其他除法也可能失敗。一個 Unix pipeline 可以幫助你在四百萬行 C 程式碼中快速篩選:
# Find divisions, assuming spaces around the / operator
grep -r ' / ' . |
# Eliminate those involving sizeof
grep -v '/ sizeof' |
# Color divisors for easy inspection and
# eliminate divisions involving numerical or symbolic constants
grep --color=always ' / [^0-9A-Z][^,;)]*' |
# Remove duplicates
sort -u這些篩選器將嫌疑行數從 5,731 縮減到 5,045,再到 2,032,最後到 1,923——一個可以在合理時間內人工檢查的數量。雖然篩選器不是百分百準確(
sizeof可以回傳零、symbolic constant 可以為零),但這比聲稱「檢查所有除法太費工」然後什麼都不做要好得多。
預防未來的同類問題#
考慮採取措施防止類似 fault 再次出現:
- 隱藏危險 API 並提供安全替代:
#define gets(x) USE_FGETS_RATHER_THAN_GETS(x)使用 gets(以 buffer overflow 聞名)的程式將無法編譯或連結。
- 如果 fault 源自不正確的型別處理,引入更嚴格的型別檢查
- 加入 static analysis 或加強其設定來自動偵測類似問題
重點回顧#
- 修復一個 fault 後,找出並修復類似的 fault,並採取措施確保它們不會在未來再次出現