diff --git a/src/rdb.c b/src/rdb.c index 049e3d96e..c30bd9fb7 100644 --- a/src/rdb.c +++ b/src/rdb.c @@ -128,41 +128,60 @@ int rdbSaveLen(rio *rdb, uint64_t len) { return nwritten; } -/* Load an encoded length. The "isencoded" argument is set to 1 if the length - * is not actually a length but an "encoding type". See the RDB_ENC_* - * definitions in rdb.h for more information. */ -uint64_t rdbLoadLen(rio *rdb, int *isencoded) { + +/* Load an encoded length. If the loaded length is a normal length as stored + * with rdbSaveLen(), the read length is set to '*lenptr'. If instead the + * loaded length describes a special encoding that follows, then '*isencoded' + * is set to 1 and the encoding format is stored at '*lenptr'. + * + * See the RDB_ENC_* definitions in rdb.h for more information on special + * encodings. + * + * The function returns -1 on error, 0 on success. */ +int rdbLoadLenByRef(rio *rdb, int *isencoded, uint64_t *lenptr) { unsigned char buf[2]; int type; if (isencoded) *isencoded = 0; - if (rioRead(rdb,buf,1) == 0) return RDB_LENERR; + if (rioRead(rdb,buf,1) == 0) return -1; type = (buf[0]&0xC0)>>6; if (type == RDB_ENCVAL) { /* Read a 6 bit encoding type. */ if (isencoded) *isencoded = 1; - return buf[0]&0x3F; + *lenptr = buf[0]&0x3F; } else if (type == RDB_6BITLEN) { /* Read a 6 bit len. */ - return buf[0]&0x3F; + *lenptr = buf[0]&0x3F; } else if (type == RDB_14BITLEN) { /* Read a 14 bit len. */ - if (rioRead(rdb,buf+1,1) == 0) return RDB_LENERR; - return ((buf[0]&0x3F)<<8)|buf[1]; + if (rioRead(rdb,buf+1,1) == 0) return -1; + *lenptr = ((buf[0]&0x3F)<<8)|buf[1]; } else if (buf[0] == RDB_32BITLEN) { /* Read a 32 bit len. */ uint32_t len; - if (rioRead(rdb,&len,4) == 0) return RDB_LENERR; - return ntohl(len); + if (rioRead(rdb,&len,4) == 0) return -1; + *lenptr = ntohl(len); } else if (buf[0] == RDB_64BITLEN) { /* Read a 64 bit len. */ uint64_t len; - if (rioRead(rdb,&len,8) == 0) return RDB_LENERR; - return ntohu64(len); + if (rioRead(rdb,&len,8) == 0) return -1; + *lenptr = ntohu64(len); } else { rdbExitReportCorruptRDB("Unknown length encoding in rdbLoadLen()"); - return 0; /* Never reached. */ + return -1; /* Never reached. */ } + return 0; +} + +/* This is like rdbLoadLenByRef() but directly returns the value read + * from the RDB stream, signaling an error by returning RDB_LENERR + * (since it is a too large count to be applicable in any Redis data + * structure). */ +uint64_t rdbLoadLen(rio *rdb, int *isencoded) { + uint64_t len; + + if (rdbLoadLenByRef(rdb,isencoded,&len) == -1) return RDB_LENERR; + return len; } /* Encodes the "value" argument as integer when it fits in the supported ranges @@ -299,7 +318,7 @@ ssize_t rdbSaveLzfStringObject(rio *rdb, unsigned char *s, size_t len) { void *rdbLoadLzfStringObject(rio *rdb, int flags) { int plain = flags & RDB_LOAD_PLAIN; int sds = flags & RDB_LOAD_SDS; - unsigned int len, clen; + uint64_t len, clen; unsigned char *c = NULL; char *val = NULL; @@ -414,7 +433,7 @@ void *rdbGenericLoadStringObject(rio *rdb, int flags) { int plain = flags & RDB_LOAD_PLAIN; int sds = flags & RDB_LOAD_SDS; int isencoded; - uint32_t len; + uint64_t len; len = rdbLoadLen(rdb,&isencoded); if (isencoded) { @@ -1291,7 +1310,7 @@ void rdbLoadProgressCallback(rio *r, const void *buf, size_t len) { } int rdbLoad(char *filename) { - uint32_t dbid; + uint64_t dbid; int type, rdbver; redisDb *db = server.db+0; char buf[1024]; @@ -1364,7 +1383,7 @@ int rdbLoad(char *filename) { } else if (type == RDB_OPCODE_RESIZEDB) { /* RESIZEDB: Hint about the size of the keys in the currently * selected data base, in order to avoid useless rehashing. */ - uint32_t db_size, expires_size; + uint64_t db_size, expires_size; if ((db_size = rdbLoadLen(&rdb,NULL)) == RDB_LENERR) goto eoferr; if ((expires_size = rdbLoadLen(&rdb,NULL)) == RDB_LENERR) diff --git a/src/rdb.h b/src/rdb.h index d90256127..7ef6782d1 100644 --- a/src/rdb.h +++ b/src/rdb.h @@ -59,7 +59,7 @@ #define RDB_32BITLEN 0x80 #define RDB_64BITLEN 0x81 #define RDB_ENCVAL 3 -#define RDB_LENERR UINT_MAX +#define RDB_LENERR UINT64_MAX /* When a length of a string object stored on disk has the first two bits * set, the remaining six bits specify a special encoding for the object diff --git a/src/redis-check-rdb.c b/src/redis-check-rdb.c index 7bb93b60b..1e34a62c3 100644 --- a/src/redis-check-rdb.c +++ b/src/redis-check-rdb.c @@ -171,7 +171,7 @@ static int processTime(int type) { return 0; } -static uint32_t loadLength(int *isencoded) { +static uint64_t loadLength(int *isencoded) { unsigned char buf[2]; uint32_t len; int type; @@ -190,10 +190,16 @@ static uint32_t loadLength(int *isencoded) { /* Read a 14 bit len */ if (!readBytes(buf+1,1)) return RDB_LENERR; return ((buf[0] & 0x3F) << 8) | buf[1]; - } else { + } else if (buf[0] == RDB_32BITLEN) { /* Read a 32 bit len */ if (!readBytes(&len, 4)) return RDB_LENERR; - return (unsigned int)ntohl(len); + return ntohl(len); + } else if (buf[0] == RDB_64BITLEN) { + /* Read a 64 bit len */ + if (!readBytes(&len, 8)) return RDB_LENERR; + return ntohu64(len); + } else { + return RDB_LENERR; } } @@ -230,7 +236,7 @@ static char *loadIntegerObject(int enctype) { } static char* loadLzfStringObject() { - unsigned int slen, clen; + uint64_t slen, clen; char *c, *s; if ((clen = loadLength(NULL)) == RDB_LENERR) return NULL; @@ -254,9 +260,9 @@ static char* loadLzfStringObject() { /* returns NULL when not processable, char* when valid */ static char* loadStringObject() { - uint32_t offset = CURR_OFFSET; + uint64_t offset = CURR_OFFSET; + uint64_t len; int isencoded; - uint32_t len; len = loadLength(&isencoded); if (isencoded) { @@ -269,7 +275,7 @@ static char* loadStringObject() { return loadLzfStringObject(); default: /* unknown encoding */ - SHIFT_ERROR(offset, "Unknown string encoding (0x%02x)", len); + SHIFT_ERROR(offset, "Unknown string encoding (0x%02llx)", len); return NULL; } } @@ -344,8 +350,8 @@ static int processDoubleValue(double** store) { } static int loadPair(entry *e) { - uint32_t offset = CURR_OFFSET; - uint32_t i; + uint64_t offset = CURR_OFFSET; + uint64_t i; /* read key first */ char *key; @@ -356,7 +362,7 @@ static int loadPair(entry *e) { return 0; } - uint32_t length = 0; + uint64_t length = 0; if (e->type == RDB_TYPE_LIST || e->type == RDB_TYPE_SET || e->type == RDB_TYPE_ZSET || @@ -384,7 +390,7 @@ static int loadPair(entry *e) { for (i = 0; i < length; i++) { offset = CURR_OFFSET; if (!processStringObject(NULL)) { - SHIFT_ERROR(offset, "Error reading element at index %d (length: %d)", i, length); + SHIFT_ERROR(offset, "Error reading element at index %llu (length: %llu)", i, length); return 0; } } @@ -393,12 +399,12 @@ static int loadPair(entry *e) { for (i = 0; i < length; i++) { offset = CURR_OFFSET; if (!processStringObject(NULL)) { - SHIFT_ERROR(offset, "Error reading element key at index %d (length: %d)", i, length); + SHIFT_ERROR(offset, "Error reading element key at index %llu (length: %llu)", i, length); return 0; } offset = CURR_OFFSET; if (!processDoubleValue(NULL)) { - SHIFT_ERROR(offset, "Error reading element value at index %d (length: %d)", i, length); + SHIFT_ERROR(offset, "Error reading element value at index %llu (length: %llu)", i, length); return 0; } } @@ -407,12 +413,12 @@ static int loadPair(entry *e) { for (i = 0; i < length; i++) { offset = CURR_OFFSET; if (!processStringObject(NULL)) { - SHIFT_ERROR(offset, "Error reading element key at index %d (length: %d)", i, length); + SHIFT_ERROR(offset, "Error reading element key at index %llu (length: %llu)", i, length); return 0; } offset = CURR_OFFSET; if (!processStringObject(NULL)) { - SHIFT_ERROR(offset, "Error reading element value at index %d (length: %d)", i, length); + SHIFT_ERROR(offset, "Error reading element value at index %llu (length: %llu)", i, length); return 0; } } @@ -428,7 +434,7 @@ static int loadPair(entry *e) { static entry loadEntry() { entry e = { NULL, -1, 0 }; - uint32_t length, offset[4]; + uint64_t length, offset[4]; /* reset error container */ errors.level = 0; @@ -445,7 +451,7 @@ static entry loadEntry() { return e; } if (length > 63) { - SHIFT_ERROR(offset[1], "Database number out of range (%d)", length); + SHIFT_ERROR(offset[1], "Database number out of range (%llu)", length); return e; } } else if (e.type == RDB_OPCODE_EOF) {