Commit 10a07973 authored by Jeff Davis's avatar Jeff Davis

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 35ea7563)
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
parent ebc346e5
...@@ -1970,10 +1970,14 @@ assign_record_type_typmod(TupleDesc tupDesc) ...@@ -1970,10 +1970,14 @@ assign_record_type_typmod(TupleDesc tupDesc)
CreateCacheMemoryContext(); 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, recentry = (RecordCacheEntry *) hash_search(RecordCacheHash,
(void *) &tupDesc, (void *) &tupDesc,
HASH_ENTER, &found); HASH_FIND, &found);
if (found && recentry->tupdesc != NULL) if (found && recentry->tupdesc != NULL)
{ {
tupDesc->tdtypmod = recentry->tupdesc->tdtypmod; tupDesc->tdtypmod = recentry->tupdesc->tdtypmod;
...@@ -1981,25 +1985,39 @@ assign_record_type_typmod(TupleDesc tupDesc) ...@@ -1981,25 +1985,39 @@ assign_record_type_typmod(TupleDesc tupDesc)
} }
/* Not present, so need to manufacture an entry */ /* Not present, so need to manufacture an entry */
recentry->tupdesc = NULL;
oldcxt = MemoryContextSwitchTo(CacheMemoryContext); oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
/* Look in the SharedRecordTypmodRegistry, if attached */ /* Look in the SharedRecordTypmodRegistry, if attached */
entDesc = find_or_make_matching_shared_tupledesc(tupDesc); entDesc = find_or_make_matching_shared_tupledesc(tupDesc);
if (entDesc == NULL) 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. */ /* Reference-counted local cache only. */
entDesc = CreateTupleDescCopy(tupDesc); entDesc = CreateTupleDescCopy(tupDesc);
entDesc->tdrefcount = 1; entDesc->tdrefcount = 1;
entDesc->tdtypmod = NextRecordTypmod++; entDesc->tdtypmod = NextRecordTypmod++;
} }
ensure_record_cache_typmod_slot_exists(entDesc->tdtypmod); else
{
ensure_record_cache_typmod_slot_exists(entDesc->tdtypmod);
}
RecordCacheArray[entDesc->tdtypmod] = entDesc; RecordCacheArray[entDesc->tdtypmod] = entDesc;
recentry->tupdesc = entDesc;
/* Assign a unique tupdesc identifier, too. */ /* Assign a unique tupdesc identifier, too. */
RecordIdentifierArray[entDesc->tdtypmod] = ++tupledesc_id_counter; 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. */ /* Update the caller's tuple descriptor. */
tupDesc->tdtypmod = entDesc->tdtypmod; tupDesc->tdtypmod = entDesc->tdtypmod;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment