From e73e0196d30198e4579656881497f057788bb53d Mon Sep 17 00:00:00 2001 From: Amit Langote Date: Tue, 6 Oct 2026 08:59:48 +0900 Subject: [PATCH] Fix possible crash when RI fast-path metadata is invalidated mid-check ri_FastPathCheck() read riinfo->fpmeta again after ri_CheckFunctionPermissions(), which looks up catalog entries and so can process invalidation messages. If one of them reaches InvalidateConstraintCacheCallBack() for the constraint, as a pg_amop change or a cache reset would, the callback detaches the metadata and sets riinfo->fpmeta to NULL, which build_index_scankeys() then dereferences. The callback already defers freeing detached metadata until AtEOXact_RI(), and its comment assumes callers keep their own pointer to it, so use a local pointer instead of riinfo->fpmeta. There is no test, as hitting this needs an invalidation to arrive during those catalog lookups. Discussion: https://postgr.es/m/CA+HiwqFaipkMsZ8XP-9sMk21h0Q7rih=NpJQXsBAaD39VtnrOA@mail.gmail.com --- src/backend/utils/adt/ri_triggers.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c index 0bcb0f9b3cf..56ca5c648e7 100644 --- a/src/backend/utils/adt/ri_triggers.c +++ b/src/backend/utils/adt/ri_triggers.c @@ -2783,6 +2783,7 @@ ri_FastPathCheck(RI_ConstraintInfo *riinfo, Oid saved_userid; int saved_sec_context; Snapshot snapshot; + FastPathMeta *fpmeta; INJECTION_POINT("ri-before-pk-lock", NULL); @@ -2854,11 +2855,19 @@ ri_FastPathCheck(RI_ConstraintInfo *riinfo, riinfo = ri_LoadConstraintInfo(riinfo->constraint_id); ri_populate_fastpath_metadata(riinfo, fk_rel, idx_rel); } - Assert(riinfo->fpmeta); - ri_CheckFunctionPermissions(riinfo, riinfo->fpmeta); + + /* + * Use our own pointer to the metadata from here on. The permission + * checks below look up catalog entries and so can process invalidation + * messages, which detach riinfo->fpmeta (see + * InvalidateConstraintCacheCallBack()); the detached object stays valid + * until AtEOXact_RI(). + */ + fpmeta = riinfo->fpmeta; + Assert(fpmeta); + ri_CheckFunctionPermissions(riinfo, fpmeta); ri_ExtractValues(fk_rel, newslot, riinfo, false, pk_vals, pk_nulls); - build_index_scankeys(riinfo, riinfo->fpmeta, idx_rel, pk_vals, pk_nulls, - skey); + build_index_scankeys(riinfo, fpmeta, idx_rel, pk_vals, pk_nulls, skey); found = ri_FastPathProbeOne(pk_rel, idx_rel, scandesc, slot, snapshot, riinfo, skey, riinfo->nkeys); SetUserIdAndSecContext(saved_userid, saved_sec_context);