智能合約安全與審計

整數溢位與下溢

整數溢位與下溢是定寬算術中的繞回錯誤。就像汽車里程表從 999999 翻回 000000,EVM 的無號整數有一個最大值,並會悄悄地越過它繞回。EVM 的原生字長為 256 位元,因此 uint256 最大可容納到 2^256 減 1 的值;再加一就繞回到零。從零減一則會下溢到最大值,一個大得驚人的數字。當合約把這個繞回後的結果當成真正的餘額,金錢便憑空被創造或銷毀。

在 Solidity 0.8 之前,語言完全不做這些檢查,於是開發者依賴 SafeMath 函式庫,為每一次加、減、乘都包上明確的邊界檢查。忘了用它就是經典的漏洞:2018 年數個 ERC-20 代幣的 batchOverflow 漏洞,讓攻擊者傳入乘積會溢位的參數,鑄出巨額餘額。下溢同樣危險,例如一筆轉帳減去比你餘額還大的金額,結果不是回滾,而是讓你擁有近乎無限的餘額。

Solidity 0.8 及之後的版本把受檢算術設為預設:在 +、-、* 等運算上發生任何溢位或下溢都會自動回滾。開發者可以用 unchecked { ... } 區塊主動退出,在已證明某值不會溢位之處省下 gas。但要注意,檢查只作用於宣告型別寬度上的運算;像 uint128(x) 或 uint8(x) 這種明確的向下轉型仍會悄悄截斷,而 unchecked 區塊則完全恢復了昔日的暗坑。

(2^256 - 1) + 1 = 0 (mod 2^256); 0 - 1 = 2^256 - 1 (mod 2^256)

定寬算術是模運算:它會在自身範圍內繞回。

升級到 Solidity 0.8 並不代表合約就對溢位免疫。向下轉型(uint256 轉 uint64)會截斷而不回滾,而任何位於 unchecked 區塊內的程式碼——這在追求 gas 最佳化的函式庫中很常見——都退回了 0.8 之前的行為。請特別審查這些地方。

又称
arithmetic overflow溢位漏洞