]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Tighten up TS dictionary cache entry creation.
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 2 Aug 2026 20:49:17 +0000 (16:49 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 2 Aug 2026 20:49:17 +0000 (16:49 -0400)
In the not-too-likely scenario where we successfully created a hash
table entry for a TS dictionary, but then failed to make a small
memory context for it, we left the hash entry in existence but with
a garbage value for dictCtx.  This confused the code the next time
through, leading to a crash.  Rearrange things so that we leave
the hash entry in a well-defined state with dictCtx == NULL, and
then the next try knows it still needs to make a memory context.

Reported-by: Alexander Lakhin <exclusion@gmail.com>
Author: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/0f3ddeb5-0dbd-479c-9d0e-ae254758e624@gmail.com
Backpatch-through: 14

src/backend/utils/cache/ts_cache.c

index 9e29f1386b0252ffd1c20116697d704b259453ac..1cec9a1f9a6df6f52045de629c9b6c941196a778 100644 (file)
@@ -280,37 +280,50 @@ lookup_ts_dictionary_cache(Oid dictId)
                        elog(ERROR, "text search template %u has no lexize method",
                                 template->tmpllexize);
 
+               /*
+                * OK, create or clear out the hashtable entry
+                */
                if (entry == NULL)
                {
                        bool            found;
 
-                       /* Now make the cache entry */
                        entry = (TSDictionaryCacheEntry *)
                                hash_search(TSDictionaryCacheHash,
                                                        &dictId,
                                                        HASH_ENTER, &found);
                        Assert(!found);         /* it wasn't there a moment ago */
 
-                       /* Create private memory context the first time through */
+                       memset(entry, 0, sizeof(TSDictionaryCacheEntry));
+                       entry->dictId = dictId;
+                       saveCtx = NULL;
+               }
+               else
+               {
+                       saveCtx = entry->dictCtx;       /* could be NULL if we failed before */
+                       memset(entry, 0, sizeof(TSDictionaryCacheEntry));
+                       entry->dictId = dictId;
+                       entry->dictCtx = saveCtx;
+               }
+
+               /*
+                * Create or clear the entry's private memory context
+                */
+               if (saveCtx == NULL)
+               {
                        saveCtx = AllocSetContextCreate(CacheMemoryContext,
                                                                                        "TS dictionary",
                                                                                        ALLOCSET_SMALL_SIZES);
+                       entry->dictCtx = saveCtx;
                        MemoryContextCopyAndSetIdentifier(saveCtx, NameStr(dict->dictname));
                }
                else
                {
-                       /* Clear the existing entry's private context */
-                       saveCtx = entry->dictCtx;
                        /* Don't let context's ident pointer dangle while we reset it */
                        MemoryContextSetIdentifier(saveCtx, NULL);
                        MemoryContextReset(saveCtx);
                        MemoryContextCopyAndSetIdentifier(saveCtx, NameStr(dict->dictname));
                }
 
-               MemSet(entry, 0, sizeof(TSDictionaryCacheEntry));
-               entry->dictId = dictId;
-               entry->dictCtx = saveCtx;
-
                entry->lexizeOid = template->tmpllexize;
 
                if (OidIsValid(template->tmplinit))