Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 13 additions & 8 deletions src/rdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -2729,12 +2729,13 @@ robj *rdbLoadObject(int rdbtype, rio *rdb, sds key, int dbid, int *error)
{
quicklist *ql = quicklistNew(server.list_max_listpack_size,
server.list_compress_depth);
if (
int list_zl_valid = ziplistValidateIntegrity(encoded, encoded_len, 1,
_listZiplistEntryConvertAndValidate, ql);
if (
#ifdef ENABLE_SWAP
!rdbLoadObjectGetSkipEmptyCheckFlag() &&
!rdbLoadObjectGetSkipEmptyCheckFlag() &&
#endif
!ziplistValidateIntegrity(encoded, encoded_len, 1,
_listZiplistEntryConvertAndValidate, ql))
!list_zl_valid)

{
rdbReportCorruptRDB("List ziplist integrity check failed.");
Expand All @@ -2746,9 +2747,9 @@ robj *rdbLoadObject(int rdbtype, rio *rdb, sds key, int dbid, int *error)
}
if (
#ifdef ENABLE_SWAP
!rdbLoadObjectGetSkipEmptyCheckFlag() &&
!rdbLoadObjectGetSkipEmptyCheckFlag() &&
#endif
ql->len == 0) {
ql->len == 0) {

zfree(encoded);
o->ptr = NULL;
Expand Down Expand Up @@ -2810,11 +2811,13 @@ robj *rdbLoadObject(int rdbtype, rio *rdb, sds key, int dbid, int *error)
case RDB_TYPE_ZSET_ZIPLIST:
{
unsigned char *lp = lpNew(encoded_len);
int zset_zl_valid =
ziplistPairsConvertAndValidateIntegrity(encoded, encoded_len, &lp);
if (
#ifdef ENABLE_SWAP
!rdbLoadObjectGetSkipEmptyCheckFlag() &&
#endif
!ziplistPairsConvertAndValidateIntegrity(encoded, encoded_len, &lp)) {
!zset_zl_valid) {
rdbReportCorruptRDB("Zset ziplist integrity check failed.");
zfree(lp);
zfree(encoded);
Expand Down Expand Up @@ -2872,11 +2875,13 @@ robj *rdbLoadObject(int rdbtype, rio *rdb, sds key, int dbid, int *error)
case RDB_TYPE_HASH_ZIPLIST:
{
unsigned char *lp = lpNew(encoded_len);
int hash_zl_valid =
ziplistPairsConvertAndValidateIntegrity(encoded, encoded_len, &lp);
if (
#ifdef ENABLE_SWAP
!rdbLoadObjectGetSkipEmptyCheckFlag() &&
#endif
!ziplistPairsConvertAndValidateIntegrity(encoded, encoded_len, &lp)) {
!hash_zl_valid) {
rdbReportCorruptRDB("Hash ziplist integrity check failed.");
zfree(lp);
zfree(encoded);
Expand Down
Binary file added tests/assets/swap/rordb-ziplist.rordb
Binary file not shown.
36 changes: 36 additions & 0 deletions tests/swap/unit/rordb_ziplist_load.tcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
tags {"rdb"} {

# This fixture is an OLD-version (6.2.6-based ROR) generated rordb file that
# contains a hash and a zset stored in the legacy *ziplist* encoding
# (RDB_TYPE_HASH_ZIPLIST / RDB_TYPE_ZSET_ZIPLIST).
#
# Regression guard for the rordb-load ziplist bug: when loading a rordb
# (SkipEmptyCheckFlag = 1), rdbLoadObject() used to skip the
# ziplist->listpack data conversion(ziplistPairsConvertAndValidateIntegrity),
# leaving an empty object and silently dropping every field.
#
# With the fix, the conversion always runs, so the fields survive the load.

set server_path [tmpdir "server.rordb-ziplist-load"]

test "load rordb with legacy ziplist-encoded hash/zset preserves all fields" {
exec cp tests/assets/swap/rordb-ziplist.rordb $server_path
start_server [list overrides [list "dir" $server_path "dbfilename" "rordb-ziplist.rordb"]] {
assert_equal [r dbsize] 2

# hash: 3 fields must survive the ziplist->listpack conversion
assert_equal [r hlen ziphash] 3
assert_equal [lsort [r hgetall ziphash]] [lsort {f1 v1 f2 v2 f3 v3}]
assert_equal [r hget ziphash f1] v1
assert_equal [r hget ziphash f2] v2
assert_equal [r hget ziphash f3] v3

# zset: 3 members must survive the ziplist->listpack conversion
assert_equal [r zcard zipzset] 3
assert_equal [r zrange zipzset 0 -1 withscores] {a 1 b 2 c 3}

# full read triggers swap-in merge; must not crash / underflow
assert_equal [r ping] {PONG}
}
}
}
Loading