| From: | Ayush Tiwari <ayushtiwari(dot)slg01(at)gmail(dot)com> |
|---|---|
| To: | Amit Langote <amitlangote09(at)gmail(dot)com> |
| Cc: | PostgreSQL Hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org> |
| Subject: | Re: InvalidateConstraintCacheCallBack() can free fpmeta while it's in use |
| Date: | 2026-08-11 09:08:27 |
| Message-ID: | CAJTYsWWAQx4OvqA4N5c=njd-GKoce4XO=4-ruvDa8Wd54rVcXg@mail.gmail.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
Hi,
On Fri, 7 Aug 2026 at 18:39, Amit Langote <amitlangote09(at)gmail(dot)com> wrote:
> On Thu, Aug 6, 2026 at 11:50 PM Amit Langote <amitlangote09(at)gmail(dot)com>
> wrote:
> >
> > Hi,
> >
> > $SUBJECT was reported to me off-list.
>
> Patches attached.
>
Thanks for the patches!
> 0001 is what I described upthread. InvalidateConstraintCacheCallBack()
> unlinks the metadata from the cache entry rather than freeing it, so
> the next check rebuilds it exactly as it does today, and the detached
> object is chained onto a list that AtEOXact_RI() releases, at which
> point no RI check can be on the stack. The call sites that test
> riinfo->fpmeta == NULL are unchanged.
>
> 0002 is what was 0004 in the series I last posted at [1], and fixes a
> separate leak in the same struct. ri_populate_fastpath_metadata()
> copies the cast and equality FmgrInfos with fn_mcxt set to
> TopMemoryContext, and fn_mcxt is scratch space for the called
> function: record_eq(), and the record I/O functions generally,
> allocate their per-call cache there and keep a pointer to it in
> fn_extra. That scratch space outlives the metadata, so any cached data
> is orphaned each time the metadata is discarded. 0002 gives the
> FmgrInfos a context of their own and deletes it alongside the struct
> in the AtEOXact_RI() cleanup.
>
> 0002 must follow 0001 because there's no safe place to delete the
> context until 0001 adds the deferred release. In the callback it would
> be a second use-after-free, this time in memory the called function
> owns rather than memory we do: an in-flight record_eq() has fn_extra
> pointing into the context and fn_mcxt at the context itself, so it
> would read back freed state or palloc into a deleted context.
>
> Ayush Tiwari reviewed 0002 at [1], and while doing so, independently
> raised the same lifetime problem this thread is about and 0001 is
> meant to fix.
>
> I've added open items for both, noting that the second must be
> committed with / after the first.
>
> [1]
> https://www.postgresql.org/message-id/CA%2BHiwqHHK2D69%2BQqAom%2Bth1kjZGK-0dYnrZujkEGFWpX_ZtxqQ%40mail.gmail.com
I tried the patches and the overall deferred-free approach looks sensible to
me. One corner case made me wonder if `fpmeta` also needs to be latched for
the whole multi-column batch flush.
`ri_FastPathFlushLoop()` calls `build_index_scankeys()` for each row, and
that
function reads `riinfo->fpmeta` again. In a small test where the first
row's
cast renames the FK constraint, the invalidation clears that field and the
second row reaches `Assert(fpmeta)`. I may be missing another invariant
here,
but passing a pointer latched at the start of the flush seems to avoid it,
much
like the array path already does.
Apart from that, the commit/abort/prepare cleanup and the `fn_mcxt`
ownership
looked reasonable in my testing.
Regards,
Ayush
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Zsolt Parragi | 2026-08-11 09:08:31 | Re: Unlogged materialized views |
| Previous Message | vignesh C | 2026-08-11 08:57:53 | Re: Support EXCEPT for TABLES IN SCHEMA publications |