The other day, I played around with the Fibonacci sequence and overflowed my
`int`

variables in surprisingly low iterations. Did you know you’ll overflow an integer in **48
** iterations? Don’t believe me? Let’s take a look at the result of the code you’ll see later in this post.

```
Enter an integer: 48
Fibonacci sequence for 48:
0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368,75025,121393,196418,
317811,514229,832040,1346269,2178309,3524578,5702887,9227465,14930352,24157817,39088169,63245986,102334155,165580
141,267914296,433494437,701408733,1134903170,1836311903,-1323752223
```

You’ll notice that the last value has looped back to a negative value. Oh no! This is a tell-tale sign that an overflow has occurred.

This post will explore how to keep your applications safe from these overflow issues.

## The code causing the overflow

First, let’s look at my implementation of the Fibonacci sequence generator. I’m using
`Spectre.Console`

to make the output more appealing, but it’s optional. I’m also using the
`System.Numerics`

namespace, which will allow you to experiment with different number types in .NET.

```
using System.Numerics;
using Spectre.Console;
while (true)
{
try
{
var integer = AnsiConsole.Ask<int>("Enter an integer: ");
if (integer <= -1)
{
AnsiConsole.MarkupLine("Goodbye!");
break;
}
var numbers = GenerateFibonacci<int>((uint)integer);
AnsiConsole.MarkupLine($"[bold green]Fibonacci sequence for {integer}:[/]");
AnsiConsole.MarkupLine($"[bold yellow]{string.Join(",", numbers)}[/]");
AnsiConsole.MarkupLine("");
}
catch (ArgumentOutOfRangeException)
{
AnsiConsole.MarkupLine("[red]Error: pick a value greater than 2[/]");
}
}
static T[] GenerateFibonacci<T>(uint iterations)
where T : INumber<T>
{
ArgumentOutOfRangeException
.ThrowIfLessThan<uint>(iterations, 2, "iterations must be greater than or equal to 2");
T[] fib = new T[iterations];
fib[0] = T.Zero;
fib[1] = T.One;
for (int i = 2; i < iterations; i++)
{
fib[i] = fib[i - 1] + fib[i - 2];
}
return fib;
}
```

Neat! Now, why does the issue occur in the first place?

## Unchecked Arithmetic

By default, .NET performs
`unchecked`

arithmetic operations. That means the runtime assumes you know what you’re doing when adding one variable to another. This is true in most day-to-day cases, as the scale of numbers most developers deal with is on the lower side of the maximum
`int`

and `long`

values.

For integers, the max value is `2147483647`

, and it is doubled to `4294967295`

if you drop the sign
`—/+`

from the value. For a long, the max value is
`9223372036854775807`

, which is quite a lot bigger but not infinite. If your application increments values indefinitely, you will run into overflow issues, and no known type will save you. It’s just math!

As you’ve seen previously, the issue is that the numbers will loop around from positive to negative values and back. Your application will continue to “work” but likely will be nonsensical and wrong.

How do we fix this issue? Well, there are two ways.

## The `checked`

keyword

The first and most precise way to fix this issue is to use the
`checked`

keyword. Using this keyword creates a scope where arithmetic overflows will trigger an `OverflowException`

.

```
static T[] GenerateFibonacci<T>(uint iterations)
where T : INumber<T>
{
ArgumentOutOfRangeException
.ThrowIfLessThan<uint>(iterations, 2, "iterations must be greater than or equal to 2");
T[] fib = new T[iterations];
fib[0] = T.Zero;
fib[1] = T.One;
for (int i = 2; i < iterations; i++)
{
checked
{
fib[i] = fib[i - 1] + fib[i - 2];
}
}
return fib;
}
```

Rerunning the same code results in the following exception.

```
Enter an integer: 49
Unhandled exception. System.OverflowException: Arithmetic operation resulted in an overflow.
at System.Int32.System.Numerics.IAdditionOperators<System.Int32,System.Int32,System.Int32>.op_CheckedAddition(Int32 left, Int32 right)
at Program.<<Main>$>g__GenerateFibonacci|0_0[T](UInt32 iterations) in /Users/khalidabuhakmeh/RiderProjects/zed-sample/Program.cs:line 40
at Program.<Main>$(String[] args) in /Users/khalidabuhakmeh/RiderProjects/zed-sample/Program.cs:line 16
```

Nice. This technique is very selective and changes the intermediate language to call the
`op_CheckedAddition`

method instead.

```
// [40 13 - 40 46]
IL_003f: ldloc.0 // fib
IL_0040: ldloc.1 // i
IL_0041: ldloc.0 // fib
IL_0042: ldloc.1 // i
IL_0043: ldc.i4.1
IL_0044: sub.ovf
IL_0045: ldelem !!0/*T*/
IL_004a: ldloc.0 // fib
IL_004b: ldloc.1 // i
IL_004c: ldc.i4.2
IL_004d: sub.ovf
IL_004e: ldelem !!0/*T*/
IL_0053: constrained. !!0/*T*/
IL_0059: call !2/*T*/ class [System.Runtime]System.Numerics.IAdditionOperators`3<!!0/*T*/, !!0/*T*/, !!0/*T*/>::op_CheckedAddition(!0/*T*/, !1/*T*/)
IL_005e: stelem !!0/*T*/
```

Cool! Problem solved, but what if we want all our arithmetic checked?

## Project Setting for Checked Arithmetic

You can add the
`CheckForOverflowUnderflow`

property in your project settings, and it will change all supported arithmetic operations to use checked operations.

```
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Spectre.Console" Version="0.49.1" />
</ItemGroup>
</Project>
```

Easy peasy. Running the original code results in the same `System.OverflowException`

.

To opt out of checking, you can use the converse `unchecked`

keyword.

```
static T[] GenerateFibonacci<T>(uint iterations)
where T : INumber<T>
{
ArgumentOutOfRangeException
.ThrowIfLessThan<uint>(iterations, 2, "iterations must be greater than or equal to 2");
T[] fib = new T[iterations];
fib[0] = T.Zero;
fib[1] = T.One;
for (int i = 2; i < iterations; i++)
{
unchecked
{
fib[i] = fib[i - 1] + fib[i - 2];
}
}
return fib;
}
```

## Conclusion

We can sometimes take for granted arithmetic operations and assume they will work. In most cases, they will, but if you’re building mission-critical applications that could run into underflow and overflow situations, it’s better to check these values so as not to cause potential headaches down the line.

I hope you enjoyed this post, and as always, thanks for reading.