Overflow behaviours with various shell implementations

  1. Introduction
  2. OpenBSD ksh
  3. bash
  4. dash
  5. zsh
  6. MirBSD ksh
  7. yash
  8. Conclusion

Introduction

Let’s try a simple script testing the upper bound of signed long integers with various implementations of the POSIX shell:

$ chmod +x overflow.sh
$ cat overflow.sh
echo $(( 9223372036854775807 ))
echo $(( 9223372036854775808 ))
echo $(( 9223372036854775808 + 1 ))

OpenBSD ksh

Tested on OpenBSD 6.8.

$ ksh ./overflow.sh 
9223372036854775807
-9223372036854775808
-9223372036854775807

All is well, nothing to see here.

bash

Tested with bash 5.0.17 on Ubuntu 20.04 and bash 5.1.4 on OpenBSD 6.8.

$ bash ./overflow.sh
9223372036854775807
-9223372036854775808
-9223372036854775807

All is well, nothing to see here.

dash

Tested with dash 0.5.11.2 on OpenBSD 6.8.

$ dash ./overflow.sh
9223372036854775807
9223372036854775807
-9223372036854775808

There is a small overflow bug here as 9223372036854775807 and 9223372036854775808 are considered equals. Oops.

zsh

Tested with zsh 5.8 on OpenBSD 6.8.

$ zsh ./overflow.sh 
9223372036854775807
./overflow.sh:2: number truncated after 18 digits: 9223372036854775808 
922337203685477580
./overflow.sh:3: number truncated after 18 digits: 9223372036854775808 + 1 
922337203685477581

This bug is strange as 9223372036854775807 is actually 20 digits long and this fact doesn’t bother zsh that much, so both the truncation and the error message have bugs too.

MirBSD ksh

Tested with mksh 58-1 on Ubuntu 20.04.

This is the MirBSD version of the Korn shell, a very interesting implementation to test as it is the default for Android.

$ mksh ./overflow.sh 
-1
0
1

Surprising? The answer is easy: contrary to the POSIX specification mksh implements integers as signed int instead of signed long. Its overflow point is thus the much more closer 2147483648 instead of 9223372036854775808.

yash

Tested with yash 2.49 on OpenBSD 6.8.

yash is a lesser known shell from Japan with a lot of very good features but the strange decision of implementing arrays with 1-based index instead of 0-based like everyone else, making it a portability nightmare.

$ yash ./overflow.sh 
9223372036854775807
9.22337203685478e+18
9.22337203685478e+18

But overflows don’t kill yash :)

Conclusion

As I was already able to witness with kbf relying on “big” numbers in shell is not portable. If safety is needed, only assumes signed int.

Of course if you are finding yourself in a situation where this page and advice are of serious help you are probably not using the most suitable programming language.