Give RI fast-path cached FmgrInfos their own memory context ri_populate_fastpath_metadata() copies the cast and equality FmgrInfos into the cached FastPathMeta with fn_mcxt set to TopMemoryContext, the context active at the copy. 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.
Because that scratch is in TopMemoryContext, it outlives the metadata. When the metadata is discarded on invalidation, whatever the cast and equality functions cached is left behind, with nothing pointing at it. Each subsequent repopulation allocates afresh, so a session that repeatedly invalidates a foreign key constraint grows TopMemoryContext without bound. Give the metadata its own context for the FmgrInfos' fn_mcxt and delete it along with the metadata, so the cached scratch is freed with the FmgrInfos that point at it. Since the preceding commit defers release of the metadata to AtEOXact_RI(), the context is deleted there rather than in InvalidateConstraintCacheCallBack(). The context deliberately is not reset while the metadata is in use. fn_extra points into fn_mcxt, so resetting it would leave those pointers dangling; the next call would find fn_extra non-NULL and read freed memory. fmgr_info_copy() zeroing fn_extra in the copy is the same invariant seen from the other side. Nothing accumulates in the context during use in any case: record_eq() and friends allocate only when fn_extra is NULL and reuse the cache afterwards. Reported-by: Noah Misch <[email protected]> Reviewed-by: Ayush Tiwari <[email protected]> Discussion: https://postgr.es/m/[email protected] Discussion: https://postgr.es/m/CA+HiwqFFB6vzx8v3t2=rbnyyxmistlf5kkjfqzj81nadfyl...@mail.gmail.com Backpatch-through: 19 Branch ------ master Details ------- https://git.postgresql.org/pg/commitdiff/590b8e89a53a4637b07cf5f4ccb290d4c29ec3b7 Modified Files -------------- src/backend/utils/adt/ri_triggers.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-)
