1
0
mirror of https://github.com/postgres/postgres.git synced 2026-10-23 13:29:09 +03:00

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
This commit is contained in:
Amit Langote
2026-10-06 08:59:48 +09:00
parent 8b29b8da78
commit e73e0196d3

View File

@@ -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);