summaryrefslogtreecommitdiff
path: root/src/bitops.c
diff options
context:
space:
mode:
authorSalvatore Sanfilippo <antirez@gmail.com>2016-06-16 12:52:36 +0200
committerGitHub <noreply@github.com>2016-06-16 12:52:36 +0200
commit33a9836fe32acffdf6fb34c8712e805d0986a956 (patch)
tree3362101e26fe7e2f46d6aeb5e09a54e127e7dfbd /src/bitops.c
parent5d83f6cfdeef7b493a67559c8d79d852abec16e9 (diff)
parent5d96b7ed4ffc1b90195fd4074ead331236e8e28f (diff)
downloadredis-33a9836fe32acffdf6fb34c8712e805d0986a956.tar.gz
Merge pull request #3264 from oranagra/bitfield_fix2
fix crash in BITFIELD GET on non existing key or wrong type see #3259
Diffstat (limited to 'src/bitops.c')
-rw-r--r--src/bitops.c29
1 files changed, 20 insertions, 9 deletions
diff --git a/src/bitops.c b/src/bitops.c
index 781cc58d6..9ae52c81b 100644
--- a/src/bitops.c
+++ b/src/bitops.c
@@ -906,6 +906,8 @@ void bitfieldCommand(client *c) {
int j, numops = 0, changes = 0;
struct bitfieldOp *ops = NULL; /* Array of ops to execute at end. */
int owtype = BFOVERFLOW_WRAP; /* Overflow type. */
+ int readonly = 1;
+ long highestWriteOffset = 0;
for (j = 2; j < c->argc; j++) {
int remargs = c->argc-j-1; /* Remaining args other than current. */
@@ -953,8 +955,10 @@ void bitfieldCommand(client *c) {
return;
}
- /* INCRBY and SET require another argument. */
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){
zfree(ops);
return;
@@ -974,6 +978,18 @@ void bitfieldCommand(client *c) {
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);
/* Actually process the operations. */
@@ -988,11 +1004,6 @@ void bitfieldCommand(client *c) {
* for simplicity. SET return value is the previous value so
* 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
* and unsigned operations, since the set of functions to get/set
* the integers and the used variables types are different. */
@@ -1060,12 +1071,12 @@ void bitfieldCommand(client *c) {
} else {
/* GET */
unsigned char buf[9];
- long strlen;
+ long strlen = 0;
unsigned char *src = NULL;
char llbuf[LONG_STR_SIZE];
- o = lookupKeyRead(c->db,c->argv[1]);
- src = getObjectReadOnlyString(o,&strlen,llbuf);
+ if (o != NULL)
+ src = getObjectReadOnlyString(o,&strlen,llbuf);
/* For GET we use a trick: before executing the operation
* copy up to 9 bytes to a local buffer, so that we can easily