Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

To detect int overflow/underflow in C, I use the below code.

What might be simpler and portable code?
(That is: fewer tests)

Assume 2's complement and don't use wider integers.

int a,b,sum;
sum = a + b;
// out-of-range only possible when the signs are the same.
if ((a < 0) == (b < 0)) {
  if (a < 0) {
    // Underflow here means the result is excessively negative.
    if (sum > b) UnderflowDetected();
  }
  else {
    if (sum < b) OverflowDetected();  
  }

[Edit]
Answer: Combining @Gareth Rees answer with some other ideas resulted in:

#include <limits.h>
int safe_add(int a, int b) {
  if (a >= 0) {
    if (b > INT_MAX - a) {
      ; /* handle overflow */
    }
  } else {
    if (b < INT_MIN - a) {
      ; /* handle underflow */
    }
  }
  return a + b;
}

Note: Solution does not require 2's complement.
Note: This post does not address unsigned overflow.

share|improve this question
    
I think you're misunderstanding underflow ... or am I? Let's say, as an example, the smallest number a float can represent is 0.001. 1.0 / 10000 would result in a value of 0.0 because the actual value is too small. –  Fiddling Bits Dec 12 '13 at 0:44
1  
@BitFiddlingCodeMonkey this is on integers - there are various wrap-around cases where the result of an addition does not fit in the same size integer. Sometimes it's called underflow when it's the sum of two negative numbers that doesn't fit. –  Michael Urman Dec 12 '13 at 1:01
    
If you just change from using int to using unsigned int, or better still, uint32_t and size_t, you'll be able to do those checks after the operation. For signed ints, overflow and underflow can't be detected after-the-fact because of undefined behaviour. And be warned: undefined behaviour can exhibit itself as anything from the program appearing to work properly right through to malware being installed on your machine and being used to steal your credit card information. –  Matt Dec 12 '13 at 12:10
    
@Matt Are you suggesting a method that would detect the out-of-range sum of 2 ints by employing unsigned conversion? OTOH if you are talking about overflow detection for 2 unsigned, that is a different question. if (sum < a) OverflowDetected(); seems to work for that. –  chux Dec 12 '13 at 15:46
1  
@chux: No - I was merely pointing out that the method employed here (i.e. do an add and then see if an overflow occurred) is valid only on unsigned integers. For signed integers it is never valid because overflow of signed integers is inherently undefined in the language. –  Matt Dec 12 '13 at 15:52
add comment

2 Answers 2

up vote 12 down vote accepted

Your code doesn't work: if the addition overflows then there is undefined behaviour here:

sum = a + b;

so your test is too late. You have to test for possible overflow before you do the addition. (If you're puzzled by this, read Dietz et al. (2012), "Understanding Integer Overflow in C/C++". Or even you're not puzzled: it's an excellent paper!)

If it were me, I'd do something like this:

#include <limits.h>

int safe_add(int a, int b) {
    if (a > 0 && b > INT_MAX - a) {
        /* handle overflow */
    } else if (a < 0 && b < INT_MIN - a) {
        /* handle underflow */
    }
    return a + b;
}

but I'm not entirely sure what the point of having separate cases for overflow and underflow is.

I also use Clang's -fsanitize=undefined when building for test.

share|improve this answer
    
Quite a lengthy paper, yet you make it seem so simple here. :-) What are INT_MAX and INT_MIN equal to? –  Jamal Dec 11 '13 at 23:17
1  
§5.2.4.2.1 in the C99 standard defines INT_MIN to be the "minimum value for an object of type int" and INT_MAX to be the "maximum value for an object of type int". –  Gareth Rees Dec 11 '13 at 23:20
1  
Yes, that's right. Typical values are INT_MIN = −2^32 = −2147483648 and INT_MAX = 2^32 − 1 = 2147483647, but the values can vary depending on your processor and compiler, so the only way to make code portable is to use the macros. –  Gareth Rees Dec 11 '13 at 23:27
1  
@Jamal Actually, with <limits>. std::numeric_limits<int>::min() and std::numeric_limits<int>::max() to be precise. –  Yuushi Dec 12 '13 at 0:16
2  
It's worth pointing out that integer overflow and underflow are undefined only for SIGNED types. For unsigned integers, overflow safely occurs as modulo arithmetic. –  Matt Dec 12 '13 at 12:02
show 8 more comments

Why not use a long to hold the result of the calculation? Then the long can be checked against the (int) MAX and MIN values to see if overflow or underflow occurred? If no violations have occurred, then the result can safely be re-cast back to an (int).

Or, is this too simple and I'm missing something very fundamental? One thing that I HAVE omitted is the possibility that the long will also overflow.

share|improve this answer
1  
As type long is only guaranteed to be at least the range of int, converting to long may not provide any additional range. Thus the problem is fundamentally the same for long as for int. Same situation for long long. –  chux Jul 6 at 17:18
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.