前言
最近遇到一個有趣的 bug,趁這次機會試試看用 AI 來協助除錯。整個過程蠻有收穫的,分享給大家參考。
問題發現
Bug 描述
在測試登出功能時,發現 app 會發生 crash。追蹤後發現是在登出時,API 會呼叫底層的解密函式,但解密用的 key 明顯有問題,導致解密失敗而引發錯誤。
由於這段流程是另一位同事負責開發的,程式碼邏輯比較複雜,短時間內看不出根本原因。於是先採取防禦性做法:如果 key 為空值,就將解密失敗的錯誤吃掉不處理。判斷後認為這樣不會影響 UI 操作,因為登出後 key 會重新取得。測試後確認沒問題,就先把這個 bug 暫時壓下來了。
深入追查
第一回合:初步分析
趁著有空檔,決定詳細釐清這個問題。想試試 AI 的能耐,於是下了第一個 prompt:
分析
SessionManager的processEncryptedData方法中,為何會發生bytesToTrim > currentLength的錯誤?從呼叫該方法的地方分析可能發生的原因。
AI 給出了幾個可能的原因:
-
加密數據損壞或截斷
- 網路傳輸過程中數據包丟失或損壞
- API 回應中的加密字串不完整
- 解密後的最後一個字節值異常大
-
錯誤的加密算法或密鑰
- 使用了錯誤的解密密鑰或 IV
- Session key 交換失敗,但程式繼續使用無效密鑰解密
- 解密產生亂碼
-
Hex 字串轉換錯誤
- 包含非法字符、長度不是偶數、部分缺失等問題
-
AES CBC 解密失敗但沒有檢查錯誤
- Whitebox 密鑰準備失敗
- IV 不匹配
- 數據長度不符合 AES 塊大小要求
-
PKCS7 Padding 格式錯誤
- 加密時使用了錯誤的 padding 方式
- 最後字節不是有效的 padding 長度值 (1-16)
-
多重解密處理錯誤
- 數據被重複解密或解密順序錯誤
-
記憶體緩衝區問題
- 緩衝區大小分配錯誤或溢出
AI 也分析了呼叫鏈:
API 回應 → DataTransformer → CryptoHandler → decryptSessionKey → processEncryptedData
評估: 這些分析大多是從相關函式內部找錯誤,但沒有太大用處,感覺方向不太對。
第二回合:調整思路
我調整了 prompt 的方向:
登出時會發生此錯誤,從登出後重新呼叫相關 API 的流程來分析原因。
這次 AI 的分析就切中要點了!它指出了幾個關鍵情況:
情況 1:競爭條件(Race Condition)
- 使用者點擊登出時,可能還有進行中的 API 請求
cancelAllRequests()取消請求,但部分回應可能已經在解密處理中- 解密過程使用的是登出前的有效密鑰,但處理的是已被截斷或損壞的回應數據
情況 2:密鑰狀態不一致
- 登出過程中 sessionManager 狀態可能部分清除
- 相關的 session 在伺服器端已失效
- 後續的 API 回應使用失效的加密上下文進行解密
情況 3:網路請求取消時機
cancelAllRequests()執行時,某些請求可能正在接收數據- 數據被截斷但仍被傳遞給解密程序
- hex 字串轉換處理不完整的數據
情況 4:登出 API 回應處理
- 伺服器可能回傳空內容或錯誤格式的加密數據
- 解密時觸發 padding 錯誤
具體發生時序:
- 使用者點擊登出
logout()被呼叫cancelAllRequests()取消所有進行中請求- 同時執行登出 API 請求
- 某個被取消的請求回應仍在處理中
- 嘗試解密已損壞/截斷的數據
processEncryptedData中bytesToTrim計算錯誤bytesToTrim > currentLength導致錯誤
可是依照這個分析去修改後,登出後的 UX 出現了問題。
第三回合:提供關鍵線索
我 trace code 發現登出後又呼叫了其他 API,這些會被 cancel 影響到。於是給了更具體的線索:
原呼叫
APIClient.logout的地方會馬上又呼叫其他 API,必須等 cancel 完成後才能再進行其他 API。
這次 AI 給出的修正方案就很完整了:
最終解決方案
修正內容
-
修正
APIClient.logout()為 async 方法- 確保登出、取消請求、重置狀態按順序執行
-
修正
AppCoordinator.logout()等待完成- 使用
await APIClient.logout()確保完全結束後再進行後續操作
- 使用
-
修正其他關鍵地方的登出調用
LoginViewModel和AuthenticationFlow中的調用都改為await
-
關於
AppContext.logout()MenuViewController中是通過 Notification 機制觸發- 最終會觸發
AppCoordinator中的 logout 方法 - 已修正最關鍵的路徑
修正效果
✅ 避免競爭條件 - 登出 API 完成後才取消其他請求
✅ 確保狀態一致 - 重置加密狀態防止使用失效密鑰
✅ 防止重疊 API 調用 - 等待完全取消後才進行後續操作
心得總結:用 AI 修 Bug 的五個要點
經過這次經驗,我整理出使用 AI 輔助除錯的幾個心得:
1. 先分析,不要直接要求修正
一開始不要叫 AI 直接修改程式碼,而是先讓它分析問題。因為分析的方向有可能不對,或者給的線索不夠,它也看不出真正的原因。
2. 確認分析方向後再請求修改
確定 AI 的分析有道理之後,再讓它嘗試修改。這樣可以避免走錯方向浪費時間。
3. 根據測試結果提供更多線索
測試完後,依據測試的狀況給 AI 更多線索。這種迭代式的對話往往能找出真正的問題點。
4. 讓 AI 做總結
可以讓 AI 總結整個修正內容,這對寫 git commit message 或技術文件很有幫助。
5. 適合場景:修別人寫的 Bug
AI 特別適合用來修別人寫的 bug。對於自己寫的程式碼,因為已經很熟悉邏輯,自己修可能還是比較快且正確。但面對不熟悉的程式碼時,AI 可以作為很好的第二雙眼睛。
結語: AI 不是萬能的,但在正確的使用方式下,確實能成為開發者的好幫手。關鍵是要懂得如何引導它,給予適當的上下文和線索。希望這次經驗分享對大家有幫助!
留言