Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can an unsigned integer addition invoke undefined behavior?

Edit: Changed the value for USHRT_MAX as it was not conformant as shown by comments.


Imagine you have a fancy compiler where its integer type limits, as defined in limits.h are:

#define INT_MAX   2147483647   /* Typical 32-bit system value */
#define USHRT_MAX 2147483647   /* ***Edited***, original question had 2000000000 */

And in my application I have the following code:

unsigned short a = 1500000000;
unsigned short b = 1500000000;
unsigned short c;
c = a + b;

As far as I know, what will happen in the last instruction will be:

  1. Integral promotion on a. As int can take all values of unsigned short, a gets promoted to int.
  2. For the same reasons, b gets promoted to int.
  3. Addition happens on int types.
  4. The result is not representable in int. Undefined Behavior due to paragraph 6.5/5.

Is my reasoning correct? Does this really invoke undefined behavior, or where did I go wrong? Note that my code only works with unsigned types, and a result applying the modulus for unsigned integers could be expected due to legal overflow on unsigned types.

If the answer to the previous question is "yes, undefined behavior", this happened for a legal conformant compiler. So, can you say that the application code I posted is incorrect? Do all non-explicitly-casted small unsigned integer additions potentially invoke undefined behavior?

like image 429
atturri Avatar asked May 27 '16 15:05

atturri


People also ask

Is signed integer overflow undefined?

12.2. 1 Basics of Integer Overflow In contrast, the C standard says that signed integer overflow leads to undefined behavior where a program can do anything, including dumping core or overrunning a buffer. The misbehavior can even precede the overflow.

Can unsigned integers overflow?

"A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type."

What is the point of unsigned int?

Unsigned integers are used when we know that the value that we are storing will always be non-negative (zero or positive). Note: it is almost always the case that you could use a regular integer variable in place of an unsigned integer.

How does unsigned integer work?

An int is signed by default, meaning it can represent both positive and negative values. An unsigned is an integer that can never be negative. If you take an unsigned 0 and subtract 1 from it, the result wraps around, leaving a very large number (2^32-1 with the typical 32-bit integer size).


1 Answers

It is not possible for USHRT_MAX to be defined as 2000000000. The maximum values of unsigned integers must be in the form: 2^n-1:

6.2.6.2 Integer types

  1. For unsigned integer types other than unsigned char, the bits of the object representation shall be divided into two groups: value bits and padding bits (there need not be any of the latter). If there are N value bits, each bit shall represent a different power of 2 between 1 and 2 N−1 , so that objects of that type shall be capable of representing values from 0 to 2 N − 1 using a pure binary representation; this shall be known as the value representation. The values of any padding bits are unspecified.

Let's say USHRT_MAX is 2^31-1 and INT_MAX is 2^31-1.

In this case the variables a and b will be promoted to type int, due to integer promotions, and the result of the signed addition will overflow.

gcc is smart enough to treat the addition of two unsigned short variables as unsigned when they are assigned to an unsigned short.

Nevertheless, for full portability the code should be:

c = a + 0u + b;
like image 65
2501 Avatar answered Oct 04 '22 20:10

2501