postgres.git / summary / log / commit / refs

commit    dda622edcdba673e90d7b2cafe747ab78249368b
Author:   Tom Lane <tgl@sss.pgh.pa.us>
Date:     Sun Aug 02 20:49:18 2026 +0000

    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 <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 | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/backend/utils/cache/ts_cache.c b/src/backend/utils/cache/ts_cache.c index 384107b6bac..3885c345975 100644 --- a/src/backend/utils/cache/ts_cache.c +++ b/src/backend/utils/cache/ts_cache.c @@ -279,37 +279,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, (void *) &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)) [parent: cfc720ef4b1d]