mirror of
https://github.com/valkey-io/valkey.git
synced 2026-10-28 16:34:55 +08:00
Three issues in the `ValkeyModule_HashSetStringRef` / `ValkeyModule_HashHasStringRef` path: 1. NULL dereference. `hashTypeHasStringRef()` used `hashtableFindRef()` and dereferenced the returned pointer unconditionally. `hashtableFindRef()` returns NULL when the field is not present, so `ValkeyModule_HashHasStringRef()` on a non-existing (or expired) field crashed the server. 2. HashHasStringRef reported false positives. For a missing key or a non-hash key the function returned VALKEYMODULE_ERR, which is 1 — the exact same value it returns when the field does hold a string reference. A module could not tell "error" from "yes". Since this is a boolean predicate, there is no room for a third status value, so it now returns plain 0/1 and never an error code. 3. HashSetStringRef leaked internal status codes. It returned hashTypeUpdateAsStringRef()'s C_OK/C_ERR directly, so failures surfaced to modules as -1 instead of VALKEYMODULE_ERR (1). The status is now mapped explicitly. ## Compatibility ValkeyModule_HashHasStringRef changes its error return from VALKEYMODULE_ERR to 0. This is a behavior change for the API. --------- Signed-off-by: Shubham S Taple <shubham.s.taple@gmail.com>
68 lines
2.1 KiB
Tcl
68 lines
2.1 KiB
Tcl
set testmodule [file normalize tests/modules/hash_stringref.so]
|
|
|
|
start_server {tags {"modules"}} {
|
|
r module load $testmodule
|
|
|
|
test {Module hash set} {
|
|
r del k
|
|
set status [catch {r hash.set_stringref k f hello} errmsg]
|
|
assert {$status == 1}
|
|
r hset k f hello1
|
|
assert_equal "0" [r hash.has_stringref k f]
|
|
r hash.set_stringref k f hello1
|
|
assert_equal "hello1" [r hget k f]
|
|
assert_equal "1" [r hash.has_stringref k f]
|
|
}
|
|
|
|
test {Module hash set_stringref on a field which does not exist} {
|
|
r del k
|
|
r hset k f hello1
|
|
set status [catch {r hash.set_stringref k nofield hello2} errmsg]
|
|
assert {$status == 1}
|
|
assert_equal "hello1" [r hget k f]
|
|
assert_equal "0" [r hash.has_stringref k f]
|
|
r hash.set_stringref k f hello1
|
|
assert_equal "hello1" [r hget k f]
|
|
assert_equal "1" [r hash.has_stringref k f]
|
|
assert_equal "0" [r hash.has_stringref k nofield]
|
|
}
|
|
|
|
test {Module hash has_stringref on a field which does not exist} {
|
|
r del k
|
|
r hset k f hello1
|
|
assert_encoding listpack k
|
|
assert_equal "0" [r hash.has_stringref k nofield]
|
|
|
|
r hash.set_stringref k f hello1
|
|
assert_encoding hashtable k
|
|
assert_equal "1" [r hash.has_stringref k f]
|
|
assert_equal "0" [r hash.has_stringref k nofield]
|
|
}
|
|
|
|
test {Module hash has_stringref on an expired field} {
|
|
r del k
|
|
r hset k f1 hello1 f2 hello2
|
|
r hash.set_stringref k f1 hello1
|
|
r hash.set_stringref k f2 hello2
|
|
r hpexpire k 1 FIELDS 1 f1
|
|
wait_for_condition 50 100 {
|
|
[r hash.has_stringref k f1] eq 0
|
|
} else {
|
|
fail "Hash field did not expire"
|
|
}
|
|
assert_equal "1" [r hash.has_stringref k f2]
|
|
}
|
|
|
|
test {Module hash has_stringref on a missing key or a non hash key} {
|
|
r del k
|
|
assert_equal "0" [r hash.has_stringref k f]
|
|
r lpush k v
|
|
assert_equal "0" [r hash.has_stringref k f]
|
|
r del k
|
|
}
|
|
|
|
test "Unload the module - hash" {
|
|
assert_equal {OK} [r module unload hash.stringref]
|
|
}
|
|
}
|