mirror of
https://github.com/fluencelabs/redis
synced 2025-03-19 09:00:51 +00:00
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:
commit
33a9836fe3
27
src/bitops.c
27
src/bitops.c
@ -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,11 +1071,11 @@ 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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user