Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does i++ invoke undefined behavior for signed types smaller than int in case of overflow?

It seems clear that the following code invokes undefined behavior because of arithmetic overflow:

#include <limits.h>

int test(void) {
    int i = INT_MAX;
    i++;  /* undefined behavior */
    return i;
}

But what about signed types smaller than int such as short or signed char? (by smaller, I assume SCHAR_MAX < INT_MAX and SHRT_MAX < INT_MAX respectively).

Which of the functions below invoke undefined behavior and why?

signed char test2(void) {
    signed char i = SCHAR_MAX;
    i = i + 1;   /* implementation defined */
    return i;
}

signed char test3(void) {
    signed char i = SCHAR_MAX;
    i += 1;   /* undefined behavior or implementation defined? */
    return i;
}

signed char test4(void) {
    signed char i = SCHAR_MAX;
    i++;      /* undefined behavior or implementation defined? */
    return i;
}

signed char test5(void) {
    signed char i = SCHAR_MAX;
    ++i;      /* undefined behavior or implementation defined? */
    return i;
}

Please provide references from or quote the C Standard to support your reasoning.

like image 202
chqrlie Avatar asked Oct 31 '16 14:10

chqrlie


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.

What happens when a signed int overflows?

"Signed integer overflow" means that you tried to store a value that's outside the range of values that the type can represent, and the result of that operation is undefined (in this particular case, your program halts with an error).

Is unsigned overflow undefined Behaviour?

-fsanitize=unsigned-integer-overflow : Unsigned integer overflow, where the result of an unsigned integer computation cannot be represented in its type. Unlike signed integer overflow, this is not undefined behavior, but it is often unintentional.

How do you overcome signed integer overflow?

Use 64-bits integers. One very good way to prevent integer overflows is to use int64_t to implement integers. In most case, 64-bits ints will not commit overflow, unlike their 32-bits counterparts. There is actually very few downsides in using int64_t instead of int32_t .


2 Answers

It would be logical for the += and similar operators to operate directly on values of the destination type, and on many implementations that is in fact what they do. The Standard, however, requires that the operator behave as though the value of the destination undergoes any applicable standard and balancing promotions, then processes the specified operation, and then gets converted back to the destination type.

Consequently, if s and u are signed and unsigned 16-bit variables, and int is 32 bits, then s*=s; will be defined for all values of s [if the result exceeds 32767, it must either yield an implementation-defined value or raise an implementation-defined signal; most implementations would have to go out of their way to do anything other than two's-complement reduction]. On the other hand, u*=u; will only be guaranteed to wrap mod 65536 for values of u up to 46340; for larger values, it will invoke Undefined Behavior.

like image 123
supercat Avatar answered Oct 20 '22 01:10

supercat


The following code does cause and overflow and thus undefined behavior:

signed char i = SCHAR_MAX;
i++; 

The operator postfix ++ does not perform integer promotions or usual arithmetic conversions1. The operator simply adds one to the value of the operand2. The operations overflows.

A clear distinction comes from the wording of the unary arithmetic operators: +, -, ~, for which the wording clearly says that the operand is promoted3. But for the postfix ++ operator the wording doesn't say that the operator is promoted4.

Clearly the postfix ++ operator does not promote the operand.


1 (Quoted from: ISO/IEC 9899:201x 6.3.1.1 Boolean, characters, and integers 2 58))
The integer promotions are applied only: as part of the usual arithmetic conversions, to certain argument expressions, to the operands of the unary +, -, and ~ operators, and to both operands of the shift operators, as specified by their respective subclauses.

2 (Quoted from: ISO/IEC 9899:201x 6.5.2.4 Postfix increment and decrement operators 2)
As a side effect, the value of the operand object is incremented (that is, the value 1 of the appropriate type is added to it)

3 (Quoted from: ISO/IEC 9899:201x 6.5.3.3 Unary arithmetic operators 2)
The result of the unary + operator is the value of its (promoted) operand. The integer promotions are performed on the operand, and the result has the promoted type.

4 (Quoted from: ISO/IEC 9899:201x 6.5.2.4 Postfix increment and decrement operators 2)
The result of the postfix ++ operator is the value of the operand.

like image 31
2501 Avatar answered Oct 20 '22 01:10

2501