Fix hscan return value (#13297)

In the last step of hscan, while replying to client, we assume all items
in the result list are keys which are mstr instances. Though, there 
might be values which are sds instances. 

Added a check to avoid calling mstrlen() for value objects.

To reproduce:
```
127.0.0.1:6379> hset myhash1 a 11111111111111111111111111111111111111111111111111111111111111111
(integer) 0
127.0.0.1:6379> hscan myhash1 0
1) "0"
2) 1) "a"
   2) "11111111111111111111111111111111111111111111111111111111111111111\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
```
This commit is contained in:
Ozan Tezcan 2024-05-28 11:59:57 +03:00 committed by GitHub
parent e2918705c8
commit 6a11d458be
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 31 additions and 1 deletions

View File

@ -1299,10 +1299,14 @@ void scanGenericCommand(client *c, robj *o, unsigned long long cursor) {
addReplyArrayLen(c, 2);
addReplyBulkLongLong(c,cursor);
unsigned long long idx = 0;
addReplyArrayLen(c, listLength(keys));
while ((node = listFirst(keys)) != NULL) {
void *key = listNodeValue(node);
addReplyBulkCBuffer(c, key, (isKeysHfield) ? mstrlen(key) : sdslen(key));
/* For HSCAN, list will contain keys value pairs unless no_values arg
* was given. We should call mstrlen for the keys only. */
int hfieldkey = isKeysHfield && (no_values || (idx++ % 2 == 0));
addReplyBulkCBuffer(c, key, hfieldkey ? mstrlen(key) : sdslen(key));
listDelNode(keys, node);
}

View File

@ -277,6 +277,32 @@ proc test_scan {type} {
set res [r hscan hash 0 count 1000 novalues]
assert_equal [lsort $keys2] [lsort [lindex $res 1]]
}
test "{$type} HSCAN with large value $enc" {
r del hash
if {$enc eq {listpack}} {
set count 60
} else {
set count 170
}
set val1 [string repeat "1" $count]
r hset hash $val1 $val1
set val2 [string repeat "2" $count]
r hset hash $val2 $val2
set res [lsort [lindex [r hscan hash 0] 1]]
assert_equal $val1 [lindex $res 0]
assert_equal $val1 [lindex $res 1]
assert_equal $val2 [lindex $res 2]
assert_equal $val2 [lindex $res 3]
set res [lsort [lindex [r hscan hash 0 novalues] 1]]
assert_equal $val1 [lindex $res 0]
assert_equal $val2 [lindex $res 1]
}
}
foreach enc {listpack skiplist} {