Reputation: 33215
For example, there are 3 variables of long type, we add a
and b
and get s
:
long a, b, s;
...
s = a + b
Now what does ((s^a) < 0 && (s^b) < 0)
mean?
I saw a check like this in the source code of Python:
if (PyInt_CheckExact(v) && PyInt_CheckExact(w)) {
/* INLINE: int + int */
register long a, b, i;
a = PyInt_AS_LONG(v);
b = PyInt_AS_LONG(w);
i = a + b;
if ((i^a) < 0 && (i^b) < 0)
goto slow_iadd;
x = PyInt_FromLong(i);
}
Upvotes: 7
Views: 72
Reputation: 280291
This code is wrong.
Assuming the usual 2's-complement rules of bitwise XOR for signed integers, then
(s^a) < 0
is the case if s
and a
have their sign bits set to opposite values. Thus,
((s^a) < 0 && (s^b) < 0)
indicates that s
has sign different from both a
and b
, which must then have equal sign (pretending 0 is positive). If you added two integers of equal sign and got a result of different sign, there must have been an overflow, so this is an overflow check.
If we assume that signed overflow wraps, then s
has opposite sign from a
and b
exactly when overflow has occurred. However, signed overflow is undefined behavior. Computing s
is already wrong; we need to check whether the overflow would occur without actually performing the operation.
Python isn't supposed to do this. You can see what it's supposed to do in the Python 2 source code for int.__add__
:
/* casts in the line below avoid undefined behaviour on overflow */
x = (long)((unsigned long)a + b);
if ((x^a) >= 0 || (x^b) >= 0)
It's supposed to cast to unsigned to get defined overflow behavior. The cast-to-unsigned fix was introduced in 5 different places as a result of issue 7406 on the Python bug tracker, but it looks like they missed a spot, or perhaps INPLACE_ADD
was changed since then. I've left a message on the tracker.
Upvotes: 5
Reputation: 13294
I don't see how this is possible.
If (s^a) < 0
, then the sign bit of either s
or a
must be a 1, so either s
or a
(but not both) must be negative. Same for s
and b
. So either s
is negative and both a
and b
are positive, or s
is positive and both a
and b
are negative. Both situations seem impossible.
Unless you count integer overflow/underflow, of course.
Upvotes: 2