From: Tom Lane Date: Sun, 2 Aug 2026 20:49:17 +0000 (-0400) Subject: Tighten up TS dictionary cache entry creation. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;ds=inline;p=thirdparty%2Fpostgresql.git Tighten up TS dictionary cache entry creation. 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 Author: Tom Lane Discussion: https://postgr.es/m/0f3ddeb5-0dbd-479c-9d0e-ae254758e624@gmail.com Backpatch-through: 14 --- diff --git a/src/backend/utils/cache/ts_cache.c b/src/backend/utils/cache/ts_cache.c index 9e29f1386b0..1cec9a1f9a6 100644 --- a/src/backend/utils/cache/ts_cache.c +++ b/src/backend/utils/cache/ts_cache.c @@ -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))