If you have ever tried to operate on numbers and gotten a counter-intuitive result then you have most likely experienced an overflow or an underflow.

The concept of Overflow and Underflow in Solidity results from a fundamental concept in computer science. In this post, I intend to guide you through the fundamentals to help you understand the **why** behind it.

I assume you understand the basics of Solidity and the basics of how binary numbers work.

Copy and paste the code below on remix to replicate an Overflow and an Underflow.

Deploy the code and let’s walk through the code.

**Line 2**: I used version**0.7.0**of solidity because overflow and underflow checking is implemented by default in versions**0.8.0**and above. Using that, the compiler would throw an error when we try to call the functions below. Moreover, It’s advised you use**0.8.0**or above when writing production code so you won’t have to use libraries like SafeMath or your implementation to do the checking. This is purely experimental.**Line 6:**I declared the variable**balance**which is set to**0**by default.**Line 8**to**Line 10**: We have the**underflow**function. It uses**line 9**to decrease the value of**balance**by**1**. Call this function once and then check the new value of the**balance**; it’s**255**. i.e**0**minus**1**just gave us**255**. That’s an underflow.**Line 12**to**Line 15**: We have the**overflow**function. It sets the value of**balance**to**255**. And then, increments it by**1**. Intuitively, the new**balance**value should be**256**but it’s**0**. That’s an overflow.

Haven replicated an underflow and overflow situation. Let’s go through the fundamentals.

## Fundamentals of Overflow and Underflow

Binary is at the core of how computers store and process data. An 8-bit memory would only be able to store at most 8-bit representations of any form of data at any given time.

Programming languages also try to emulate this pattern to handle storage more efficiently. For example, if you wanted to store data that you know for sure won’t exceed the 8-bit space why then would you create a 256-bit storage space for it? It’s a waste of storage space among other disadvantages and that’s why languages like solidity give us the ability to store data in different storage spaces based on data size. For integers, we could store integers from the **8 bits** up to **256 bits **in steps of **8 **using **int8**/**uint8** to **int256**/**uint256 **respectively.

Imagine declaring an unsigned integer and setting the storage to 8-bit storage as illustrated below in solidity.

But, at the time of assignment, an integer exceeding the 8-bit storage space is passed to the variable **a**. What happens then? That’s what overflow and underflow are all about. Overflows and underflows are a result of data exceeding the predefined storage space created for them.

So, how do you determine the minimum and maximum integer a bit size can store?

Here’s the simple formula:

**For unsigned integers**:**0**to**(2 ^ n ) – 1**where**n**is the number of bits. For example, for 8 bits:**0 to (2 ^ 8) – 1 = 0 to (256) – 1 = 0 to 255****For signed integers**:**(-2 ^ n -1)**to**(2 ^ n – 1) – 1**where**n**is the number of bits. For example, for 8 bits:**(-2 ^ 8 -1)**to**(2 ^ 8 – 1) – 1**=**(-2 ^ 7)**to**(2 ^ 7) – 1**=**-128 to 127**

Or, using Solidity:

To understand this better, think of it as how modulo arithmetic works. Values of arithmetic operations are **wrapped** around the range of numbers they can store. For example:

**25**+**120**in**signed 8-bit(int8)**is**-111.****25**plus**120**is**145**but the highest number that can be represented is**127**so instead of the next number being**128**it starts all over from the least value**-128**and counts up to**-127**then**-126**,**-125**up to**-111****40**+**240**in**unsigned 8-bit(uint8)**is**24**.**40**plus**240**is**280**but the highest number that can be represented is**255**so instead of the next number being**256**it starts all over from the least value**0**then counts up to**1**then**2**,**3**up to**24****0**–**1**in**unsigned 8-bit(uint8)**is**255**.**0**minus**1**is**-1**but the least number that can be represented is**0**so instead of the next number being**-1**it goes over to the top at**255**.**-128**–**5**in**signed 8-bit(int8)**is**1****23**.**-128**minus**5**is**-133**but the least number that can be represented is**-128**so instead of the following number being**-129**it starts all over from the top at**127**and counts down to**126**then**125**,**124**down to**123**

At this point, it is safe to say that the values in the range are like numbers on a clock and every number revolves around them.

Let’s go a bit more in-depth by using binary numbers to explain the examples above.

Before we move on, here are a few things to take note of when solving in binary:

- In
**signed binary arithmetic**, if the addition of**two****positive numbers**gives a**-ve number**then an overflow/underflow has occurred. - In
**signed binary arithmetic**, if the addition of**two negative numbers**gives a**+ve number**then an overflow/underflow has occurred. - In
**unsigned binary arithmetic**, if there is a**carry**from the**MSB**(i.e for the**most significant bit**. it’s the numbers on the left-most part of the binary digit. For example, in**00011001**,**0**is the most significant bit and in**10000000**,**1**is the most significant bit) then an overflow has occurred. - In
**signed binary arithmetic**, the**MSB**signifies if a number is a**-ve number**or**+ve number**. If the**MSB**is**0**, it’s a**+ve number**while if the**MSB**is**1**, it’s a**-ve number**. - A simple trick to know if an overflow/underflow has occurred in
**signed arithmetic**addition is if the**carry into the MSB**and the**carry out of the MSB**are different. If they are the same, an overflow/underflow has**not**occurred. For example,**1**&**1**and**0**&**0**means no overflow/underflow while**0**&**1**and**1**&**0**means there is an overflow/underflow. While for**unsigned arithmetic**, if there is a**carry out of the MSB**then there is an overflow/underflow.

The above is quite dense but I assure you you can understand the next part without understanding it. Feel free to go through it multiple times to understand it better but for now, you can just move to the next part.

The calculations:

**25**+**120**in**signed 8-bit**:**25**is**00011001**and**120**is**01111000**.**00011001****+****01111000**is**10010001**.**10010001**is**-111**in**signed**binary arithmetic.**40**+**240**in**unsigned 8-bit: 40**is**00101000**and**240**is**11110000**.**00101000****+ 11110000**is**00011000**.**00011000**is**24**in**unsigned**binary arithmetic.**0**–**1**in**unsigned 8-bit: 0**is**00000000**and**1**is**00000001**.**00000000****+ 11111111**(i.e this is the**2’s complement**of**00000001**which is**1**. We can’t perform**0**–**1**rather we do**0**+ (**-1**) and**-1**is**11111111**) is**11111111**.**11111111**is**255**in**unsigned**binary arithmetic.**-128 –****5**in**signed 8-bit: -128**is**10000000**and**-5**is**11111011**. Using**-128**+ (**-5**) then**10000000****+ 11111011**is**01111011**.**01111011**is**123**in**signed**binary arithmetic.

Use a binary calculator to try these out yourself.

That’s a wrap ✌️

## Conclusion

As you might have noticed, this post is not about how to prevent an overflow or underflow rather it’s about **why **you run into them. That being said, overflows and underflows are security threats and have been the cause of hacks in the past so make sure you prevent them by using solidity version **0.8.0 **and above or using the SafeMath library when writing your solidity code.

This is quite complex to grasp right away so feel free to ask questions in the comment below. Please share if you found this helpful. Happy learning.

## 1 comment

Good post.