0

I am dealing with large integers (unsigned long long) and need to guard for overflow conditions. The code throws the exception regardless if there actually is one:

try
{
    unsigned long long y = std::numeric_limits<unsigned long long>::max() - 2;
    unsigned long long z = 1;
    int size = - 1;
    if((y+z) ^ y < 0) //If y+z causes overflow its sign will be changed => y and (y+z) will have opposite signs
        throw std::overflow_error("overflow of y+z");
    //int* myarray= new int[size]; VS Debug Library catches it earlier than catch()
    printf("%d\n", y*(y+z));
}
catch(exception& e)
{
    cout << e.what() << endl;
}

Since it is of the largest data type(64 bits) already, there is no room to promote to anything larger.

New code:

try
{
    unsigned long long int y = std::numeric_limits<unsigned long long int>::max() - 2;
    unsigned long long int z = std::numeric_limits<unsigned long long int>::max() / 2;
    unsigned long long delta = std::numeric_limits<unsigned long long int>::max() - y;
    int size = - 1;
    if(z > delta) //If y+z causes overflow its sign will be changed => y and (y+z) will have opposite signs
        throw std::overflow_error("overflow of y+z");
    //int* myarray= new int[size]; VS Debug Library catches it earlier than catch()
    printf("%d\n", (y+z));
}
catch(exception& e)
{
    cout << e.what() << endl;
}
Vectorizer
  • 1,076
  • 9
  • 24

2 Answers2

3

y < 0 will always be false, and anything xor 0 will always be that thing (Did you miss that < is evaluated at higher precedence than ^?).

Therefore unless x + y mod <the max value> happens to equal 0, you will throw (and probably appears to always throw in practice unless you contrived specific inputs).

Perhaps what you meant to do was something like this: if((std::numeric_limits<unsigned long long>::max() - y) < z) throw ...;

Mark B
  • 95,107
  • 10
  • 109
  • 188
2

You have two issues. The main one is operator precedence: < is higher than ^. This is a great reason to compile with all warnings enabled as both gcc and clang give me a warning about this expression and suggest parentheses!

Your expression, as evaluated by the compiler, is really:

if ( (y+z) ^ (y < 0) )

Since y < 0 evaluates as 0, that's just:

if (y+z)

which is obviously true. But even if you had the parentheses correct, as:

if (((y+z) ^ y) < 0) { ... }

That expression is trivially false. It will still have type unsigned long long which will never evaluate as < 0.

Barry
  • 286,269
  • 29
  • 621
  • 977