Engineering Blog

Neglecting integer overflow

Concepts

Integer is a basic data types. Golang supports integer data types extensively. Integer are divided into two types which are signed and unsigned integer. Now we will see it’s types

Signed integer in go

TypesRange
TypesRange
int8-128 to 127
int16-32768 to 32767
int32-2147483648 to 2147483647
int64-9223372036854775808 to 9223372036854775807

Types of signed integer

Unsigned integer in Golang

TypesRange
TypesRange
uint80 to 255
uint160 to 65535
uint320 to 4294967295
uint640 to 18446744073709551615
Types of unsigned integer

The other two integer types are the most commonly used: int and uint. These two types have a size that depends on the system architecture: 32 bits on 32 bits systems or 64 bits on 64-bbit systems.

Integer Overflow

Now, Let’s talk about integer overflow. If a program performs a calculation and the true answer is larger than the available space,it may result in an integer overflow. It can cause the program to use incorrect numbers and respond in unintended ways, which can be exploited by attackers. Unexpected integer overflow can lead to serious bugs. An integer overflow occurs when an arithmetic operation creates a value outside the range.

Let’s now discuss integer overflow. Suppose we want to initialize an int8 to its maximum value and then increment it. What should be the behavior of this code?

	var counter int8 = math.MaxInt8
	counter++
	fmt.Printf("counter=%d\n", counter)

This code compiles and doesn’t panic at runtime. However, the counter++ statement generates an integer overflow:

counter=-128

An int8 is represented using 8 bits. Here is the binary representation of the maximum int8 value (math.MaxInt8):

01111111
1286432168421

7 bits set to 1

Because an int8 is signed integer, the bit on the left represents the integer’s sign: 0 for positive, 1 for negative. If we increment this integer, there is no space left to represent the new value. Hence, this leads to an integer overflow. Binary wise here’s the new value:

10000000
1286432168421
7 bits set to 0

In Go, an integer overflow that can be detected at compile time generates a compilation error. For example:

var counter int8 = math.MaxInt8 + 1

However, at run time, an integer overflow is silent, this does not lead to an application panic. It is essential to keep this behavior in mind, because it can lead to sneaky bugs (for example, an integer increment or addition of positive integers that leads to negative result.)

Detecting integer overflow

To detect an overflow with common operations. In most contexts, like handling a counter of requests or basic additions/multiplications, we shouldn’t worry too much if we use the right integer type. But in some cases, like memory constrained projects using smaller integer types, dealing with large numbers, or doing conversions. Following are the possible integer overflow scenarios:

  • Detecting integer overflow when incrementing
  • Detecting integer overflows during addition
  • Detecting an integer overflow during multiplication

Detecting integer overflow when increment

If we want to detect an integer overflow during an increment operation with a type based on a defined size (int8,int16,int32,int64,uint8,uint16,uint32,uint64). We can check the value against the math constants. For example, with an int8:

func incrementNumber(counter int8) int8 {
	if counter == math.MaxInt8 {
		panic("integer overflow")
	}
	return counter + 1
}

This function checks whether the input is already equal to math.MaxInt8. If it matches the case it panic the code with overflow message.

In summary, integer overflows are silent operation in Go. If we want to check for overflows to avoid unexpected errors, we can use the utility functions. If int is not enough, You may use package math/big which is provided by Go.

References:

  • 100 Go Mistakes and how to avoid them, Teiva Harsanyi, Manning Publications Co
Previous Post
Next Post