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 1wXIMt-003BAr-2F for pgsql-hackers@arkaria.postgresql.org; Wed, 10 Jun 2026 12:49:15 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wXIMs-00BP6K-1w for pgsql-hackers@arkaria.postgresql.org; Wed, 10 Jun 2026 12:49:14 +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 1wXIMs-00BP60-0c for pgsql-hackers@lists.postgresql.org; Wed, 10 Jun 2026 12:49:14 +0000 Received: from mail-yw1-x112f.google.com ([2607:f8b0:4864:20::112f]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1wXIMq-000000020ef-1BIx for pgsql-hackers@postgresql.org; Wed, 10 Jun 2026 12:49:13 +0000 Received: by mail-yw1-x112f.google.com with SMTP id 00721157ae682-7e8833c99fcso74656897b3.3 for ; Wed, 10 Jun 2026 05:49:12 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1781095751; cv=none; d=google.com; s=arc-20240605; b=CBkI2Wkt8F20JDV36UTD/W13zq1YoTGi5Pvsk+N/iawIgk8tUYYyMqNIohmj+hLZJp RdjmqZh4fOCtXRM71RXdzvGLqIHHQbpsQssQ9k6mULQEpUsk+BiTJpA0Mq4FK7da0U4j eOD/Xa4XzpX5EjzetCbybC7yDMDo+MvwmeBI7KX155k05NXqhg8jKc4VBzlWlvSl9ojo xmxqzlmhdPgbkDgp8zgrVEuNvy7hHdJsFXOGP2hZU3mo4j03VZQXTtsa5anx09bzgVg/ +nXp73CBVhSLh+YKrPkkOMHug8Emh2qnVC5I68dso5BHi8tPjKQtrjScULng5bM+D5kO 4kCQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:dkim-signature; bh=LwhxG2XMLNcuH6zkw1gJc/TQC2yD74uyVW4CtiseemQ=; fh=+TloApSW1UW3a6Xn5UwbNQOWgAjEqFkHHwMklfDOAnY=; b=J9GaYAny4ma/LCy9z7bB3jbkCoZWH5SLyJkBTAxopaEWQ4CfP55uOPXTiVVeJCIMev 5ordPBqo/fLXJ6CsfmjdtcNMPTqTVoGzvFwf6o1a1RbRninl5XheMWhKrOQ+pAO247aT /aO1ksXRpgZ5FxYMXRlXGKIYY0RShc/kaXqbJl7O0K+3UxE9F7pZNJ302pq6zwE93xge yyojuqyeGJJBsYOvAWRuoquVHg1fqWxq7scEnLymHIqlZex+m1G3jTwoI6Mwi1KlTQno 5wrWIvJpzUcBgILVwF8ytPnCfYsJccFhZ6KVfkQAhuF98/dYyKk2zNlMYizOvi54voZ6 l0vA==; darn=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=1781095751; x=1781700551; darn=postgresql.org; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=LwhxG2XMLNcuH6zkw1gJc/TQC2yD74uyVW4CtiseemQ=; b=VQydw0dlFnX2jqNE+xH3AwiPo7sEsX8RDvUgpzFO6XGMXcIygCV9446SmuCUfZzajx k4snl62y7EglYo21jpgwZ5ndt12BRTIVz8Hrpv9CwshRtO+kqkDEXzxOA+h+Es01Ieuy W5nqjYCILV1JSJRBsZJ5+EV6duxNuP2wz/PwzPJPeuurvwIyl3zkLc9qB7EkfIeM9s8b mq0dABtlKa//i4SZXnrJ8eNVH9qmMpqBpJO19/i2ptKzPlyyI4w/3d4ut6/1YXrGeCuK DvX50zJR0khqoQ9crSk1De6m2fEjFVlsSx2EUcH80ZFlwg8Mm2xLfpNLzhXhjxfKYHJf qxSw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1781095751; x=1781700551; h=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=LwhxG2XMLNcuH6zkw1gJc/TQC2yD74uyVW4CtiseemQ=; b=DU+K0gud7I49PbuXwdIRpCvGn91TLQymv/OmgWiBl2RswIagHIHCNlW7aemQDyIrv9 oTHQlYXn7hYyMdZxvnAuKTo18uGOMr/SYQHZQmwpkKF96Awzg++DUKMtw6U12+KnTTJz s7K5AhuAAQpbKtmEEfEqKYb6tcE50OCeqaNQaWdny8R/9SLq2YbB77tRppSUVbAUw3Qj n00SiAAJOt01m+vgTQK4zY42UFqQcKOoZVX2trDqU9GY5zeWC8vKX9Li1NnrbxiOFaZ+ R5W9FRDUX3z8i5r4v5lASUUcg4qOdc5APztC/yGiTVZFjGdNW1CtG21KrafTJXDdeATk jTmg== X-Forwarded-Encrypted: i=1; AFNElJ9QxCTU/F+KDEQw6UlBpd5JvfCYe2hky7+3Mu9ay1q1elwsrleRPC/yxaCnDZ4bVlYsUBz5mowZ+YOK46n9@postgresql.org X-Gm-Message-State: AOJu0YzYZKLc8tlOdn/um7WOFIY8lLt/gS3SvV5qZ15RqnG5lu/vRr+D pBckEJMOkmphQb2CpcO1wf7U1IkiiF3d5wqz//jqZafuVUP0bcHXHRZ8HCWIbnaIw0m0Sbmvz5L VonzWuPCXExPPpQDYiZQTYURgUCqvmPk= X-Gm-Gg: Acq92OFrb+WDYjCWeV7+SzlIFcW2tXzkAZvPLYOKcRCOH5KqayHqdz8g6vnjzn7Vr/I 56H/pMiLNe5jmMFnNJF7USK9+L8RH2Y1sK9CSVUMp4fVO75/WVEIuXgirAUPDiq9wh1m2HjWEVd fXHTmFYBSq3bVl/7gifdTOd51PH0pkglNelN7MyfBpsEYU5JjtoKhQeLJ3i5Eria0MktWtj3NS4 XPur3HG8+d+OR9ppUe/SqqLPM2E8MTjbG5kxdfkJsiBmVpWYkVRGTanE6DUchMrLJ+Je2mxW9xn ksd9BiDusH5xJBdKyrAcU+5mghPjIUFb5W3qgpVo0KEo0qtsr2M7fd8B8NMx X-Received: by 2002:a05:690c:4588:b0:7d1:cd93:c8e9 with SMTP id 00721157ae682-7ed0d5bc939mr249178147b3.13.1781095751524; Wed, 10 Jun 2026 05:49:11 -0700 (PDT) MIME-Version: 1.0 References: In-Reply-To: From: Ayush Tiwari Date: Wed, 10 Jun 2026 18:18:59 +0530 X-Gm-Features: AVVi8CeL69602CjEMh-h6gWqH0PQSiZD-Ck9fK2Pj87svypy2JZ4nxSC0FKZTgM Message-ID: Subject: Re: PG19 FK fast path: OOB write and missed FK checks during batched To: Amit Langote Cc: Nikolay Samokhvalov , pgsql-hackers mailing list , Andrey Borodin , Kirk Wolak Content-Type: multipart/alternative; boundary="00000000000094a5c60653e5ab21" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --00000000000094a5c60653e5ab21 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Hi, On Wed, 10 Jun 2026 at 17:47, Amit Langote wrote: > Hi Ayush, > > Thanks for the review. > > On Wed, Jun 10, 2026 at 7:09=E2=80=AFPM Ayush Tiwari > wrote: > > On Wed, 10 Jun 2026 at 14:02, Amit Langote > wrote > >> Thanks for checking. I will review them a bit more closely before > >> committing by Friday. Other reviews are welcome. > > > > Thanks for the patch! > > > > I read through v1-0001 and v1-0002 and tried them locally. I had a > couple of > > things I wanted to ask about. > > > > 1. The per-entry "flushing" flag and test coverage. If I'm reading the > two > > patches together correctly, with both applied the 64-row re-entry test > in 0001 > > reaches the flush through ri_FastPathEndBatch(), where 0002's cache-wid= e > > ri_fastpath_flushing guard already routes the re-entrant check to the > per-row > > path before it gets back into ri_FastPathBatchAdd(). Does that mean th= e > > per-entry flag from 0001 isn't really exercised by that test once 0002 > is in? > > As far as I can tell you'd need the flush to fire from > ri_FastPathBatchAdd() > > itself (a 65th row) to reach it. I tried a 65-row variant (same FK, > re-entrant > > DML from the cast during the full-batch flush), including a case where > the > > re-entrant row was an orphan, and it seemed to do the right thing; the > > per-row fallback still raised the violation. Would it be worth > switching the > > test to 65 rows, or adding that variant, so the per-entry guard is > covered too? > > Or am I missing a path where the committed test already hits it? > > You're right. With 0002 applied, the 64-row test reaches the flush > through ri_FastPathEndBatch(), where the cache-wide > ri_fastpath_flushing guard catches the re-entry before it returns to > ri_FastPathBatchAdd(), so the per-entry flag is no longer exercised by > that test. To hit the per-entry flag the flush has to fire from > ri_FastPathBatchAdd() itself, which the 64-row case no longer does > once the add and flush are reordered. > > Rather than bump the test to 65 rows, I'd prefer to keep the flush > firing from ri_FastPathBatchAdd() at 64 by not reordering the add and > flush, and prevent the OOB write by bounds-checking the write instead, > as done in the attached updated 0001. A re-entrant add then can't > overrun the array regardless of the flag, the per-entry flushing guard > still routes the re-entry to the per-row path, and a 64-row statement > flushes from ri_FastPathBatchAdd() on the 64th row, so the existing > test exercises the per-entry guard. > Makes sense, it is better. > 2. Resetting ri_fastpath_flushing. I noticed it's cleared only in the > > PG_FINALLY of ri_FastPathEndBatch(), which does seem to cover the cases > I could > > think of. Since ri_FastPathXactCallback already NULLs ri_fastpath_cach= e > and > > clears ri_fastpath_callback_registered at transaction end, I wondered > whether > > it might be worth clearing ri_fastpath_flushing there too, just as chea= p > > insurance against some future path that leaves it set across transactio= ns > > though maybe that's unnecessary given the PG_FINALLY. > > Agreed, it's cheap and matches the existing resets there, so I've > added it to ri_FastPathXactCallback() in v2-0002. > > > Other than the above queries, the patch looks good to me. > > Updated patches attached. > Thanks for the updated patches! Both patches, lgtm. Regards, Ayush --00000000000094a5c60653e5ab21 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Hi,

On Wed, 10 Jun 2= 026 at 17:47, Amit Langote <a= mitlangote09@gmail.com> wrote:
Hi Ayush,

Thanks for the review.

On Wed, Jun 10, 2026 at 7:09=E2=80=AFPM Ayush Tiwari
<ayusht= iwari.slg01@gmail.com> wrote:
> On Wed, 10 Jun 2026 at 14:02, Amit Langote <amitlangote09@gmail.com> wrote=
>> Thanks for checking.=C2=A0 I will review them a bit more closely b= efore
>> committing by Friday.=C2=A0 Other reviews are welcome.
>
> Thanks for the patch!
>
> I read through v1-0001 and v1-0002 and tried them locally. I had a cou= ple of
> things I wanted to ask about.
>
> 1. The per-entry "flushing" flag and test coverage.=C2=A0 If= I'm reading the two
> patches together correctly, with both applied the 64-row re-entry test= in 0001
> reaches the flush through ri_FastPathEndBatch(), where 0002's cach= e-wide
> ri_fastpath_flushing guard already routes the re-entrant check to the = per-row
> path before it gets back into ri_FastPathBatchAdd().=C2=A0 Does that m= ean the
> per-entry flag from 0001 isn't really exercised by that test once = 0002 is in?
> As far as I can tell you'd need the flush to fire from ri_FastPath= BatchAdd()
> itself (a 65th row) to reach it.=C2=A0 I tried a 65-row variant (same = FK, re-entrant
> DML from the cast during the full-batch flush), including a case where= the
> re-entrant row was an orphan, and it seemed to do the right thing; the=
> per-row fallback still raised the violation.=C2=A0 Would it be worth s= witching the
> test to 65 rows, or adding that variant, so the per-entry guard is cov= ered too?
> Or am I missing a path where the committed test already hits it?

You're right. With 0002 applied, the 64-row test reaches the flush
through ri_FastPathEndBatch(), where the cache-wide
ri_fastpath_flushing guard catches the re-entry before it returns to
ri_FastPathBatchAdd(), so the per-entry flag is no longer exercised by
that test. To hit the per-entry flag the flush has to fire from
ri_FastPathBatchAdd() itself, which the 64-row case no longer does
once the add and flush are reordered.

Rather than bump the test to 65 rows, I'd prefer to keep the flush
firing from ri_FastPathBatchAdd() at 64 by not reordering the add and
flush, and prevent the OOB write by bounds-checking the write instead,
as done in the attached updated 0001. A re-entrant add then can't
overrun the array regardless of the flag, the per-entry flushing guard
still routes the re-entry to the per-row path, and a 64-row statement
flushes from ri_FastPathBatchAdd() on the 64th row, so the existing
test exercises the per-entry guard.

Mak= es sense, it is better.

> 2. Resetting ri_fastpath_flushing.=C2=A0 I noticed it's cleared on= ly in the
> PG_FINALLY of ri_FastPathEndBatch(), which does seem to cover the case= s I could
> think of.=C2=A0 Since ri_FastPathXactCallback already NULLs ri_fastpat= h_cache and
> clears ri_fastpath_callback_registered at transaction end, I wondered = whether
> it might be worth clearing ri_fastpath_flushing there too, just as che= ap
> insurance against some future path that leaves it set across transacti= ons
> though maybe that's unnecessary given the PG_FINALLY.

Agreed, it's cheap and matches the existing resets there, so I've added it to ri_FastPathXactCallback() in v2-0002.

> Other than the above queries, the patch looks good to me.

Updated patches attached.

Thanks for the updated p= atches!

Both patches, lgtm.

Regards,
Ayush=C2=A0
--00000000000094a5c60653e5ab21--