From 39173a9bd0ddcbdb14d1e05bc7a82cad6e7f7fee Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Wed, 14 Oct 2026 12:05:14 +0900 Subject: [PATCH] Fix potential use-after-frees in WAL sender A WAL sender tracks its WAL reader and logical decoding context as two static variables, which were left set after being freed for a START_REPLICATION command. The WAL reader is used for in a physical replication command, both the WAL reader and the logical decoding context are used for a logical replication command. Both variables are now cleared once their contents are released at the end of each replication command, to keep the release of the resources and the maintenance of the pointers close to each other. Some more cleanup is done by WalSndErrorCleanup(), as well, once the WAL reader is clear. The assertion added by 879ad9f90e83 is moved before the execution of a replication command, checking now that both the WAL reader and the logical decoding context are never set before the execution of a new command. Author: Ayush Tiwari Reviewed-by: Michael Paquier Discussion: https://postgr.es/m/CAJTYsWW+hdmmVt_A4hvGv2_5RWK8-kaOf5ncT65=5i_hyD=BHg@mail.gmail.com Backpatch-through: 14 --- src/backend/replication/walsender.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c index 69fbb038790..bf7e12446f5 100644 --- a/src/backend/replication/walsender.c +++ b/src/backend/replication/walsender.c @@ -351,6 +351,9 @@ WalSndErrorCleanup(void) if (xlogreader != NULL && xlogreader->seg.ws_file >= 0) wal_segment_close(xlogreader); + xlogreader = NULL; + logical_decoding_ctx = NULL; + if (MyReplicationSlot != NULL) ReplicationSlotRelease(); @@ -1009,6 +1012,9 @@ StartReplication(StartReplicationCmd *cmd) Assert(streamingDoneSending && streamingDoneReceiving); } + XLogReaderFree(xlogreader); + xlogreader = NULL; + if (cmd->slotname) ReplicationSlotRelease(); @@ -1561,6 +1567,8 @@ StartLogicalReplication(StartReplicationCmd *cmd) WalSndLoop(XLogSendLogical); FreeDecodingContext(logical_decoding_ctx); + logical_decoding_ctx = NULL; + xlogreader = NULL; ReplicationSlotRelease(); replication_active = false; @@ -2064,6 +2072,9 @@ exec_replication_command(const char *cmd_string) CHECK_FOR_INTERRUPTS(); + Assert(xlogreader == NULL); + Assert(logical_decoding_ctx == NULL); + /* * Prepare to parse and execute the command. */ @@ -2204,7 +2215,6 @@ exec_replication_command(const char *cmd_string) /* dupe, but necessary per libpqrcv_endstreaming */ EndReplicationCommand(cmdtag); - Assert(xlogreader != NULL); break; }