postgres.git / summary / log / commit / refs

commit    ea834d747d454c4fd66b08ebecaa9483476cf4a4
Author:   Amit Kapila <akapila@postgresql.org>
Date:     Thu Jun 18 04:05:53 2026 +0000
First released in: 17.11, 18.6

    Avoid stale slot access after dropping obsolete synced slots.
    
    drop_local_obsolete_slots() continued to dereference local_slot after
    calling ReplicationSlotDropAcquired().  Once the slot is dropped, its
    entry in the slot array can be reused by another backend, so later reads
    of local_slot->data could observe a different slot's name or database
    OID, leading to an incorrect unlock and log message.
    
    Save the slot name and database OID before performing the drop, and use
    the saved values for the subsequent UnlockSharedObject() call and the log
    message.  While at it, emit the "dropped replication slot" message only
    when a slot was actually dropped, rather than unconditionally.
    
    Author: Xuneng Zhou <xunengzhou@gmail.com>
    Reviewed-by: Zhijie Hou <houzj.fnst@fujitsu.com>
    Reviewed-by: Amit Kapila <amit.kapila16@gmail.com>
    Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
    Backpatch-through: 17, where it was introduced
    Discussion: https://postgr.es/m/TY4PR01MB177184FF9EE916F577E1F554194082@TY4PR01MB17718.jpnprd01.prod.outlook.com


src/backend/replication/logical/slotsync.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/backend/replication/logical/slotsync.c b/src/backend/replication/logical/slotsync.c index 555b12ec132..d6b2ebf8f25 100644 --- a/src/backend/replication/logical/slotsync.c +++ b/src/backend/replication/logical/slotsync.c @@ -447,6 +447,7 @@ drop_local_obsolete_slots(List *remote_slot_list) /* Drop the local slot if it is not required to be retained. */ if (!local_sync_slot_required(local_slot, remote_slot_list)) { + Oid slot_database = local_slot->data.database; bool synced_slot; /* @@ -454,8 +455,8 @@ drop_local_obsolete_slots(List *remote_slot_list) * ReplicationSlotsDropDBSlots(), trying to drop the same slot * during a drop-database operation. */ - LockSharedObject(DatabaseRelationId, local_slot->data.database, - 0, AccessShareLock); + LockSharedObject(DatabaseRelationId, slot_database, 0, + AccessShareLock); /* * In the small window between getting the slot to drop and @@ -472,17 +473,19 @@ drop_local_obsolete_slots(List *remote_slot_list) if (synced_slot) { - ReplicationSlotAcquire(NameStr(local_slot->data.name), true); + NameData slot_name = local_slot->data.name; + + ReplicationSlotAcquire(NameStr(slot_name), true); ReplicationSlotDropAcquired(); - } - UnlockSharedObject(DatabaseRelationId, local_slot->data.database, - 0, AccessShareLock); + ereport(LOG, + errmsg("dropped replication slot \"%s\" of database with OID %u", + NameStr(slot_name), + slot_database)); + } - ereport(LOG, - errmsg("dropped replication slot \"%s\" of database with OID %u", - NameStr(local_slot->data.name), - local_slot->data.database)); + UnlockSharedObject(DatabaseRelationId, slot_database, 0, + AccessShareLock); } } } [parent: 2e0c61aed624]