building-secure-contracts
building-secure-contracts copied to clipboard
Error in learn_evm/arithmetic-checks.md : Arithmetic checks for int256 multiplication
At this page : https://github.com/crytic/building-secure-contracts/blob/master/learn_evm/arithmetic-checks.md#arithmetic-checks-for-int256-multiplication
The first block of code is :
/// @notice versions >=0.8.0 && <0.8.17
function checkedMulInt(int256 a, int256 b) public pure returns (int256 c) {
unchecked {
c = a * b;
if (a > 0 && b > 0 && a > type(int256).max / b) arithmeticError();
if (a > 0 && b < 0 && a < type(int256).min / b) arithmeticError();
if (a < 0 && b > 0 && a < type(int256).min / b) arithmeticError();
if (a < 0 && b < 0 && a < type(int256).max / b) arithmeticError();
}
}
There is an issue on the third condition that should be replaced :
/// @notice versions >=0.8.0 && <0.8.17
function checkedMulInt(int256 a, int256 b) public pure returns (int256 c) {
unchecked {
c = a * b;
if (a > 0 && b > 0 && a > type(int256).max / b) arithmeticError();
if (a > 0 && b < 0 && a < type(int256).min / b) arithmeticError();
- if (a < 0 && b > 0 && a < type(int256).min / b) arithmeticError();
+ if (a < 0 && b > 0 && a > type(int256).min / b) arithmeticError();
if (a < 0 && b < 0 && a < type(int256).max / b) arithmeticError();
}
}
I discovered this issue while trying to use the code block for the solution of nodeGuardian's yul assembly quest.
Let me know if you need more details.
I tested this with concrete examples and found the original code (<) appears correct:
| a | b | Original (<) | Proposed (>) | Actual |
|---|---|---|---|---|
| -10 | 5 | OK ✓ | OVERFLOW ✗ | No overflow |
| MIN/2 - 1 | 2 | OVERFLOW ✓ | OK ✗ | Overflow |
When a < 0 and b > 0, underflow occurs when a * b < MIN, which means a < MIN / b (dividing by positive preserves inequality).
The proposed > causes false positives and misses real overflows.