Skip to content

Commit 5b1621d

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 03fc042 commit 5b1621d

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
@@ -1797,36 +1797,54 @@ assign_record_type_typmod(TupleDesc tupDesc)
17971797
CreateCacheMemoryContext();
17981798
}
17991799

1800-
/* Find or create a hashtable entry for this tuple descriptor */
1800+
/*
1801+
* Find a hashtable entry for this tuple descriptor. We don't use
1802+
* HASH_ENTER yet, because if it's missing, we need to make sure that all
1803+
* the allocations succeed before we create the new entry.
1804+
*/
18011805
recentry = (RecordCacheEntry *) hash_search(RecordCacheHash,
18021806
(void *) &tupDesc,
1803-
HASH_ENTER, &found);
1807+
HASH_FIND, &found);
18041808
if (found && recentry->tupdesc != NULL)
18051809
{
18061810
tupDesc->tdtypmod = recentry->tupdesc->tdtypmod;
18071811
return;
18081812
}
18091813

18101814
/* Not present, so need to manufacture an entry */
1811-
recentry->tupdesc = NULL;
18121815
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
18131816

18141817
/* Look in the SharedRecordTypmodRegistry, if attached */
18151818
entDesc = find_or_make_matching_shared_tupledesc(tupDesc);
18161819
if (entDesc == NULL)
18171820
{
1821+
/*
1822+
* Make sure we have room before we CreateTupleDescCopy() or advance
1823+
* NextRecordTypmod.
1824+
*/
1825+
ensure_record_cache_typmod_slot_exists(NextRecordTypmod);
1826+
18181827
/* Reference-counted local cache only. */
18191828
entDesc = CreateTupleDescCopy(tupDesc);
18201829
entDesc->tdrefcount = 1;
18211830
entDesc->tdtypmod = NextRecordTypmod++;
18221831
}
1823-
ensure_record_cache_typmod_slot_exists(entDesc->tdtypmod);
1832+
else
1833+
{
1834+
ensure_record_cache_typmod_slot_exists(entDesc->tdtypmod);
1835+
}
1836+
18241837
RecordCacheArray[entDesc->tdtypmod] = entDesc;
1825-
recentry->tupdesc = entDesc;
18261838

18271839
/* Assign a unique tupdesc identifier, too. */
18281840
RecordIdentifierArray[entDesc->tdtypmod] = ++tupledesc_id_counter;
18291841

1842+
/* Fully initialized; create the hash table entry */
1843+
recentry = (RecordCacheEntry *) hash_search(RecordCacheHash,
1844+
(void *) &tupDesc,
1845+
HASH_ENTER, NULL);
1846+
recentry->tupdesc = entDesc;
1847+
18301848
/* Update the caller's tuple descriptor. */
18311849
tupDesc->tdtypmod = entDesc->tdtypmod;
18321850

0 commit comments

Comments
 (0)