From b9efea3ccbeb7913456de239a423f23188bcf26e Mon Sep 17 00:00:00 2001 From: Maksim Melnikov Date: Mon, 29 Jun 2026 12:55:41 +0300 Subject: [PATCH 1/2] Fix segfault when postgres was build with -DRELCACHE_FORCE_RELEASE. rum is using a pointer to relcache entry, that has been already freed --- src/rum_debug_funcs.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/rum_debug_funcs.c b/src/rum_debug_funcs.c index b138ef00de..f91d346e11 100644 --- a/src/rum_debug_funcs.c +++ b/src/rum_debug_funcs.c @@ -19,6 +19,7 @@ #include "miscadmin.h" #include "storage/bufmgr.h" #include "storage/bufpage.h" +#include "storage/lmgr.h" #include "storage/lockdefs.h" #include "utils/array.h" #include "utils/builtins.h" @@ -929,20 +930,17 @@ find_attnum_posting_tree_key(RumPageItemsState piState) * piState and makes the necessary checks. */ static bool -prepare_scan(text *relName, uint32 blkNo, +prepare_scan(Relation rel, uint32 blkNo, RumPageItemsState * piState, FuncCallContext *srfFctx, pageTypeFlags pageType) { - Relation rel; /* needed to initialize the RumState structure */ - Page page; /* the page to be scanned */ RumPageOpaque opaq; /* data from the opaque area of the page */ int resSize; - /* Getting rel by name and page by number */ - rel = get_rel_from_name(relName); + /* Getting page by number */ page = get_rel_page(rel, blkNo); /* The page cannot be new */ @@ -962,8 +960,6 @@ prepare_scan(text *relName, uint32 blkNo, (*piState)->rumState = palloc(sizeof(RumState)); initRumState((*piState)->rumState, rel); - relation_close(rel, AccessShareLock); - /* Writing the page and page type into a long-lived structure */ (*piState)->srfFctx = srfFctx; (*piState)->page = page; @@ -1551,6 +1547,7 @@ rum_page_items_info(PG_FUNCTION_ARGS) text *relName = PG_GETARG_TEXT_PP(0); uint32 blkNo = PG_GETARG_UINT32(1); pageTypeFlags pageType = PG_GETARG_UINT32(2); + Relation rel; /* needed to initialize the RumState structure */ int counter; @@ -1573,6 +1570,9 @@ rum_page_items_info(PG_FUNCTION_ARGS) TupleDesc tupDesc; /* description of the result tuple */ MemoryContext oldMctx; /* the old function memory context */ + /* Getting rel by name */ + rel = get_rel_from_name(relName); + /* * Initializing the FuncCallContext structure and switching the memory * context to the one needed for structures that must be saved during @@ -1582,9 +1582,10 @@ rum_page_items_info(PG_FUNCTION_ARGS) oldMctx = MemoryContextSwitchTo(fctx->multi_call_memory_ctx); /* Before scanning the page, you need to prepare piState */ - if (!prepare_scan(relName, blkNo, &piState, fctx, pageType)) + if (!prepare_scan(rel, blkNo, &piState, fctx, pageType)) { MemoryContextSwitchTo(oldMctx); + relation_close(rel, AccessShareLock); PG_RETURN_NULL(); } @@ -1614,6 +1615,13 @@ rum_page_items_info(PG_FUNCTION_ARGS) /* In the current call, we are reading data from the previous one */ piState = fctx->user_fctx; + /* + * Need set rel if it is not first call. Anyway, relation has been already + * locked here. + */ + rel = piState->rumState->index; + Assert(CheckRelationLockedByMe(rel, AccessShareLock, false)); + /* The counter is defined differently on different pages */ if (RumIsDataPage(piState)) counter = fctx->call_cntr; @@ -1645,6 +1653,8 @@ rum_page_items_info(PG_FUNCTION_ARGS) SRF_RETURN_NEXT(fctx, piState->result); } + relation_close(rel, AccessShareLock); + /* Completing the function */ SRF_RETURN_DONE(fctx); } From 9989c56c5f23ef07afb5512f0dc981d1f86f7e7f Mon Sep 17 00:00:00 2001 From: Maksim Melnikov Date: Fri, 7 Aug 2026 14:53:10 +0300 Subject: [PATCH 2/2] Cosmetics fixes, should be squashed with b9efea3 --- src/rum_debug_funcs.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/rum_debug_funcs.c b/src/rum_debug_funcs.c index f91d346e11..172573f368 100644 --- a/src/rum_debug_funcs.c +++ b/src/rum_debug_funcs.c @@ -270,20 +270,17 @@ typedef struct RumPageItemsStateData typedef RumPageItemsStateData *RumPageItemsState; /* - * This function and get_rel_raw_page() are derived - * from the separation of the get_raw_page_internal() - * function, which was copied from the pageinspect code. - * It is needed in order to call the initRumState() - * function if necessary. + * Open the relation named by relname, acquire specified type of lock, + * Caller must close rel when done with it. */ static Relation -get_rel_from_name(text *relName) +get_rel_from_relname(text *relName, LOCKMODE lockmode) { RangeVar *relrv; Relation rel; relrv = makeRangeVarFromNameList(textToQualifiedNameList(relName)); - rel = relation_openrv(relrv, AccessShareLock); + rel = relation_openrv(relrv, lockmode); #if PG_VERSION_NUM >= 150000 if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind)) @@ -1379,8 +1376,8 @@ rum_metapage_info(PG_FUNCTION_ARGS) /* Only the superuser can use this */ check_superuser(); - /* Getting rel by name and page by number */ - rel = get_rel_from_name(relName); + /* Open target relation by name and getting page by number */ + rel = get_rel_from_relname(relName, AccessShareLock); page = get_rel_page(rel, blkNo); relation_close(rel, AccessShareLock); @@ -1462,8 +1459,8 @@ rum_page_opaque_info(PG_FUNCTION_ARGS) /* Only the superuser can use this */ check_superuser(); - /* Getting rel by name and raw page by number */ - rel = get_rel_from_name(relName); + /* Open target relation by name and getting raw page by number */ + rel = get_rel_from_relname(relName, AccessShareLock); page = get_rel_page(rel, blkNo); relation_close(rel, AccessShareLock); @@ -1570,8 +1567,8 @@ rum_page_items_info(PG_FUNCTION_ARGS) TupleDesc tupDesc; /* description of the result tuple */ MemoryContext oldMctx; /* the old function memory context */ - /* Getting rel by name */ - rel = get_rel_from_name(relName); + /* open target relation */ + rel = get_rel_from_relname(relName, AccessShareLock); /* * Initializing the FuncCallContext structure and switching the memory