From d6e8fe77afdb79853dd62581be2e785f0014bdf9 Mon Sep 17 00:00:00 2001 From: antirez Date: Thu, 14 Jun 2018 18:08:05 +0200 Subject: [PATCH] Fix infinite loop in dbRandomKey(). Thanks to @kevinmcgehee for signaling the issue and reasoning about the consequences and potential fixes. Issue #5015. --- src/db.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/db.c b/src/db.c index 16928aa0..b4190f86 100644 --- a/src/db.c +++ b/src/db.c @@ -223,6 +223,8 @@ int dbExists(redisDb *db, robj *key) { * The function makes sure to return keys not already expired. */ robj *dbRandomKey(redisDb *db) { dictEntry *de; + int maxtries = 100; + int allvolatile = dictSize(db->dict) == dictSize(db->expires); while(1) { sds key; @@ -234,6 +236,17 @@ robj *dbRandomKey(redisDb *db) { key = dictGetKey(de); keyobj = createStringObject(key,sdslen(key)); if (dictFind(db->expires,key)) { + if (allvolatile && server.masterhost && --maxtries == 0) { + /* If the DB is composed only of keys with an expire set, + * it could happen that all the keys are already logically + * expired in the slave, so the function cannot stop because + * expireIfNeeded() is false, nor it can stop because + * dictGetRandomKey() returns NULL (there are keys to return). + * To prevent the infinite loop we do some tries, but if there + * are the conditions for an infinite loop, eventually we + * return a key name that may be already expired. */ + return keyobj; + } if (expireIfNeeded(db,keyobj)) { decrRefCount(keyobj); continue; /* search for another key. This expired. */