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 1wXdQW-003OBq-2q for pgsql-hackers@arkaria.postgresql.org; Thu, 11 Jun 2026 11:18:25 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wXdQV-00FrTQ-2P for pgsql-hackers@arkaria.postgresql.org; Thu, 11 Jun 2026 11:18:23 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wXdQV-00FrTI-14 for pgsql-hackers@lists.postgresql.org; Thu, 11 Jun 2026 11:18:23 +0000 Received: from mail-pl1-x633.google.com ([2607:f8b0:4864:20::633]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1wXdQT-00000002Abq-1wik for pgsql-hackers@lists.postgresql.org; Thu, 11 Jun 2026 11:18:22 +0000 Received: by mail-pl1-x633.google.com with SMTP id d9443c01a7336-2bf1f074a12so79809415ad.0 for ; Thu, 11 Jun 2026 04:18:21 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1781176700; cv=none; d=google.com; s=arc-20240605; b=j8D7nYGvC0vomkASiTgnp4f3/2sJmMEPx/SGLkGDALjUF6Kjqmwed2Ye4UTHwExza5 gtsK5vTwrSgI3Xg1daWBLd2ja5uh2CB4VMF4o/uMh2/kMqh3q8mjwXdkPKtx+W9zTpXX ACiAGluuqB+ZbXj2nvCkLf8aZ0T/TUKrBq92YMkCFWM5ovfyymAAuk0JvxuNYW6XW2Dz 2vLOzIylaPtupjmzA6E1ex05Val+/0+6KTMYi5ylK52Bjt8YqKz/n0Bp4h0rdjQKtQHN eHdJxfEFMkejP975a2FTgCouGRHH0rnQKVk0l8zAkZ1tel6hZOicYKWSPLAfVIQv91/7 Nl6g== 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=Mh3CrR8uJErXnmwq/Dm/RZtBbHI38eGqhEEK/Qh4lqU=; fh=CVOTkLPXOEq1eZfHgGaFflsAZ8Opu4EFxfyWujTejgo=; b=BJ+NN5/sYETbqbjgpAJpv+jmNsSYTzE0PhbhDG/hZSkljGrKurm+2aoz9V8WEnAbd+ trTH8k3eIhK/3UufSgKSXCrKtOLmHAZFALfrNvMDa8S6vzorTPkRcl4ApfU0edVnu5Ij X5DiRZr/XLr5WT7W348QdQv+x/RIz/6fRljgvEO9ibDX44cRX7Dg942v5hgq2QKyNjU3 Rv0NXHUxqesuR8QCKQrODe4xCA5h57XpyM8cfZ++hOUnAHmALugRqK7ezzfaQ5lawTm5 dKCHbPkWBCtBfAs4MCeTu9GERErzBkklP+tVn58BjdH+lP5Jx94DdJqhXjUgUV0IB6P+ xmkQ==; 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=1781176700; x=1781781500; 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=Mh3CrR8uJErXnmwq/Dm/RZtBbHI38eGqhEEK/Qh4lqU=; b=VMxFSvqXX+nMpZb4lqz1YLNCCaxfcrEyQe405dAx3hPIVUbz5WWAkBEGDLD7MOuKeB 2i7Uqzp9AKaL/fvx3CUfBU2WECx4LPY/6iF3uUl+V8wfgkMdEiqt2QAIRJra5jooUp8I cmY8ln2HN6HVzYpk8RSe62BK5eOsfvA53eb4Z2mhBcQ4/CPh7/ugjEXdO1tXhSB/UNUP U/cM7nEjvZz1SHkFrVUOH2W0/SBYbDwINPXI0uw8bbRi4al+ClxQoa31XI7UCRHg1kzn vvid7IfCuHhwg+LkRTyr2PNAm2zECF/RxIxUQjFhr6WjJ+ndtsy2QGAE4mrEPbyW3RpO uhDw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1781176700; x=1781781500; 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=Mh3CrR8uJErXnmwq/Dm/RZtBbHI38eGqhEEK/Qh4lqU=; b=iZvOVKEskdvSq5FjBmPS5fBSwvcOtS9Jj+rIdu3WaUQ/r9exoe6lkiUO8WEnUeheHm XOewCLDMF30VrhODilqHx7nngwbzx0JlLYtz5uxxBIiC1rQIoGG6i7XilaeftEfVVSP3 ydTxXGkeyWgexSfN/+dbQUvECHe1VI2G8Si3VgbL1zVMrpPs0WkNzOZoATTs+Z6ufBZC MXQwaUtWv0GleEd8ODiOm+O6PlL3JTkVhqYgvkXebGIkh6g50EmSj5tUq/pTJHI/yeyk kBAWQmgNCHm1EflIMqaCe6NvBdMUtXO13EabXmAVhud2J5nXxpTGXEVu15IJFktNezry qtNA== X-Forwarded-Encrypted: i=1; AFNElJ/eepUah2mu56+fKgBdUVIv+mR2H3RMNSF1ORY4M6eDPd+Yw3D+azlxhXF5+s40gKp+Kh713sF5J0fHteBU@lists.postgresql.org X-Gm-Message-State: AOJu0YyqPTUm0wUe4UJ5Yta3fV+Z5QySNNSeLy/+eQq+HbngQUG4ScKJ P4vO4WdTAL7C8HmAYw8tMR+HMN1Bo99tn6bOgJhMWdYAAm1nFIcm+ydUozDtcEo2Ng+R0JbZbsb NZboLobPwuCVcwE2MZja1xqTWw7wcpoQ= X-Gm-Gg: Acq92OFUKfcQ5/aBSvTLoS1Xh88E3tyd0uKepabl4445wg2zwSKtQ6M/70NtVW/zTN4 M/q4I9UWOb0q/9MX12SNANrCaPOUykiWyczk1ucpIOtSr4R311FsgJzTPD/Y9DWlr0w4T2PYhGL E8N4uHSAqR5Mnz5ft+9NB7waG4ZjPlnu5RG05RtECc7lZ6cjNNyyRCsDUR/otHzl6YJOlc3oOeF YZWZDCrmwQNC/7ZMXu4Ud4CHXPTBmC4Vf5fHEbXJ9dSyUucY9gRsgNXzC3paMfWq1S3Ry3t1mqt 68Se5i6AWPCh9BPR6VZG2lpuHUlMV4S2gxZm/G6b+1jsSBI0Og+ilLwb9z866V9WbgWeKjysqw1 N1jrZPvQyvNfbpPIFsmoIzycTbQyxC+undKhwwloSKzqC69ajEq0V X-Received: by 2002:a17:902:f542:b0:2c2:da54:8a73 with SMTP id d9443c01a7336-2c2f1eba1a7mr29844565ad.18.1781176700156; Thu, 11 Jun 2026 04:18:20 -0700 (PDT) MIME-Version: 1.0 References: In-Reply-To: From: Amit Kapila Date: Thu, 11 Jun 2026 16:48:08 +0530 X-Gm-Features: AVVi8Ce_OaW4-g1_9H2H0o3agqf2Cwaja84LHb0Ml2pUNWjibgm2yXBboRUG-_c Message-ID: Subject: Re: Fix race in ReplicationSlotRelease for ephemeral slots To: "Zhijie Hou (Fujitsu)" Cc: Xuneng Zhou , Fujii Masao , 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 On Thu, Jun 11, 2026 at 2:52=E2=80=AFPM Amit Kapila wrote: > > On Sat, Jun 6, 2026 at 3:05=E2=80=AFPM Zhijie Hou (Fujitsu) > wrote: > > > > On Friday, June 5, 2026 8:45 PM Xuneng Zhou wrot= e: > > > 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: > > > > > > > > /* 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 databa= se lock? > > > > > > 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. > > > > I recall condition (1) is considered acceptable, since the database loc= k is > > released immediately after re-verifying that the slot is no longer the = original > > 'synced' one anyway. Additionally, this race can only occur when replay= ing a > > DROP DATABASE, which is rare in practice. Since we only take a shared l= ock, it > > does not seem to cause real issues. > > > > It seems that (1) is talking about the access to local_slot->data.name > before we acquire database lock in local_sync_slot_required() whereas > your response doesn't seem to address that concern. If not, then how > exactly does the database lock protect what we are doing in > local_sync_slot_required()? > I re-analyzed this case and found the 'Before-drop' case is safe. In the gap between get_local_synced_slots() releasing ReplicationSlotControlLock and LockSharedObject, ReplicationSlotsDropDBSlots() can run and free a synced slot cell because the slotsync worker holds no database lock yet. The cell can then be reused by any user-created (non-synced) slot. It could lead to following risks which I think are already addressed due to recheck of sync flag. 1. Stale name read in local_sync_slot_required(): The reused cell holds a different name. local_sync_slot_required() might return false (drop needed). But then the in_use && synced spinlock check sees synced =3D false and skips the actual drop. The wrong decision is caught. 2. Wrong database OID read at line 551: The reused cell holds OID_B from the new slot. We lock OID_B, then at lines 563=E2=80=93565 we see sync= ed =3D false, skip the drop, and unlock OID_B at line 579. Since no drop occurred, the cell is still the same non-synced slot, so the lock and unlock see the same OID_B. Symmetric =E2=80=94 no lock leak. 3. Acquiring the wrong slot at line 575: Once the shared database lock is held at line 551, ReplicationSlotsDropDBSlots() is blocked from freeing the cell. The slotsync worker itself won't free a synced slot from any other code path while inside this function. So, this should not happen. Does this match your analysis? If so, After-drop case is still a risk, and for that, the patch proposed in email [1] seems to address it. [1] - https://www.postgresql.org/message-id/CABPTF7VyH1-W2xnDspECDEzFGQj%3D= WTFpZBCqKfM11OAZa6gQHQ%40mail.gmail.com --=20 With Regards, Amit Kapila.