Blog

Integer overflow and underflow in solidity

The Ethereum Virtual Machine specifies integers with fixed-size data types. This means that an integer variable can only represent numbers in a certain range. For example, when we use a value larger than what a uint value can accommodate, it wraps back to a number it can accept. This wrapping is usually toward the absolute lowest or highest value that the uint can store. The "uint8" declaration, for instance, represents an unsigned integer having a lower range value of 0 and an upper range value of 255 (2^8 - 1).

Hence, if you increment 255, it will automatically be 0, if you decrement 0, it will become 255.

In smart contracts, when an arithmetic operation exceeds the maximum or minimum value that the data type can represent, or without proper bounds checking, this will result in what we know as "over/underflows".

Trivial example of an overflow:



Note how this only works due to the solidity version being 0.7.6, as with 0.8.0, there is a built-in over/underflow protection.


Common Overflow/Underflow Vulnerability

1. The most common scenario where integer underflow or overflow occurs is during unsafe typecasting. Typecasting involves converting an integer from a larger uint data type to a smaller one. For instance, consider a situation where you've stored the integer 256 in a variable of type uint256, and you intend to convert it to uint8.

When performing this conversion, it's crucial to understand that the value will wrap around upon overflow and become 0:



Therefore, it is absolutely mandatory to always use @OpenZeppelin's SafeCast library (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeCast.sol)

2. Another vulnerability can occur from using the unchecked{...} keyword for arithmetics. An unchecked code block in Solidity allows arithmetic operations to occur without the compiler automatically verifying for overflow and underflow conditions, the rationale behind this is gas-optimization. This means that arithmetic operations within an unchecked code block may exceed the bounds of the data type being used, leading to overflow or underflow:



I have already found a few bugs in my audits related to this scenario.


How to prevent over and underflows from happening?

1. Use SafeMath

Libraries, like OpenZeppelin’s SafeMath, are prevalent in Solidity development for guarding against integer overflow and underflow risks. This is only necessary for versions that are below 0.8.0

2. Use Solidity version >= 0.8.0

A simple solution to prevent this bug is to utilize a Solidity compiler version of 0.8 or higher. This has built-in protection. Nonetheless, it is crucial to ensure that the code is designed to handle denial-of-service attacks stemming from integer overflow.

3. Avoid unchecked Math functions

Exercise caution when employing unchecked math functions, and recognize their susceptibility to triggering integer overflow and underflow vulnerabilities.

4. Input validation

Incorporate thorough input validation mechanisms to verify that input values fall within predetermined acceptable ranges, safeguarding against potential overflow or underflow situations.

5. Iteration control

Exercise careful control over the number of iterations within loops and iterative constructs, specifically for -- loops, I have found quite a few underflow issues during my audits.

6. SafeCast: Incorporate the SafeCast library for type conversions.



Link to the article

https://twitter.com/CharlesWangP/status/1783491505534959993