mirror of
https://github.com/fluencelabs/redis
synced 2025-06-27 07:51:33 +00:00
Fix memory corruption in moduleHandleBlockedClients
By using a "circular BRPOPLPUSH"-like scenario it was possible the get the same client on db->blocking_keys twice (See comment in moduleTryServeClientBlockedOnKey) The fix was actually already implememnted in moduleTryServeClientBlockedOnKey but it had a bug: the funxction should return 0 or 1 (not OK or ERR) Other changes: 1. Added two commands to blockonkeys.c test module (To reproduce the case described above) 2. Simplify blockonkeys.c in order to make testing easier 3. cast raxSize() to avoid warning with format spec
This commit is contained in:
18
src/module.c
18
src/module.c
@ -4393,14 +4393,26 @@ RedisModuleBlockedClient *moduleBlockClient(RedisModuleCtx *ctx, RedisModuleCmdF
|
||||
* can really be unblocked, since the module was able to serve the client.
|
||||
* If the callback returns REDISMODULE_OK, then the client can be unblocked,
|
||||
* otherwise the client remains blocked and we'll retry again when one of
|
||||
* the keys it blocked for becomes "ready" again. */
|
||||
* the keys it blocked for becomes "ready" again.
|
||||
* This function returns 1 if client was served (and should be unblocked) */
|
||||
int moduleTryServeClientBlockedOnKey(client *c, robj *key) {
|
||||
int served = 0;
|
||||
RedisModuleBlockedClient *bc = c->bpop.module_blocked_handle;
|
||||
/* Protect against re-processing: don't serve clients that are already
|
||||
* in the unblocking list for any reason (including RM_UnblockClient()
|
||||
* explicit call). */
|
||||
if (bc->unblocked) return REDISMODULE_ERR;
|
||||
* explicit call).
|
||||
* For example, the following pathological case:
|
||||
* Assume a module called LIST implements the same command as
|
||||
* the Redis list data type.
|
||||
* LIST.BRPOPLPUSH src dst 0 ('src' goes into db->blocking_keys)
|
||||
* LIST.BRPOPLPUSH dst src 0 ('dst' goes into db->blocking_keys)
|
||||
* LIST.LPUSH src foo
|
||||
* 'src' is in db->blocking_keys after the first BRPOPLPUSH is served
|
||||
* (and stays there until the next beforeSleep).
|
||||
* The second BRPOPLPUSH will signal 'src' as ready, leading to the
|
||||
* unblocking of the already unblocked (and worst, freed) reply_client
|
||||
* of the first BRPOPLPUSH. */
|
||||
if (bc->unblocked) return 0;
|
||||
RedisModuleCtx ctx = REDISMODULE_CTX_INIT;
|
||||
ctx.flags |= REDISMODULE_CTX_BLOCKED_REPLY;
|
||||
ctx.blocked_ready_key = key;
|
||||
|
Reference in New Issue
Block a user