Try to Catch This: Try-Catch in Solidity Reviewed
三句話摘要
Solidity try-catch 的三個邊緣案例:哪些 revert 不會被捕獲,開發者與審計員常踩的坑。 try-catch 只捕獲「外部呼叫本體」的 revert,Solidity 在進入 try 之前插入的 EXTCODESIZE 檢查、回傳長度驗證,以及傳入參數的內部呼叫,都在保護範圍之外。 三種 catch 子句各司其職:`error` 捕獲帶原因字串的正常 revert;`panic` 捕獲算術溢位、陣列越界、除以零等程式錯誤;低層級 catch 負責其他所有情況,包括 custom error、out of gas,以及 error/panic 解碼失敗。
重點整理
重點- 1
三種 catch 子句各司其職:`error` 捕獲帶原因字串的正常 revert;`panic` 捕獲算術溢位、陣列越界、除以零等程式錯誤;低層級 catch 負責其他所有情況,包括 custom error、out of gas,以及 error/panic 解碼失敗。
- 2
參數的內部呼叫在 try 外執行:若傳入外部函式的參數本身是一個內部呼叫,該呼叫的 revert 發生在進入 try 區塊之前,因此不受捕獲,整個交易直接失敗。
- 3
Solidity 自動插入的兩種前置檢查不被捕獲:呼叫合約地址前的 EXTCODESIZE 檢查(目標為 EOA 時觸發)以及回傳資料大小驗證,均在進入 try 之前執行,失敗時直接 revert。Solidity 0.8.10 起,若預期有非零回傳資料,EXTCODESIZE 檢查會被跳過。
- 4
try/catch 區塊內部的 revert 不再往上捕獲:在 try 或 catch 區塊裡拋出的異常,不會被同層的 catch 處理,會直接向上傳播。
實用技巧與重點
乾貨- 工具/語言:Solidity、Chain Security(審計公司)
- 版本節點:Solidity 0.8.10 起,若預期非零回傳資料,EXTCODESIZE 檢查不再執行
- 三種 catch 子句:`catch Error(string memory reason)`、`catch Panic(uint errorCode)`、`catch (bytes memory lowLevelData)`
- 會被捕獲:外部呼叫本體內的 revert、ABI decode 失敗
- 不會被捕獲:傳入參數的內部呼叫 revert、EXTCODESIZE 檢查失敗、回傳資料大小不符、try/catch 區塊自身內部的 revert
- 觸發 panic 的典型情況:arithmetic overflow、invalid array access、division by zero、assert 失敗
結論
結論“try-catch 只捕獲「外部呼叫本體」的 revert,Solidity 在進入 try 之前插入的 EXTCODESIZE 檢查、回傳長度驗證,以及傳入參數的內部呼叫,都在保護範圍之外。”
完整解析
詳細智能合約開發中,try-catch 常被視為「萬用保險網」,但 Chain Security 安全工程師 Mark 在這場閃電演講中指出,這個認知存在幾個危險的盲區,即使資深審計員也偶有誤解。
try-catch 的基本結構分三層:`catch Error` 捕獲帶有 reason string 的正常 revert;`catch Panic` 處理算術溢位、陣列越界、除以零、assert 失敗等「不應出現於無錯誤程式碼」中的例外;最低層的 `catch (bytes memory)` 則接住其他所有情況,包括 custom error、out of gas,以及前兩種子句解碼失敗的情形。理論上,低層級 catch 應能兜住一切——但現實並非如此。
Mark 以一個具體例子說明:對介面 `I` 的函式 `fu` 發出外部呼叫,其參數來自另一個內部呼叫。問題在於,這個「傳入參數的內部呼叫」在控制流進入 try 區塊之前就已執行;一旦它 revert,catch 完全感知不到,交易直接失敗。這是第一個盲區。
第二個盲區是 EXTCODESIZE 檢查。Solidity 在真正發出外部呼叫前,會自動檢查目標地址是否為合約(即 code size > 0);若目標是 EOA,檢查失敗,revert 在進入 try 之前發生,同樣逃脫 catch。值得注意的是,Solidity 0.8.10 起,若預期回傳非零資料(即函式有回傳值),此 EXTCODESIZE 檢查會被跳過——這引出第三個盲區:若外部呼叫實際回傳的資料長度不符預期,Solidity 同樣會在 try 之前 revert。
整體原則因此可歸納為:外部呼叫本體內部的 revert 會被捕獲;由 Solidity 在呼叫前自動插入的各種前置檢查,以及 try/catch 區塊自身內部拋出的異常,均不會被捕獲。這條規則看似簡單,卻在真實審計中反覆造成漏洞,值得每位 Solidity 開發者內化為直覺。
關鍵時刻
Pipeline v2帶時間戳的重點,會在逐字稿層級分析上線後產生。目前請先透過原始影片觀看。
事實查核
Pipeline v2說法查證是下一次管線升級的一部分。KeyFrame 只會顯示它真正能驗證的內容。

