aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Davis <jdavis@postgresql.org>2021-07-09 14:15:48 -0700
committerJeff Davis <jdavis@postgresql.org>2021-07-10 10:27:07 -0700
commit10a07973cf72b32f32f0e05ada16c84580496d93 (patch)
tree45443928d7feee74adc712bf64cc6d038a67fa74
parentebc346e5bb72b2a68258f1be8791f2b90191cd38 (diff)
downloadpostgresql-10a07973cf72b32f32f0e05ada16c84580496d93.tar.gz
postgresql-10a07973cf72b32f32f0e05ada16c84580496d93.zip
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
-rw-r--r--src/backend/utils/cache/typcache.c28
1 files changed, 23 insertions, 5 deletions
diff --git a/src/backend/utils/cache/typcache.c b/src/backend/utils/cache/typcache.c
index de96e96c8fd..aa74a9a33ed 100644
--- a/src/backend/utils/cache/typcache.c
+++ b/src/backend/utils/cache/typcache.c
@@ -1970,10 +1970,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;
@@ -1981,25 +1985,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;