Skip to content

Commit 5ebb853

Browse files
rlerdorfclaude
authored andcommitted
Fix segfault during Redis Cluster failover
When a Redis Cluster failover occurs, the client detects that the redirected node was a replica of the old master and calls cluster_map_keyspace() to remap the cluster topology. If cluster_map_keyspace() fails (e.g., due to network issues during the remap), it frees all node objects via zend_hash_clean(c->nodes) and zeros the master array via memset(c->master, 0, ...). The bug was that the return value of cluster_map_keyspace() was being ignored in the failover detection path. This caused the code to continue with NULL socket pointers, leading to segfaults when dereferencing c->cmd_sock later. This fix: 1. Checks the return value of cluster_map_keyspace() in failover detection and returns FAILURE if it fails 2. Adds defense-in-depth NULL checks after MOVED and ASK redirections to prevent segfaults if slots become NULL for any reason Fixes production crashes observed during Redis Cluster failovers. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent f5db01b commit 5ebb853

File tree

1 file changed

+14
-1
lines changed

1 file changed

+14
-1
lines changed

cluster_library.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1431,7 +1431,10 @@ static int cluster_update_slot(redisCluster *c) {
14311431
if (!CLUSTER_REDIR_CMP(c, slave->sock)) {
14321432
// Detected a failover, the redirected node was a replica
14331433
// Remap the cluster's keyspace
1434-
cluster_map_keyspace(c);
1434+
if (cluster_map_keyspace(c) == FAILURE) {
1435+
CLUSTER_THROW_EXCEPTION("Failed to remap cluster keyspace after failover", 0);
1436+
return FAILURE;
1437+
}
14351438
return SUCCESS;
14361439
}
14371440
} ZEND_HASH_FOREACH_END();
@@ -1610,9 +1613,19 @@ PHP_REDIS_API short cluster_send_command(redisCluster *c, short slot, const char
16101613
return -1;
16111614
}
16121615
c->cmd_sock = SLOT_SOCK(c, slot);
1616+
/* Verify slot is valid after update */
1617+
if (!c->cmd_sock) {
1618+
CLUSTER_THROW_EXCEPTION("Socket for slot is NULL after MOVED redirection", 0);
1619+
return -1;
1620+
}
16131621
} else if (c->redir_type == REDIR_ASK) {
16141622
/* For ASK redirection we want to redirect but not update slot mapping */
16151623
c->cmd_sock = cluster_get_asking_sock(c);
1624+
/* Verify socket from ASK redirection */
1625+
if (!c->cmd_sock) {
1626+
CLUSTER_THROW_EXCEPTION("Socket is NULL after ASK redirection", 0);
1627+
return -1;
1628+
}
16161629
}
16171630
}
16181631

0 commit comments

Comments
 (0)