forked from lei.chen/myxce
fix(controller): NULL-guard ep->owner in myreq_handler — stop round-4 restart SIGSEGV (bug-1286)
Root-caused via the non-ASAN debug build + gdb: on a chaotic restart an inbound endpoint dispatches a request (e.g. walCatchupEntry op 37) while ep->owner (cluster_t) is NULL — not yet wired at accept, or cleared during teardown. The handler did `c = ep->owner` then `ha_dispatch_gate(&c->ha, ...)`; with c==NULL, &c->ha = NULL+offsetof(cluster,ha) = 0x3ff0, a garbage pointer ha_dispatch_gate dereferenced (atomic_load &ha->role) -> SIGSEGV, dropping the node below quorum and stalling the election. Guard c==NULL after decode (so the decoded request is freed, no leak): log a loud WARN and drop the request — there is no cluster context to dispatch through and no c->myhost to address a reply. The controller stays alive (never self-terminate on an operational condition); the peer retries once the endpoint is owned. Backtrace: ha_dispatch_gate(ha=0x3ff0) <- myreq_handler cluster.c <- vtask_entry <- run_task. Second of the two round-4 blockers (bug-1282 deadlock already fixed). Re-running the 7.2 chaotic soak with both fixes. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019dbTHR9CsEYK9RsqmQpQpC
This commit is contained in:
parent
02e9275706
commit
5db734aa44
1 changed files with 17 additions and 0 deletions
|
|
@ -247,6 +247,23 @@ static int myreq_handler(vtask_t* task)
|
|||
|
||||
init_reply_by_req(&reply, &request);
|
||||
|
||||
/* bug-1286: a chaotic-restart race can run this handler on an inbound endpoint
|
||||
* whose owner (cluster_t) is NULL — not yet wired at accept time, or cleared
|
||||
* during teardown. With c == NULL, `&c->ha` is a NULL+offset garbage pointer
|
||||
* (0x3ff0) that SIGSEGV'd ha_dispatch_gate (ha.c) when it loaded ha->role.
|
||||
* Drop the request LOUDLY instead of dereferencing it: we have no cluster
|
||||
* context to dispatch through and cannot even address a reply (it needs
|
||||
* c->myhost). The controller stays alive (never self-terminate on an
|
||||
* operational condition); the peer retries once the endpoint is owned. The
|
||||
* request is freed here so the decoded packet does not leak. */
|
||||
if (c == NULL) {
|
||||
WARN("myreq_handler: endpoint %p has no owner (cluster) — dropping %s "
|
||||
"(restart race, bug-1286)", (void*)ep,
|
||||
xce_request_op_name(&request));
|
||||
xce_free_request(&request);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Dispatch gate: reject ops not allowed in current FSM state (req 1.3, 1.4) */
|
||||
rc = ha_dispatch_gate(&c->ha, request.opcode);
|
||||
if (rc != 0) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue