postgres.git / summary / log / commit / refs

commit    5b1621d2fb736bcec58114faf035e6ad9bd64a1d
Author:   Jeff Davis <jdavis@postgresql.org>
Date:     Fri Jul 09 21:15:48 2021 +0000
First released in: 15.0, 11.13, 12.8, 13.4, 14.0

    Fix assign_record_type_typmod().
    
    If an error occurred in the wrong place, it was possible to leave an
    unintialized entry in the hash table, leading to a crash. Fixed.
    
    Also, be more careful about the order of operations so that an
    allocation error doesn't leak memory in CacheMemoryContext or
    unnecessarily advance NextRecordTypmod.
    
    Backpatch through version 11. Earlier versions (prior to 35ea75632a5)
    do not exhibit the problem, because an uninitialized hash entry
    contains a valid empty list.
    
    Author: Sait Talha Nisanci <Sait.Nisanci@microsoft.com>
    Reviewed-by: Andres Freund
    Discussion: https://postgr.es/m/HE1PR8303MB009069D476225B9A9E194B8891779@HE1PR8303MB0090.EURPRD83.prod.outlook.com
    Backpatch-through: 11


src/backend/utils/cache/typcache.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/backend/utils/cache/typcache.c b/src/backend/utils/cache/typcache.c index 07a08430d66..8aa6704b810 100644 --- a/src/backend/utils/cache/typcache.c +++ b/src/backend/utils/cache/typcache.c @@ -1797,10 +1797,14 @@ assign_record_type_typmod(TupleDesc tupDesc) CreateCacheMemoryContext(); } - /* Find or create a hashtable entry for this tuple descriptor */ + /* + * Find a hashtable entry for this tuple descriptor. We don't use + * HASH_ENTER yet, because if it's missing, we need to make sure that all + * the allocations succeed before we create the new entry. + */ recentry = (RecordCacheEntry *) hash_search(RecordCacheHash, (void *) &tupDesc, - HASH_ENTER, &found); + HASH_FIND, &found); if (found && recentry->tupdesc != NULL) { tupDesc->tdtypmod = recentry->tupdesc->tdtypmod; @@ -1808,25 +1812,39 @@ assign_record_type_typmod(TupleDesc tupDesc) } /* Not present, so need to manufacture an entry */ - recentry->tupdesc = NULL; oldcxt = MemoryContextSwitchTo(CacheMemoryContext); /* Look in the SharedRecordTypmodRegistry, if attached */ entDesc = find_or_make_matching_shared_tupledesc(tupDesc); if (entDesc == NULL) { + /* + * Make sure we have room before we CreateTupleDescCopy() or advance + * NextRecordTypmod. + */ + ensure_record_cache_typmod_slot_exists(NextRecordTypmod); + /* Reference-counted local cache only. */ entDesc = CreateTupleDescCopy(tupDesc); entDesc->tdrefcount = 1; entDesc->tdtypmod = NextRecordTypmod++; } - ensure_record_cache_typmod_slot_exists(entDesc->tdtypmod); + else + { + ensure_record_cache_typmod_slot_exists(entDesc->tdtypmod); + } + RecordCacheArray[entDesc->tdtypmod] = entDesc; - recentry->tupdesc = entDesc; /* Assign a unique tupdesc identifier, too. */ RecordIdentifierArray[entDesc->tdtypmod] = ++tupledesc_id_counter; + /* Fully initialized; create the hash table entry */ + recentry = (RecordCacheEntry *) hash_search(RecordCacheHash, + (void *) &tupDesc, + HASH_ENTER, NULL); + recentry->tupdesc = entDesc; + /* Update the caller's tuple descriptor. */ tupDesc->tdtypmod = entDesc->tdtypmod; [parent: 03fc042eb628]