Skip to content

Commit 52c168d

Browse files
committed
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 35ea756) 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
1 parent 946f62f commit 52c168d

File tree

1 file changed

+23
-5
lines changed

1 file changed

+23
-5
lines changed

src/backend/utils/cache/typcache.c

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1786,36 +1786,54 @@ assign_record_type_typmod(TupleDesc tupDesc)
17861786
CreateCacheMemoryContext();
17871787
}
17881788

1789-
/* Find or create a hashtable entry for this tuple descriptor */
1789+
/*
1790+
* Find a hashtable entry for this tuple descriptor. We don't use
1791+
* HASH_ENTER yet, because if it's missing, we need to make sure that all
1792+
* the allocations succeed before we create the new entry.
1793+
*/
17901794
recentry = (RecordCacheEntry *) hash_search(RecordCacheHash,
17911795
(void *) &tupDesc,
1792-
HASH_ENTER, &found);
1796+
HASH_FIND, &found);
17931797
if (found && recentry->tupdesc != NULL)
17941798
{
17951799
tupDesc->tdtypmod = recentry->tupdesc->tdtypmod;
17961800
return;
17971801
}
17981802

17991803
/* Not present, so need to manufacture an entry */
1800-
recentry->tupdesc = NULL;
18011804
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
18021805

18031806
/* Look in the SharedRecordTypmodRegistry, if attached */
18041807
entDesc = find_or_make_matching_shared_tupledesc(tupDesc);
18051808
if (entDesc == NULL)
18061809
{
1810+
/*
1811+
* Make sure we have room before we CreateTupleDescCopy() or advance
1812+
* NextRecordTypmod.
1813+
*/
1814+
ensure_record_cache_typmod_slot_exists(NextRecordTypmod);
1815+
18071816
/* Reference-counted local cache only. */
18081817
entDesc = CreateTupleDescCopy(tupDesc);
18091818
entDesc->tdrefcount = 1;
18101819
entDesc->tdtypmod = NextRecordTypmod++;
18111820
}
1812-
ensure_record_cache_typmod_slot_exists(entDesc->tdtypmod);
1821+
else
1822+
{
1823+
ensure_record_cache_typmod_slot_exists(entDesc->tdtypmod);
1824+
}
1825+
18131826
RecordCacheArray[entDesc->tdtypmod] = entDesc;
1814-
recentry->tupdesc = entDesc;
18151827

18161828
/* Assign a unique tupdesc identifier, too. */
18171829
RecordIdentifierArray[entDesc->tdtypmod] = ++tupledesc_id_counter;
18181830

1831+
/* Fully initialized; create the hash table entry */
1832+
recentry = (RecordCacheEntry *) hash_search(RecordCacheHash,
1833+
(void *) &tupDesc,
1834+
HASH_ENTER, NULL);
1835+
recentry->tupdesc = entDesc;
1836+
18191837
/* Update the caller's tuple descriptor. */
18201838
tupDesc->tdtypmod = entDesc->tdtypmod;
18211839

0 commit comments

Comments
 (0)