Merge pull request #3264 from oranagra/bitfield_fix2

fix crash in BITFIELD GET on non existing key or wrong type see #3259
This commit is contained in:
Salvatore Sanfilippo 2016-06-16 12:52:36 +02:00 committed by GitHub
commit 33a9836fe3

View File

@ -906,6 +906,8 @@ void bitfieldCommand(client *c) {
int j, numops = 0, changes = 0; int j, numops = 0, changes = 0;
struct bitfieldOp *ops = NULL; /* Array of ops to execute at end. */ struct bitfieldOp *ops = NULL; /* Array of ops to execute at end. */
int owtype = BFOVERFLOW_WRAP; /* Overflow type. */ int owtype = BFOVERFLOW_WRAP; /* Overflow type. */
int readonly = 1;
long highestWriteOffset = 0;
for (j = 2; j < c->argc; j++) { for (j = 2; j < c->argc; j++) {
int remargs = c->argc-j-1; /* Remaining args other than current. */ int remargs = c->argc-j-1; /* Remaining args other than current. */
@ -953,8 +955,10 @@ void bitfieldCommand(client *c) {
return; return;
} }
/* INCRBY and SET require another argument. */
if (opcode != BITFIELDOP_GET) { if (opcode != BITFIELDOP_GET) {
readonly = 0;
highestWriteOffset = bitoffset + bits - 1;
/* INCRBY and SET require another argument. */
if (getLongLongFromObjectOrReply(c,c->argv[j+3],&i64,NULL) != C_OK){ if (getLongLongFromObjectOrReply(c,c->argv[j+3],&i64,NULL) != C_OK){
zfree(ops); zfree(ops);
return; return;
@ -974,6 +978,18 @@ void bitfieldCommand(client *c) {
j += 3 - (opcode == BITFIELDOP_GET); j += 3 - (opcode == BITFIELDOP_GET);
} }
if (readonly) {
/* Lookup for read is ok if key doesn't exit, but errors
* if it's not a string*/
o = lookupKeyRead(c->db,c->argv[1]);
if (o != NULL && checkType(c,o,OBJ_STRING)) return;
} else {
/* Lookup by making room up to the farest bit reached by
* this operation. */
if ((o = lookupStringForBitCommand(c,
highestWriteOffset)) == NULL) return;
}
addReplyMultiBulkLen(c,numops); addReplyMultiBulkLen(c,numops);
/* Actually process the operations. */ /* Actually process the operations. */
@ -988,11 +1004,6 @@ void bitfieldCommand(client *c) {
* for simplicity. SET return value is the previous value so * for simplicity. SET return value is the previous value so
* we need fetch & store as well. */ * we need fetch & store as well. */
/* Lookup by making room up to the farest bit reached by
* this operation. */
if ((o = lookupStringForBitCommand(c,
thisop->offset + (thisop->bits-1))) == NULL) return;
/* We need two different but very similar code paths for signed /* We need two different but very similar code paths for signed
* and unsigned operations, since the set of functions to get/set * and unsigned operations, since the set of functions to get/set
* the integers and the used variables types are different. */ * the integers and the used variables types are different. */
@ -1060,12 +1071,12 @@ void bitfieldCommand(client *c) {
} else { } else {
/* GET */ /* GET */
unsigned char buf[9]; unsigned char buf[9];
long strlen; long strlen = 0;
unsigned char *src = NULL; unsigned char *src = NULL;
char llbuf[LONG_STR_SIZE]; char llbuf[LONG_STR_SIZE];
o = lookupKeyRead(c->db,c->argv[1]); if (o != NULL)
src = getObjectReadOnlyString(o,&strlen,llbuf); src = getObjectReadOnlyString(o,&strlen,llbuf);
/* For GET we use a trick: before executing the operation /* For GET we use a trick: before executing the operation
* copy up to 9 bytes to a local buffer, so that we can easily * copy up to 9 bytes to a local buffer, so that we can easily