Fix module unblock crash due to no timeout_callback (#13017)
The block timeout is passed in the test case, but we do not pass in the timeout_callback, and it will crash when unlocking. In this case, in moduleBlockedClientTimedOut we will check timeout_callback. There is the stack: ``` beforeSleep blockedBeforeSleep handleBlockedClientsTimeout checkBlockedClientTimeout unblockClientOnTimeout replyToBlockedClientTimedOut moduleBlockedClientTimedOut -- timeout_callback is NULL, invalidFunctionWasCalled bc->timeout_callback(&ctx,(void**)c->argv,c->argc); ```
This commit is contained in:
parent
f469dd8ca6
commit
74a6e48a3d
@ -8438,7 +8438,12 @@ void moduleBlockedClientTimedOut(client *c, int from_module) {
|
||||
if (!from_module)
|
||||
prev_error_replies = server.stat_total_error_replies;
|
||||
|
||||
bc->timeout_callback(&ctx,(void**)c->argv,c->argc);
|
||||
if (bc->timeout_callback) {
|
||||
/* In theory, the user should always pass the timeout handler as an
|
||||
* argument, but better to be safe than sorry. */
|
||||
bc->timeout_callback(&ctx,(void**)c->argv,c->argc);
|
||||
}
|
||||
|
||||
moduleFreeContext(&ctx);
|
||||
|
||||
if (!from_module)
|
||||
|
@ -629,16 +629,23 @@ static void timer_callback(RedisModuleCtx *ctx, void *data)
|
||||
RedisModule_FreeThreadSafeContext(reply_ctx);
|
||||
}
|
||||
|
||||
/* unblock_by_timer <period_ms> <timeout_ms>
|
||||
* period_ms is the period of the timer.
|
||||
* timeout_ms is the blocking timeout. */
|
||||
int unblock_by_timer(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
|
||||
{
|
||||
if (argc != 2)
|
||||
if (argc != 3)
|
||||
return RedisModule_WrongArity(ctx);
|
||||
|
||||
long long period;
|
||||
long long timeout;
|
||||
if (RedisModule_StringToLongLong(argv[1],&period) != REDISMODULE_OK)
|
||||
return RedisModule_ReplyWithError(ctx,"ERR invalid period");
|
||||
if (RedisModule_StringToLongLong(argv[2],&timeout) != REDISMODULE_OK) {
|
||||
return RedisModule_ReplyWithError(ctx,"ERR invalid timeout");
|
||||
}
|
||||
|
||||
RedisModuleBlockedClient *bc = RedisModule_BlockClient(ctx, NULL, NULL, NULL, 0);
|
||||
RedisModuleBlockedClient *bc = RedisModule_BlockClient(ctx, NULL, NULL, NULL, timeout);
|
||||
RedisModule_CreateTimer(ctx, period, timer_callback, bc);
|
||||
return REDISMODULE_OK;
|
||||
}
|
||||
|
@ -278,7 +278,17 @@ foreach call_type {nested normal} {
|
||||
}
|
||||
|
||||
test {Unblock by timer} {
|
||||
assert_match "OK" [r unblock_by_timer 100]
|
||||
# When the client is unlock, we will get the OK reply.
|
||||
assert_match "OK" [r unblock_by_timer 100 0]
|
||||
}
|
||||
|
||||
test {block time is shorter than timer period} {
|
||||
# This command does not have the reply.
|
||||
set rd [redis_deferring_client]
|
||||
$rd unblock_by_timer 100 10
|
||||
# Wait for the client to unlock.
|
||||
after 120
|
||||
$rd close
|
||||
}
|
||||
|
||||
test "Unload the module - blockedclient" {
|
||||
|
Loading…
x
Reference in New Issue
Block a user