SC08:2025 - Integer Overflow and Underflow

Description:

Ethereum Virtual Machine (EVM) defines fixed-size data types for integers. This implies that the range of numbers that an integer variable can represent is finite.For instance, a “uint8” (unsigned integer of 8 bits; i.e., non-negative) can only store integers that fall between 0 and 255. The outcome of trying to store any value greater than 255 into an “uint8” will lead to an overflow. Similarly, the outcome of subtracting “1” from “0” will produce 255. This is called underflow.When an arithmetic operation exceeds or falls short of a type’s maximum or minimum size, an overflow or underflow occurs.For signed integers, the outcome will be a bit different. If we try subtracting “1” from an int8 whose value is -128, we get 127. This is because signed int types, which may represent negative values, start over once we reach the highest negative value.Two straightforward examples of this behavior include periodic mathematical functions (adding 2 to the argument of sin leaves the value intact) and odometers in automobiles, which track distance traveled (they reset to 000000 after the maximum number, i.e., 999999, is exceeded).

Important Note:- In Solidity 0.8.0 and above, the compiler automatically handles checking for overflows and underflows in arithmetic operations, reverting the transaction if an overflow or underflow occurs. Solidity 0.8.0 also introduces the unchecked keyword, which allows developers to perform arithmetic operations without these automatic checks, explicitly permitting overflow without reverting. This can be particularly useful for optimizing gas usage in cases where overflow is not a concern or where the wraparound behavior is desired, similar to how arithmetic behaved in earlier versions of Solidity.

Example (Vulnerable contract):

// SPDX-License-Identifier: MIT
pragma solidity ^0.4.17;

contract Solidity_OverflowUnderflow {
    uint8 public balance;

    constructor() public {
        balance = 255; // Maximum value of uint8
    }

    // Increments the balance by a given value
    function increment(uint8 value) public {
        balance += value; // Vulnerable to overflow
    }

    // Decrements the balance by a given value
    function decrement(uint8 value) public {
        balance -= value; // Vulnerable to underflow
    }
}

Impact:

Remediation:

Example (Fixed version):

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Solidity_OverflowUnderflow {
    uint8 public balance;

    constructor() {
        balance = 255; // Maximum value of uint8
    }

    // Increments the balance by a given value
    function increment(uint8 value) public {
        balance += value; // Solidity 0.8.x automatically checks for overflow
    }

    // Decrements the balance by a given value
    function decrement(uint8 value) public {
        require(balance >= value, "Underflow detected");
        balance -= value;
    }
}

Examples of Smart Contracts that fell victim to Integer Overflow and Underflow Attacks:

  1. PoWH Coin Ponzi Scheme : A Comprehensive Hack Analysis
  2. Poolz Finance : A Comprehensive Hack Analysis