From e542132b07a76c73cd5e1dd067671afbb4c53fe6 Mon Sep 17 00:00:00 2001 From: "zhaozhao.zz" Date: Mon, 4 Nov 2019 20:32:19 +0800 Subject: [PATCH] expires: refactoring judgment about whether a key is expired Calling lookupKey*() many times to search a key in one command may get different result. That's because lookupKey*() calls expireIfNeeded(), and delete the key when reach the expire time. So we can get an robj before the expire time, but a NULL after the expire time. The worst is that may lead to Redis crash, for example `RPOPLPUSH foo foo` the first time we get a list form `foo` and hold the pointer, but when we get `foo` again it's expired and deleted. Now we hold a freed memory, when execute rpoplpushHandlePush() redis crash. To fix it, we can refactor the judgment about whether a key is expired, using the same basetime `server.cmd_start_mstime` instead of calling mstime() everytime. --- src/db.c | 2 +- src/server.c | 1 + src/server.h | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/db.c b/src/db.c index 2c0a0cdd3..1a272faae 100644 --- a/src/db.c +++ b/src/db.c @@ -1199,7 +1199,7 @@ int keyIsExpired(redisDb *db, robj *key) { * only the first time it is accessed and not in the middle of the * script execution, making propagation to slaves / AOF consistent. * See issue #1525 on Github for more information. */ - mstime_t now = server.lua_caller ? server.lua_time_start : mstime(); + mstime_t now = server.lua_caller ? server.lua_time_start : server.cmd_start_mstime; return now > when; } diff --git a/src/server.c b/src/server.c index 8f165113d..99438ccac 100644 --- a/src/server.c +++ b/src/server.c @@ -3596,6 +3596,7 @@ int processCommand(client *c) { queueMultiCommand(c); addReply(c,shared.queued); } else { + server.cmd_start_mstime = mstime(); call(c,CMD_CALL_FULL); c->woff = server.master_repl_offset; if (listLength(server.ready_keys)) diff --git a/src/server.h b/src/server.h index f724f7d64..08eb2eef9 100644 --- a/src/server.h +++ b/src/server.h @@ -1401,6 +1401,7 @@ struct redisServer { time_t timezone; /* Cached timezone. As set by tzset(). */ int daylight_active; /* Currently in daylight saving time. */ long long mstime; /* 'unixtime' with milliseconds resolution. */ + mstime_t cmd_start_mstime; /* Pubsub */ dict *pubsub_channels; /* Map channels to list of subscribed clients */ list *pubsub_patterns; /* A list of pubsub_patterns */