Re: [PATCH] Segfault in pool_do_auth() when failover races with a new connection

From: Tatsuo Ishii <ishii(at)postgresql(dot)org>
To: emond(dot)papegaaij(at)gmail(dot)com
Cc: pgpool-hackers(at)lists(dot)postgresql(dot)org
Subject: Re: [PATCH] Segfault in pool_do_auth() when failover races with a new connection
Date: 2026-07-02 07:39:22
Message-ID: 20260702.163922.30147080599128209.ishii@postgresql.org
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgpool-hackers

Hi Emond,

> Hi,
>
> Last night one of CI builds detected a segmentation fault in pgpool
> (4.7.2). I've ran an analysis on the coredump with Claude and came to
> the conclusion that this can happen when trying to open a connection
> in the middle of a failover.
>
> Symptom / backtrace (resolved from the core dump):
> pool_do_auth (src/auth/pool_auth.c:349) <-- SIGSEGV, fault addr 0x0
> connect_backend (src/protocol/child.c:1099) (PG_TRY block)
> get_backend_connection (src/protocol/child.c:2109)
> do_child (src/protocol/child.c:233)
>
> The crashing statement is:
> protoMajor = MAIN_CONNECTION(cp)->sp->major; /* pool_auth.c:349 */
> i.e. cp->slots[MAIN_NODE_ID] is NULL. From the core, the pool had
> slots[0] == NULL while slots[1]/slots[2] were valid, and MAIN_NODE_ID == 0.
>
> pool_initialize_private_backend_status() snapshots
> private_backend_status[] and my_main_node_id non‑atomically w.r.t. the
> parent's failover, so a child can capture my_main_node_id == 0 while
> node 0 is already CON_DOWN. new_connection() then never creates
> slots[0], and pool_do_auth() dereferences the NULL main slot. (Same
> class as the NULL‑MAIN_CONNECTION case noted in
> pool_virtual_main_db_node_id().)

From pool_initialize_private_backend_status():

for (i = 0; i < MAX_NUM_BACKENDS; i++)
{
private_backend_status[i] = BACKEND_INFO(i).backend_status;
/* my_backend_status is referred to by VALID_BACKEND macro. */
my_backend_status[i] = &private_backend_status[i];
}

my_main_node_id = REAL_MAIN_NODE_ID;

BACKEND_INFO(i).backend_status are updated in the pgpool main process
at line 1793 of failover(pgpool_main.c) by calling
handle_failover_request(), but REAL_MAIN_NODE_ID (actually
Req_info->main_node_id, shared memory) is updated at 1846 of
failover() by calling save_node_info(). So updating REAL_MAIN_NODE_ID
tends to slightly delay after updating
BACKEND_INFO(i).backend_status. This may explain why my_main_node is
set the stale data (1).

Another possibility is my_main_node_id being lacking volatile
qualification. This also could set stale data to my_main_node_id (2).

Of course (1) and (2) are not mutually exclusive. So your patch for
(1) and fix for (2) need to be both applied.

By the way in your patch there is loops like this. This can be
replaced by existing get_next_main_node().

+ for (i = 0; i < NUM_BACKENDS; i++)
+ {
+ if (private_backend_status[i] == CON_UP ||
+ private_backend_status[i] == CON_CONNECT_WAIT)
+ {
+ my_main_node_id = i;
+ break;
+ }
+ }

All of the above in mind, I propose attached patch.

What do you think?
--
Tatsuo Ishii
SRA OSS K.K.
English: http://www.sraoss.co.jp/index_en/
Japanese:http://www.sraoss.co.jp

Attachment Content-Type Size
connect_crash_fix_v2.patch text/x-patch 3.6 KB

In response to

Responses

Browse pgpool-hackers by date

  From Date Subject
Next Message Emond Papegaaij 2026-07-02 09:21:13 Re: [PATCH] Segfault in pool_do_auth() when failover races with a new connection
Previous Message Tatsuo Ishii 2026-07-01 01:11:48 Adding volatile qualifer