Skip to content

Commit 10a0797

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 ebc346e commit 10a0797

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
@@ -1970,36 +1970,54 @@ assign_record_type_typmod(TupleDesc tupDesc)
19701970
CreateCacheMemoryContext();
19711971
}
19721972

1973-
/* Find or create a hashtable entry for this tuple descriptor */
1973+
/*
1974+
* Find a hashtable entry for this tuple descriptor. We don't use
1975+
* HASH_ENTER yet, because if it's missing, we need to make sure that all
1976+
* the allocations succeed before we create the new entry.
1977+
*/
19741978
recentry = (RecordCacheEntry *) hash_search(RecordCacheHash,
19751979
(void *) &tupDesc,
1976-
HASH_ENTER, &found);
1980+
HASH_FIND, &found);
19771981
if (found && recentry->tupdesc != NULL)
19781982
{
19791983
tupDesc->tdtypmod = recentry->tupdesc->tdtypmod;
19801984
return;
19811985
}
19821986

19831987
/* Not present, so need to manufacture an entry */
1984-
recentry->tupdesc = NULL;
19851988
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
19861989

19871990
/* Look in the SharedRecordTypmodRegistry, if attached */
19881991
entDesc = find_or_make_matching_shared_tupledesc(tupDesc);
19891992
if (entDesc == NULL)
19901993
{
1994+
/*
1995+
* Make sure we have room before we CreateTupleDescCopy() or advance
1996+
* NextRecordTypmod.
1997+
*/
1998+
ensure_record_cache_typmod_slot_exists(NextRecordTypmod);
1999+
19912000
/* Reference-counted local cache only. */
19922001
entDesc = CreateTupleDescCopy(tupDesc);
19932002
entDesc->tdrefcount = 1;
19942003
entDesc->tdtypmod = NextRecordTypmod++;
19952004
}
1996-
ensure_record_cache_typmod_slot_exists(entDesc->tdtypmod);
2005+
else
2006+
{
2007+
ensure_record_cache_typmod_slot_exists(entDesc->tdtypmod);
2008+
}
2009+
19972010
RecordCacheArray[entDesc->tdtypmod] = entDesc;
1998-
recentry->tupdesc = entDesc;
19992011

20002012
/* Assign a unique tupdesc identifier, too. */
20012013
RecordIdentifierArray[entDesc->tdtypmod] = ++tupledesc_id_counter;
20022014

2015+
/* Fully initialized; create the hash table entry */
2016+
recentry = (RecordCacheEntry *) hash_search(RecordCacheHash,
2017+
(void *) &tupDesc,
2018+
HASH_ENTER, NULL);
2019+
recentry->tupdesc = entDesc;
2020+
20032021
/* Update the caller's tuple descriptor. */
20042022
tupDesc->tdtypmod = entDesc->tdtypmod;
20052023

0 commit comments

Comments
 (0)