127.0.0.1:6380> bitfield hello set i64 0 -2
1) (integer) 0
127.0.0.1:6380> bitfield hello get i64 0
1) (integer) -1
127.0.0.1:6380> get hello
"\xff\xff\xff\xff\xff\xff\xff\xfe"
127.0.0.1:6380> bitfield hi set i64 0 9223372036854775807
1) (integer) 0
127.0.0.1:6380> bitfield hi incrby i64 0 1
1) (integer) -1
127.0.0.1:6380> get hi
"\xff\xff\xff\xff\xff\xff\xff\xff"
When use i64, Redis will use (uint64_t)-1 << 64,this behavior is undefined. On my compiler, ((uint64_t)-1 << 64) == ((uint64_t)-1).
In function getSignedBitfield, the value will always be -1:
if (value & ((uint64_t)1 << (bits-1)))
// value will be -1 if bit == 64
value |= ((uint64_t)-1) << bits;
In function checkSignedBitfieldOverflow, c will always be -1:
{
uint64_t mask = ((uint64_t)-1) << bits;
uint64_t msb = (uint64_t)1 << (bits-1);
uint64_t a = value, b = incr, c;
c = a+b; /* Perform addition as unsigned so that's defined. */
/* If the sign bit is set, propagate to all the higher order
* bits, to cap the negative value. If it's clear, mask to
* the positive integer limit. */
if (c & msb) {
c |= mask; // c will be -1 if bit == 64
} else {
c &= ~mask;
}
*limit = c;
}
In function checkUnsignedBitfieldOverflow,Because bits can't be 64, it is OK.
Comment From: antirez
Thanks @huangzhw! Very good catch. Do you agree with the proposed fix in 746297314? The idea of the fix is that, when -1 << 64 would overflow, is because we don't need to do any masking at all.
Comment From: huangzhw
@antirez I agree with the proposed fix in 7462973. It is simple and correct!
Comment From: antirez
Thanks @huangzhw! Closing.