From 01370879bb0fe4065d06d92efb01582d1b1df996 Mon Sep 17 00:00:00 2001
From: Masahiko Sawada <sawada.mshk@gmail.com>
Date: Fri, 24 Apr 2026 10:36:55 -0700
Subject: [PATCH] Fix race condition in XLogLogicalInfo and ProcSignal
 initialization

Previously, InitializeProcessXLogLogicalInfo() was called before
ProcSignalInit(). This created a window where a process could miss a
signal barrier if it was issued between these two calls. As a result,
the process could fail to update its local XLogLogicalInfo cache,
leading to an inconsistent logical decoding state.

This commit fixes this by moving InitializeProcessXLogLogicalInfo()
after ProcSignalInit(). This ensures that the process is registered to
participate in signal barriers before its state is initialized,
preventing it from missing any state change propagated during the
startup sequence.

Discussion: https://postgr.es/m/
---
 src/backend/postmaster/auxprocess.c | 17 ++++++++++++-----
 src/backend/utils/init/postinit.c   | 20 ++++++++++++--------
 2 files changed, 24 insertions(+), 13 deletions(-)

diff --git a/src/backend/postmaster/auxprocess.c b/src/backend/postmaster/auxprocess.c
index 8fdc518b3a1..01cced61492 100644
--- a/src/backend/postmaster/auxprocess.c
+++ b/src/backend/postmaster/auxprocess.c
@@ -71,12 +71,16 @@ AuxiliaryProcessMainCommon(void)
 	ProcSignalInit(NULL, 0);
 
 	/*
-	 * Initialize a local cache of the data_checksum_version, to be updated by
-	 * the procsignal-based barriers.
+	 * Initialize local states, to be updated by the procsignal-based
+	 * barriers.
 	 *
-	 * This intentionally happens after initializing the procsignal, otherwise
-	 * we might miss a state change. This means we can get a barrier for the
-	 * state we've just initialized - but it can happen only once.
+	 * These initialization intentionally happens afater initializing the
+	 * procsignal, otherwise we might miss a state change. This means we can
+	 * get a barrier for the state we've just initialized.
+	 */
+
+	/*
+	 * Initialize a local cache of the data_checksum_version.
 	 *
 	 * The postmaster (which is what gets forked into the new child process)
 	 * does not handle barriers, therefore it may not have the current value
@@ -88,6 +92,9 @@ AuxiliaryProcessMainCommon(void)
 	 */
 	InitLocalDataChecksumState();
 
+	/* Initialize logical info WAL logging state */
+	InitializeProcessXLogLogicalInfo();
+
 	/*
 	 * Auxiliary processes don't run transactions, but they may need a
 	 * resource owner anyway to manage buffer pins acquired outside
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index 6f074013aa9..96b06e444ec 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -662,9 +662,6 @@ BaseInit(void)
 	/* Initialize lock manager's local structs */
 	InitLockManagerAccess();
 
-	/* Initialize logical info WAL logging state */
-	InitializeProcessXLogLogicalInfo();
-
 	/*
 	 * Initialize replication slots after pgstat. The exit hook might need to
 	 * drop ephemeral slots, which in turn triggers stats reporting.
@@ -759,12 +756,16 @@ InitPostgres(const char *in_dbname, Oid dboid,
 	ProcSignalInit(MyCancelKey, MyCancelKeyLength);
 
 	/*
-	 * Initialize a local cache of the data_checksum_version, to be updated by
-	 * the procsignal-based barriers.
+	 * Initialize local states, to be updated by the procsignal-based
+	 * barriers.
 	 *
-	 * This intentionally happens after initializing the procsignal, otherwise
-	 * we might miss a state change. This means we can get a barrier for the
-	 * state we've just initialized.
+	 * These initialization intentionally happens afater initializing the
+	 * procsignal, otherwise we might miss a state change. This means we can
+	 * get a barrier for the state we've just initialized.
+	 */
+
+	/*
+	 * Initialize a local cache of the data_checksum_version.
 	 *
 	 * The postmaster (which is what gets forked into the new child process)
 	 * does not handle barriers, therefore it may not have the current value
@@ -776,6 +777,9 @@ InitPostgres(const char *in_dbname, Oid dboid,
 	 */
 	InitLocalDataChecksumState();
 
+	/* Initialize logical info WAL logging state */
+	InitializeProcessXLogLogicalInfo();
+
 	/*
 	 * Also set up timeout handlers needed for backend operation.  We need
 	 * these in every case except bootstrap.
-- 
2.53.0

