From ec47e433103099bb6c992e678b7ed925637a70d1 Mon Sep 17 00:00:00 2001 From: Masahiko Sawada Date: Mon, 16 Dec 2024 10:11:16 -0800 Subject: [PATCH v2] radixtree: Fix crash when non-creator begins an iteration on shared tree. Previously, a radix tree can be created on shared memory to share among with other processes but processes who attached to the shared radix tree could not begin the iteration since they don't create the iteration context in RT_ATTACH(). It caused a server crash due to null-pointer-dereference when a non-creator begins an iteration on shared radix tree. To fix it, this commit changes the iter_context to be created in RT_BEGIN_ITERATE() in both shared and local cases. Backpatch to v17, where radixtree.h was introduced. Reviewed-by: John Naylor Discussion: https://postgr.es/m/CAD21AoBB2U47V%3DF%2BwQRB1bERov_of5%3DBOZGaybjaV8FLQyqG3Q%40mail.gmail.com Backpatch-through: 17 --- src/include/lib/radixtree.h | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/src/include/lib/radixtree.h b/src/include/lib/radixtree.h index 1301f3fee44..2b866e6d51c 100644 --- a/src/include/lib/radixtree.h +++ b/src/include/lib/radixtree.h @@ -1836,14 +1836,6 @@ RT_CREATE(MemoryContext ctx) tree = (RT_RADIX_TREE *) palloc0(sizeof(RT_RADIX_TREE)); tree->context = ctx; - /* - * Separate context for iteration in case the tree context doesn't support - * pfree - */ - tree->iter_context = AllocSetContextCreate(ctx, - RT_STR(RT_PREFIX) "_radix_tree iter context", - ALLOCSET_SMALL_SIZES); - #ifdef RT_SHMEM tree->dsa = dsa; dp = dsa_allocate0(dsa, sizeof(RT_RADIX_TREE_CONTROL)); @@ -1895,6 +1887,10 @@ RT_CREATE(MemoryContext ctx) } #ifdef RT_SHMEM +/* + * Attach to an existing shared radix tree using a handle. The returned object + * is allocated in backend-local memory using the current memory context. + */ RT_SCOPE RT_RADIX_TREE * RT_ATTACH(dsa_area *dsa, RT_HANDLE handle) { @@ -1902,6 +1898,7 @@ RT_ATTACH(dsa_area *dsa, RT_HANDLE handle) dsa_pointer control; tree = (RT_RADIX_TREE *) palloc0(sizeof(RT_RADIX_TREE)); + tree->context = CurrentMemoryContext; /* Find the control object in shared memory */ control = handle; @@ -1913,10 +1910,18 @@ RT_ATTACH(dsa_area *dsa, RT_HANDLE handle) return tree; } +/* + * Detach from a shared radix tree. This frees backend-local resource associated + * with the radix tree, but the radix tree will continue to exist until it is + * either explicitly destroyed (by a backend that is still attached to it), or + * the area that backs it is returned to the operating system. + */ RT_SCOPE void RT_DETACH(RT_RADIX_TREE * tree) { Assert(tree->ctl->magic == RT_RADIX_TREE_MAGIC); + if (tree->iter_context) + MemoryContextDelete(tree->iter_context); pfree(tree); } @@ -2086,6 +2091,15 @@ RT_BEGIN_ITERATE(RT_RADIX_TREE * tree) RT_ITER *iter; RT_CHILD_PTR root; + /* + * Create a separate context for iteration in case the context doesn't + * support pfree, if not created yet. + */ + if (tree->iter_context == NULL) + tree->iter_context = AllocSetContextCreate(tree->context, + RT_STR(RT_PREFIX) "_radix_tree iter context", + ALLOCSET_SMALL_SIZES); + iter = (RT_ITER *) MemoryContextAllocZero(tree->iter_context, sizeof(RT_ITER)); iter->tree = tree; -- 2.43.5