29

There's (1):

// assume x,y are non-negative
if(x > max - y) error;

And (2):

// assume x,y are non-negative
int sum = x + y;
if(sum < x || sum < y) error;

Whichs is preferred or is there a better way.

iBug
  • 35,554
  • 7
  • 89
  • 134
Ganker
  • 329
  • 1
  • 3
  • 5
  • 1
    Actually the duplicate is not a duplicate at all, it is talking about `unsigned` that have well-defined wraparound semantics, whereas overflowing a signed integer is undefined behaviour in C. – Antti Haapala -- Слава Україні Mar 16 '15 at 15:33
  • 2
    There is no need to check both `sum < x` and `sum < y`. – Paweł Bylica Oct 07 '15 at 13:43
  • This was previously closed as a duplicate of [How to detect integer overflow?](//stackoverflow.com/q/199333), but that's about `unsigned` where wrapping is well-defined behaviour. signed `int` is harder because you can't just add and *then* check if it overflowed, that would already be UB and thus compilers can assume there was no overflow! – Peter Cordes Feb 04 '19 at 06:00
  • Possible duplicate of [How do I detect unsigned integer multiply overflow?](https://stackoverflow.com/questions/199333/how-do-i-detect-unsigned-integer-multiply-overflow) – GSerg May 07 '19 at 15:42

3 Answers3

64

Integer overflow is the canonical example of "undefined behaviour" in C (noting that operations on unsigned integers never overflow, they are defined to wrap-around instead). This means that once you've executed x + y, if it overflowed, you're already hosed. It's too late to do any checking - your program could have crashed already. Think of it like checking for division by zero - if you wait until after the division has been executed to check, it's already too late.

So this implies that method (1) is the only correct way to do it. For max, you can use INT_MAX from <limits.h>.

If x and/or y can be negative, then things are harder - you need to do the test in such a way that the test itself can't cause overflow.

if ((y > 0 && x > INT_MAX - y) ||
    (y < 0 && x < INT_MIN - y))
{
    /* Oh no, overflow */
}
else
{
    sum = x + y;
}
caf
  • 233,326
  • 40
  • 323
  • 462
  • Btw, can you comment on the performance of this solution compared to other alternative solutions? – Pacerier Sep 22 '13 at 18:10
  • 8
    It makes little sense to compare the performance against an incorrect solution. What other correct solution did you have in mind? – caf Sep 23 '13 at 01:04
  • 2
    the other usual way seem to be casting to a wider type. I'm not sure of a third alternative but there are surely more. – Pacerier Sep 24 '13 at 04:12
  • @Pacerier Casting to a wider type is not possible if you're already working with the largest type on the platform. – martinkunev Mar 03 '17 at 22:29
  • Everybody knows what the behavior of C is on integer overflow. It does not matter what the standard says legally, what counts is what every single compiler actually does. Any compiler that did not simply ignore overflows would simply not be able to compile most applications. – Tuntable Jul 12 '18 at 00:45
  • @Tuntable: That's not the case. Take a look at this simple example: https://godbolt.org/g/qFz1HA - all recent optimising compilers assume the overflow can't happen and just return `a + 100` regardless of the value of `a`. – caf Jul 12 '18 at 06:49
  • 1
    @Tuntable: What every single compiler does is optimizations which can lead to horror: http://blog.llvm.org/2011/05/what-every-c-programmer-should-know_14.html – ilstam Jun 07 '19 at 00:20
  • Thanks, that lvm article is excellent and an eye opener. Hard to see why -fwrapv would not just be part of the standard. Of course if C programmers cared about security they would provide an easy way to trap integer overflow. Like Visual Basic does. There is actually virtually no overhead as hardware generally can trap it. It is just a C thing. That now pollutes Java. When I write C I just do what everyone else does and ignore the problem. – Tuntable Jun 08 '19 at 01:20
5

You can really only check for overflow with unsigned integers and arithmatic:

unsigned a,b,c;
a = b + c;
if (a < b) {
    /* overflow */
}

The behavior of overflow with signed integers is undefined in C, but on most machines you can use

int a,b,c;
a = b + c;
if (c < 0 ? a > b : a < b) {
    /* overflow */
}

This may require compile-time flags to get the compiler to enforce wrapping semantics, and won't work on machines that use any kind of saturating or trapping arithmetic

Chris Dodd
  • 119,907
  • 13
  • 134
  • 226
  • 9
    Checking for overflow after the fact with signed integers isn't correct. It's undefined behaviour, so compilers will happily optimize out the checks without passing a switch like `-fwrapv` to enable signed wrapping as a language extension. It's not just a portability issue across architectures. – strcat Sep 08 '15 at 21:24
  • 1
    Overflow for signed integers can also be checked. See https://www.securecoding.cert.org/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow – sbhatla Nov 30 '16 at 15:28
  • 2
    Nope, modern gcc breaks your signed `int` example. [Signed integer not overflowing on ARM64?](//stackoverflow.com/q/54510094). – Peter Cordes Feb 04 '19 at 05:59
-6

You only have to check one of them. If x + y overflows, it will be less than both x and y. Hence:

int sum = x + y;
if (sum < x) error;

should be sufficient.

The following site has a bunch of stuff about integer overflow:

http://www.fefe.de/intof.html

If you want to handle negative numbers, it can be expanded:

int sum = x + y;
if (y >= 0) {
   if (sum < x) error;
} else {
   if (sum > x) error;
}
clahey
  • 4,795
  • 3
  • 27
  • 20