Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wVSzZ-001yzr-0r for pgsql-hackers@arkaria.postgresql.org; Fri, 05 Jun 2026 11:45:37 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wVSzY-00C1mZ-0e for pgsql-hackers@arkaria.postgresql.org; Fri, 05 Jun 2026 11:45:36 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wVSzX-00C1mQ-2t for pgsql-hackers@lists.postgresql.org; Fri, 05 Jun 2026 11:45:35 +0000 Received: from mail-ej1-x631.google.com ([2a00:1450:4864:20::631]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1wVSzV-00000001PXp-449D for pgsql-hackers@lists.postgresql.org; Fri, 05 Jun 2026 11:45:35 +0000 Received: by mail-ej1-x631.google.com with SMTP id a640c23a62f3a-bec4639953dso306923566b.1 for ; Fri, 05 Jun 2026 04:45:33 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1780659933; cv=none; d=google.com; s=arc-20240605; b=lwGE5p+kLSburGYpNeXt5hz2AFhDN6dGacQGShrNd+4f/TKa6awVeoXKX0DCgwZXoX p/CcaEf0BhPxH3QZtBysW1pqYxajKqfUH2mrenYGplMUom0piEWqM3Pp6Pnk4c5SJXIy oTKDLvJPx/f0PR9veEncPlFWFVUI19xBC8kkN5UVYs2iyqkmDHeUeCrXwBjD9iXMRGz5 YYpSySgU01njwKPh4kkYxp1MCzVsAWvxK8+mPdkRqNVqnw/wpwjaBPirxgdGNJKseN4z fSlqRv2zRhLfKjVBoi/yJtNRnmmOl2kuU7woJ9uVwmsuoQYHchBYxrjHwVI/6acD7nqL FyEQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:dkim-signature; bh=LOjgYusfT4+UW93R3jK/OH6ekDNgyVBkrRPxfjV30M4=; fh=mQ8T129vK60uiX9dvzcp4hw2qKe/LeaxPqDjTVwRzVY=; b=IBDETGK8I7Qfl4JM9Aldm6afz05Br9YBQhvKVJhXifskZQyECdCFzPwAo8wqSMq+2J kkMCW2IR1EgsHjDaOkJzeZSHg14q+huTTaL6G14uZTsUe4sSPes3+vjTscgnoQtk58/9 gN5kx0VxNA6YvU4R+5c4SkZwjmPj0YkJFvy5Mt3gYVM0DO1/444Uu6tbzimw8As380eN hW1l/jzrThm56uKDHHaciLLEyjxAF8GkQssRJ5TlKQCP+xZpJalCL2/rnRdBlNNhAnN6 T0AML4QSRqCZk+5ZSLvhTAmHTT90QLIa2qJQUocHlhVqFjUGkuA9/DGCULAVYVyrUHKE 4/eQ==; darn=lists.postgresql.org ARC-Authentication-Results: i=1; mx.google.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1780659933; x=1781264733; darn=lists.postgresql.org; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=LOjgYusfT4+UW93R3jK/OH6ekDNgyVBkrRPxfjV30M4=; b=JsvKYRpKiRjOtgVspmt9IhW/whowZaq0pM+EhGT6hS8RJcK7MhCuN7Xnq7QPKLinRl 1FTiwxgd7bojSkAHBu8XajVQZx8vvoAzzHssM6wzm5H0dDImzspdI08GrMqrSHThBEfj cenJR1A7ZH3IxPvuYI24AOoBRxXhdRqNtR0tDmsITddQVDVymzdOhPdc69rb/9I44aUH 0kUEr9lt/sqhLpIso9Zki/JQqGHF8Z1VqQWtkovrC6EIPac0UUBVA8YjxLafc2/fAEBT 0w56nsv9NGIG171Y8So6jMlWAjcesY2Tiq1ZkJ/m6b9KoblCQfd8kDgzsOs6frrVpPfO 590A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780659933; x=1781264733; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=LOjgYusfT4+UW93R3jK/OH6ekDNgyVBkrRPxfjV30M4=; b=fWaPVYhatT6PJjM6WZYprvCXfriyo1jDRVp+pZPc2vZ6giZVUfIWTi+MjD2TxTWukj uIhQAAkOOLUtlJmMQ6K46pe8cNLNLew43ro/ZgmhlXCoTvwNfggDGih7GHfom3iWrrLR yaBQkGDlvZ1F4/Fcoi4n7OSQxz4E/gOTCA+TguxIKBbbpN/aupVnEPwVHTSvSSfdD48i 4ssZe6EjpX1Jue5RFwhQlfpisshypfgVuUkY/5+LuWredKqkNXlYNODxX29I/Pjdytfq ZLLWBJLIeAN17L6HdxGy4nkJ/TO2/g6M6HhzWIaqZQtGZhsOnVZyOUHnzOveyasR90nQ fwGA== X-Forwarded-Encrypted: i=1; AFNElJ8W8ITV27kZRMTfDu3BnMvGbr3pANgi4fy/K/CgcoSjIUIHR+7rHo3oR8RHeElHXDGwEUb2PaS+k+BRt11C@lists.postgresql.org X-Gm-Message-State: AOJu0YysbrHs00+ek0ka0SeauHgjuZof44TdNMtUgcuQ33TohfnmXmxH XkyOK4La96JV5ke/8MaMnlfv2diUi8Xmm2yD6sipXppxzQYBSXSONA4kARz14OCskaDZdNCEwuR 69A2rdrEtiIjJAXQP+tFbHk2iV9pMUpk= X-Gm-Gg: Acq92OG1vCWfSRG9+Pi1mLRbxlx1FMeqU0iKZWmDjxFack6R6hD8zLdN1bdWtK1N+IF gwA2KtmDDPgBX3oIHIEH5HELkd9O7bcegJYmsOdWIdgVgd0UeuXnHdSMvPdDU9YTZrnUgqzkOLm 4SQo2Sj8nzAyWAlkqysHzJ51GN+7+jEkeBYf7g/Fd+QVQxDJBXh7pcpN+NyXWE1/7qdAu0KVPWT Suq2CY3npnNYwxzkPz5g/lPseXpAJYRx6FllReL+pBzE5TuHXxgf9Ea/hmr0GXoRDqLUVr7mDGT Snodz2OuVyWm2tetnqry1bWjUDNUKLpzqknz+CZhLfWUr6N97yHe472kQJ9Zf3SsX75T4GlZEes i6AHj1KHlGDocBhOiOy8b+rq5kYt4uLMt1lGLTNtgfryI9vzOdfM= X-Received: by 2002:a17:907:7f89:b0:bee:215e:5480 with SMTP id a640c23a62f3a-bf36fd9c65dmr148903366b.9.1780659932342; Fri, 05 Jun 2026 04:45:32 -0700 (PDT) MIME-Version: 1.0 References: In-Reply-To: From: Xuneng Zhou Date: Fri, 5 Jun 2026 19:45:20 +0800 X-Gm-Features: AVVi8CeIhfQKnkBFezB23eyIRdThm8KktQ_j93We4WZFPwVAwDf-CrsDYabJjBA Message-ID: Subject: Re: Fix race in ReplicationSlotRelease for ephemeral slots To: Fujii Masao Cc: "Zhijie Hou (Fujitsu)" , Srinath Reddy Sadipiralla , PostgreSQL Hackers Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk Hi Fujii-san, On Wed, Jun 3, 2026 at 8:03=E2=80=AFPM Fujii Masao = wrote: > > On Tue, Jun 2, 2026 at 3:00=E2=80=AFPM Xuneng Zhou = wrote: > > > > Hi, > > > > On Sat, May 30, 2026 at 4:14=E2=80=AFPM Zhijie Hou (Fujitsu) > > wrote: > > > I'm not sure if adding an injection point for this rare case is worth= while. Even > > > if we were to add one, future refactoring of that function could shif= t the > > > position of the injection point, so its long-term usefulness is uncer= tain. I > > > don't have a strong opinion on this, so I'll leave it to Fujii-San to= decide. > > I've pushed the patch. Thanks! > > IMO the proposed test looks a bit too narrow, so I'm not sure it's worth > adding at this point. For now, I've committed only the code fix. > > > > There's an adjacent bug around drop_local_obsolete_slots. The root > > cause of them looks similar -- ReplicationSlot * is a pointer to a > > reusable shared-memory array cell, not a durable identity for the same > > slot. In drop_local_obsolete_slots, the issue is that the slot has > > been freed after ReplicationSlotDropAcquired(false); however, another > > backend may reuse the same cell before the unlock/log reads. This > > seems less severe -- it does not normally corrupt slot state, because > > the code only read after the drop. But it can still unlock/log > > misusing the identity of a different slot. Attached a test using > > injection point to reproduce it and a patch to fix it. > > Thanks again for the report and patch! > > /* Drop the local slot if it is not required to be retained. */ > if (!local_sync_slot_required(local_slot, remote_slot_list)) > { > + bool dropped =3D false; > + NameData slot_name =3D {0}; > + Oid slot_database =3D local_slot->data.database; > bool synced_slot; > > Is it really safe to read slot_database before acquiring the database loc= k? Reading slot_database before taking the database lock seems not inherently unsafe by itself. The comment suggests that the lock is primarily used to prevent conflicts with the startup process running ReplicationSlotsDropDBSlots() during db-drop replay; it does not protect replication slot array reuse. The unsafe part could be reading slot_database from local_slot after ReplicationSlotControlLock has been released. At this point, the slot array cell may already have been freed and reused, so the value read may no longer belong to the slot that get_local_synced_slots() originally collected. As a result, we could end up locking the wrong database. There seems to be two related issues: 1) Before drop: reading local_slot->data.database / local_slot->data.name after the slot-array lock was released, before verifying the cell still represents the same synced slot. 2) After drop: calling ReplicationSlotDropAcquired(false) and then reading local_slot->data.database / local_slot->data.name for unlocking/logging after the cell may have been reused by another backend. The prior patch targets to fix 2), but leaves 1) unfixed. > BTW, I'm also wondering whether it's safe for > local_sync_slot_required() to access local_slot without holding a lock. I share the same concern here. The issue smells similar to the one discussed above -- reading values from the array cell directly without the protection of array lock. To solve them altogether, it might be better to stop carrying raw ReplicationSlot * values across unprotected windows. We can get the snapshot values such as slot name & database oid from get_local_synced_slots() instead. Then local_sync_slot_required() works from the snapshot, and drop_local_obsolete_slots() uses the copied database OID to take the database lock. Before dropping, it should revalidate by copied name/database that the slot is still a synced logical slot, then acquire/drop by copied name, and use only copied values for unlock/logging. I plan to prepare a refactoring patch for this. Does that seem like the right direction to you? -- Regards, Xuneng Zhou HighGo Software Co., Ltd.