BITCOUNT: check for argument, before checking for key (#12394)

Generally, In any command we first check for  the argument and then check if key exist.

Some of the examples are

```
127.0.0.1:6379> getrange no-key invalid1 invalid2
(error) ERR value is not an integer or out of range
127.0.0.1:6379> setbit no-key 1 invalid
(error) ERR bit is not an integer or out of range
127.0.0.1:6379> xrange no-key invalid1 invalid2
(error) ERR Invalid stream ID specified as stream command argument
```

**Before change** 
```
bitcount no-key invalid1 invalid2
0
```

**After change**
```
bitcount no-key invalid1 invalid2
(error) ERR value is not an integer or out of range
```
This commit is contained in:
Wen Hui 2023-08-21 17:53:46 +08:00 committed by GitHub
parent c98a28a848
commit 45d3310694
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 23 additions and 13 deletions

View File

@ -802,25 +802,12 @@ void bitcountCommand(client *c) {
int isbit = 0;
unsigned char first_byte_neg_mask = 0, last_byte_neg_mask = 0;
/* Lookup, check for type, and return 0 for non existing keys. */
if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
checkType(c,o,OBJ_STRING)) return;
p = getObjectReadOnlyString(o,&strlen,llbuf);
/* Parse start/end range if any. */
if (c->argc == 4 || c->argc == 5) {
long long totlen = strlen;
/* Make sure we will not overflow */
serverAssert(totlen <= LLONG_MAX >> 3);
if (getLongLongFromObjectOrReply(c,c->argv[2],&start,NULL) != C_OK)
return;
if (getLongLongFromObjectOrReply(c,c->argv[3],&end,NULL) != C_OK)
return;
/* Convert negative indexes */
if (start < 0 && end < 0 && start > end) {
addReply(c,shared.czero);
return;
}
if (c->argc == 5) {
if (!strcasecmp(c->argv[4]->ptr,"bit")) isbit = 1;
else if (!strcasecmp(c->argv[4]->ptr,"byte")) isbit = 0;
@ -829,6 +816,20 @@ void bitcountCommand(client *c) {
return;
}
}
/* Lookup, check for type, and return 0 for non existing keys. */
if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
checkType(c,o,OBJ_STRING)) return;
p = getObjectReadOnlyString(o,&strlen,llbuf);
long long totlen = strlen;
/* Make sure we will not overflow */
serverAssert(totlen <= LLONG_MAX >> 3);
/* Convert negative indexes */
if (start < 0 && end < 0 && start > end) {
addReply(c,shared.czero);
return;
}
if (isbit) totlen <<= 3;
if (start < 0) start = totlen+start;
if (end < 0) end = totlen+end;
@ -844,6 +845,10 @@ void bitcountCommand(client *c) {
end >>= 3;
}
} else if (c->argc == 2) {
/* Lookup, check for type, and return 0 for non existing keys. */
if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
checkType(c,o,OBJ_STRING)) return;
p = getObjectReadOnlyString(o,&strlen,llbuf);
/* The whole string. */
start = 0;
end = strlen-1;

View File

@ -140,6 +140,11 @@ start_server {tags {"bitops"}} {
set e
} {ERR *syntax*}
test {BITCOUNT against non-integer value} {
catch {r bitcount no-key a b} e
set e
} {ERR *not an integer*}
test {BITCOUNT regression test for github issue #582} {
r del foo
r setbit foo 0 1