5

Solved!

The relevant passage can be found in C90 ISO 9899:1990 6.1.2.5 Types:

"[..] A computation involving unsigned operands can never overflow, because [...]"

Therefore 9899:1990 6.3 can not apply and can therefore not be undefined behavior.

Thanks to Keith Thompson for helping me read. :-)

[2014-03-14] Apparently unsigned short integer can overflow resulting in undefined behavior depending on the target environment. This can happen if short unsigned integer become arithmetically promoted to int. Details see updated answer and the comments of supercat. Thanks to both. :-)

Original Question:

First of all, sorry for my bad English... I try my best. This is my first question and I think a quite stupid one.

For some sad reasons, my company got stuck to still ANSI C90 (ANSI/ISO 9899:1990) and so I have an old copy of this standard in my hands, but still missing the Corrections and ademnends.

I have an really easy question, and had known the answer perfectly well in times of my studies - till I try to read it up in the standard.

What happens if I have an unsigned integer overflow on an addition. Please see this piece of code:

uint32_t a,b,c;
b = UINT_MAX;
c = UINT_MAX;
a = b + c; /* Overflow here - undefined behavior? */

All I ever know about that is, that unsigned integer just wraps around as long as needed and everything is fine, while not always intended.

Now I was looking for the corresponding parts in the standard.

There is of course ISO 9899:1990 6.2.1.2 which describe the wrap around for unsigned integers, whenever it is converted. And there is a little bit of 6.2.1.5 "usual arithmetic conversions", which describe how the types are become wider, mostly that both operands of an expression have the same type.

Now there is 6.3 "Expressions" which is concerning me. I cite:

"[...] If an exception occurs during the evaluation of an expression (that is, if the result is not mathematically defined or NOT IN THE RANGE OF REPRESENTABLE VALUES FOR ITS TYPE) the behavior is UNDEFINED. [...]"

And the chapter 6.3.6 about additive operators says:

  • usual arithmetic conversions on operands, which does not apply as everything is uint32_t.
  • and the result is the sum of both, which clearly does not fit into uint32_t.
  • FINE

Nothing is said, that the resulting value is converted to the result type - so 6.2.1.2 does not apply. But the value then clearly overflows, where 6.3 steps in.

As far as I can see - this is undefined behavior according to ISO 9899:1990. What did I miss? Is there something in the Corrigendae? Have I miss a line or word in the standard?

I am really confused now. :-)

With regards, Mark

Question Update

[2014-03-03] Solved

[2014-03-03] So thanks to Acme I now have a clear and complete answer for ANSI C99 (see answer to: "Is unsigned integer subtraction defined behavior": It is clear defined behavior as expected. And though I expect this for ANSI C90 also, I still can't read it out of the text of ISO 9899:1990, given the text passages above. So I consider my question still unanswered for the moment.

Edit: Just Typos | Edit2: add C90 & standards tags | Edit3: add Question Update | Edit4: add solved section | Edit5: add answer links :-) | Edit6: Update short unsigned integer overflows | Edit7: some typos

Community
  • 1
  • 1
Mark A.
  • 579
  • 4
  • 13
  • I believe http://www.lysator.liu.se/c has (next to final) drafts of what became ANSI C/C90. Perhaps the [comp.lang.c FAQ](http://c-faq.com) is of help in locating a copy. – vonbrand Mar 03 '14 at 17:23
  • thanks vonbrand - I have a copy of the standard, but bad reading skills. – Mark A. Mar 03 '14 at 18:06
  • 1
    Finally I was right. It WAS a stupid question! :-) – Mark A. Mar 03 '14 at 18:07

1 Answers1

6

There has been no significant change in this area from C90 to C99, or from C99 to C11.

C90 6.1.2.5 (there are no paragraph numbers, but it's the first paragraph on page 23 of the PDF) says:

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 unsigned integer type.

Nearly the same wording (with the phrase "resulting unsigned integer type" changed to "resulting type" appears in 6.2.5 paragraph 9 in the C99 and C11 standards.

The only significant change (that I'm aware of) is an addition in C99 regarding signed conversion. In C90, if a signed or unsigned value is converted to a signed integer type, and the result cannot be represented in the target type, the result is implementation-defined. In C99 and C11, either the result is implementation-defined or an implementation-defined signal is raised. (I don't know of any compiler that takes advantage of the permission to raise a signal.)

As supercat points out in a comment, multiplication of two unsigned short values can overflow. Suppose short is 16 bits, int is 32 bits, and integer representations are typical (2's-complement for signed types, no padding bits). Then given:

unsigned short US = USHRT_MAX; // 65536

both operands in the expression

us * us

are promoted from unsigned short to int (because int can hold all possible values of type unsigned short) -- but the product, which is nearly 232, cannot fit in a 32-bit signed int.

(During the C standardization process in the late 1980s, the committee had to choose between "value-preserving" and "unsigned-preserving" integer promotions. They chose the former. With unsigned-preserving semantics, the unsigned short operands would be promoted to unsigned int, and this problem would not occur.)

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • Ah - there is the missing link. I just have to read more patient. I guess I just have not exspected computation and overflow rules in types chapter. Itself - thank you very much. – Mark A. Mar 03 '14 at 17:49
  • A computation involving two unsigned operands which are at least as large as `int`, cannot overflow. The product of two unsigned operands which are smaller than `int`, however, can overflow if `int` is not large enough to hold the result. – supercat Mar 13 '14 at 23:29
  • @supercat: Which can only happen if `int` is wider than `short`, but less than twice as wide (which is certainly legal, but probably nonexistent in the real world). – Keith Thompson Mar 14 '14 at 00:22
  • 2
    @KeithThompson: It can also happen if it's exactly twice as wide. On a machine with 64-bit integer, `uint32_t a = 3037000500u; uint32_b = a*a;` will generate Undefined Behavior. I'm not sure of any good efficient portable way to multiply two uint32_t to yield a uint32_t result. Casting to uint64_t would work, but it's hideous. Casting to `unsigned` would fail on embedded controllers where `int` is smaller than 32 bits. – supercat Mar 14 '14 at 00:27
  • @supercat: You're right (and I realized it just before I read your comment). Ick. – Keith Thompson Mar 14 '14 at 00:28
  • @KeithThompson: The inconsistency of value-preserving and unsignedness-preserving behaviors is IMHO horrible; C badly needs, IMHO, a means of declaring types that should behave as members of algebraic rings (e.g. the set of integers congruent mod 4294967296), as distinct from types which act as numbers. Ring types should *not* promote, but should always wrap at their precise specified size. If a machine has e.g. a 36-bit `int`, code using a `uring32_t` should perform 36-bit math and mask the result. The idea that a compiler should promote such values so as to produce "faster" code... – supercat Mar 14 '14 at 02:29
  • ...as opposed to code which wraps exactly as specified, strikes me as absurd. Note that adding any size of integer to a ring should yield a member of the same ring. Rings should be implicitly assignable only the same ring or smaller rings; conversion to numbers or to larger rings should be performed via cast. – supercat Mar 14 '14 at 02:31
  • Will this overflow produce "undefined behavior" or "implementation defined behavior"? – Mark A. Mar 14 '14 at 08:33
  • @MarkA.: The behavior of signed integer overflow is undefined. On the other hand, *conversion* of an integer value to a signed type, when the value cannot be represented, yields an implementation-defined result -- or raises an implementation-defined signal, which can then cause undefined behavior. – Keith Thompson Mar 14 '14 at 14:18
  • @Keith Thank you for clarification. Every day I love C more and more. Must be something like the Stockholm Syndrom :-) – Mark A. Mar 14 '14 at 14:46
  • @MarkA.: You misspelled Syndrome. – Keith Thompson Mar 14 '14 at 14:47
  • @KeithThompson Thanks, but there is nothing I can do about it anymore. :-) – Mark A. Mar 14 '14 at 14:54
  • I wonder if any reasonable people on the Committee would oppose a rule specifying that if the result of an addition, multiplication, left shift, bitwise operator, or unary plus or minus, is cast or coerced to an unsigned type smaller than `int`, compilers must either make it behave an unsigned operation and coerce its operands likewise, or define `__NON_MODULAR_UNSIGNED_SHORT`, and provide that strictly-conforming programs would not be required to compile in the presence of such a flag. Note that probably 99+% of compilers written before 2010 were already compliant with that requirement. – supercat May 13 '15 at 00:32