Fix listpack memory leak in zipmap-to-hash conversion on error path (#14878)

When loading RDB_TYPE_HASH_ZIPMAP objects, a listpack is allocated for
the zipmap-to-listpack conversion. If the conversion loop encounters a
duplicate key, allocation failure, or oversized listpack, the error
handler frees the dict, field, encoded buffer, and object — but not the
listpack. Add the missing lpFree(lp) call and a regression test that
RESTOREs a zipmap with duplicate keys to exercise this path.
This commit is contained in:
Zijie Zhao 2026-03-16 01:12:03 -05:00 committed by GitHub
parent a441d3db44
commit 4f0d3118e1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 25 additions and 0 deletions

View file

@ -2839,6 +2839,7 @@ robj *rdbLoadObject(int rdbtype, rio *rdb, sds key, int dbid, int *error)
rdbReportCorruptRDB("Hash zipmap with dup elements, or big length (%u)", flen);
dictRelease(dupSearchDict);
sdsfree(field);
lpFree(lp);
zfree(encoded);
o->ptr = NULL;
decrRefCount(o);

View file

@ -377,6 +377,30 @@ test {corrupt payload: hash empty zipmap} {
}
}
test {corrupt payload: hash zipmap with duplicate keys} {
# Craft a structurally valid zipmap with duplicate key "a" to trigger the
# dictAdd failure path in rdbLoadObject (RDB_TYPE_HASH_ZIPMAP).
# This exercises the error-handling branch that must free the listpack
# allocated for the zipmap-to-listpack conversion.
#
# Zipmap layout (12 bytes):
# \x02 zmlen=2
# \x01 a key "a" (len 1)
# \x01 \x00 b value "b" (len 1, free 0)
# \x01 a key "a" again (duplicate!)
# \x01 \x00 d value "d" (len 1, free 0)
# \xFF end
start_server [list overrides [list loglevel verbose use-exit-on-panic yes crash-memcheck-enabled no] ] {
r config set sanitize-dump-payload yes
r debug set-skip-checksum-validation 1
catch {
r RESTORE _hash 0 "\x09\x0C\x02\x01\x61\x01\x00\x62\x01\x61\x01\x00\x64\xFF\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00"
} err
assert_match "*Bad data format*" $err
verify_log_message 0 "*Hash zipmap with dup elements*" 0
}
}
test {corrupt payload: fuzzer findings - NPD in streamIteratorGetID} {
start_server [list overrides [list loglevel verbose use-exit-on-panic yes crash-memcheck-enabled no] ] {
r config set sanitize-dump-payload no