Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 3acd059

Browse filesBrowse files
committed
Fix exception safety bug in typcache.c.
If an out-of-memory error was thrown at an unfortunate time, ensure_record_cache_typmod_slot_exists() could leak memory and leave behind a global state that produced an infinite loop on the next call. Fix by merging RecordCacheArray and RecordIdentifierArray into a single array. With only one allocation or re-allocation, there is no intermediate state. Back-patch to all supported releases. Reported-by: "James Pang (chaolpan)" <chaolpan@cisco.com> Reviewed-by: Michael Paquier <michael@paquier.xyz> Discussion: https://postgr.es/m/PH0PR11MB519113E738814BDDA702EDADD6EFA%40PH0PR11MB5191.namprd11.prod.outlook.com
1 parent 522a31a commit 3acd059
Copy full SHA for 3acd059

File tree

Expand file treeCollapse file tree

2 files changed

+28
-21
lines changed
Filter options
Expand file treeCollapse file tree

2 files changed

+28
-21
lines changed

‎src/backend/utils/cache/typcache.c

Copy file name to clipboardExpand all lines: src/backend/utils/cache/typcache.c
+27-21Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -273,10 +273,15 @@ static const dshash_parameters srtr_typmod_table_params = {
273273
/* hashtable for recognizing registered record types */
274274
static HTAB *RecordCacheHash = NULL;
275275

276-
/* arrays of info about registered record types, indexed by assigned typmod */
277-
static TupleDesc *RecordCacheArray = NULL;
278-
static uint64 *RecordIdentifierArray = NULL;
279-
static int32 RecordCacheArrayLen = 0; /* allocated length of above arrays */
276+
typedef struct RecordCacheArrayEntry
277+
{
278+
uint64 id;
279+
TupleDesc tupdesc;
280+
} RecordCacheArrayEntry;
281+
282+
/* array of info about registered record types, indexed by assigned typmod */
283+
static RecordCacheArrayEntry *RecordCacheArray = NULL;
284+
static int32 RecordCacheArrayLen = 0; /* allocated length of above array */
280285
static int32 NextRecordTypmod = 0; /* number of entries used */
281286

282287
/*
@@ -1703,19 +1708,20 @@ ensure_record_cache_typmod_slot_exists(int32 typmod)
17031708
{
17041709
if (RecordCacheArray == NULL)
17051710
{
1706-
RecordCacheArray = (TupleDesc *)
1707-
MemoryContextAllocZero(CacheMemoryContext, 64 * sizeof(TupleDesc));
1708-
RecordIdentifierArray = (uint64 *)
1709-
MemoryContextAllocZero(CacheMemoryContext, 64 * sizeof(uint64));
1711+
RecordCacheArray = (RecordCacheArrayEntry *)
1712+
MemoryContextAllocZero(CacheMemoryContext,
1713+
64 * sizeof(RecordCacheArrayEntry));
17101714
RecordCacheArrayLen = 64;
17111715
}
17121716

17131717
if (typmod >= RecordCacheArrayLen)
17141718
{
17151719
int32 newlen = pg_nextpower2_32(typmod + 1);
17161720

1717-
RecordCacheArray = repalloc0_array(RecordCacheArray, TupleDesc, RecordCacheArrayLen, newlen);
1718-
RecordIdentifierArray = repalloc0_array(RecordIdentifierArray, uint64, RecordCacheArrayLen, newlen);
1721+
RecordCacheArray = repalloc0_array(RecordCacheArray,
1722+
RecordCacheArrayEntry,
1723+
RecordCacheArrayLen,
1724+
newlen);
17191725
RecordCacheArrayLen = newlen;
17201726
}
17211727
}
@@ -1753,8 +1759,8 @@ lookup_rowtype_tupdesc_internal(Oid type_id, int32 typmod, bool noError)
17531759
{
17541760
/* It is already in our local cache? */
17551761
if (typmod < RecordCacheArrayLen &&
1756-
RecordCacheArray[typmod] != NULL)
1757-
return RecordCacheArray[typmod];
1762+
RecordCacheArray[typmod].tupdesc != NULL)
1763+
return RecordCacheArray[typmod].tupdesc;
17581764

17591765
/* Are we attached to a shared record typmod registry? */
17601766
if (CurrentSession->shared_typmod_registry != NULL)
@@ -1780,19 +1786,19 @@ lookup_rowtype_tupdesc_internal(Oid type_id, int32 typmod, bool noError)
17801786
* Our local array can now point directly to the TupleDesc
17811787
* in shared memory, which is non-reference-counted.
17821788
*/
1783-
RecordCacheArray[typmod] = tupdesc;
1789+
RecordCacheArray[typmod].tupdesc = tupdesc;
17841790
Assert(tupdesc->tdrefcount == -1);
17851791

17861792
/*
17871793
* We don't share tupdesc identifiers across processes, so
17881794
* assign one locally.
17891795
*/
1790-
RecordIdentifierArray[typmod] = ++tupledesc_id_counter;
1796+
RecordCacheArray[typmod].id = ++tupledesc_id_counter;
17911797

17921798
dshash_release_lock(CurrentSession->shared_typmod_table,
17931799
entry);
17941800

1795-
return RecordCacheArray[typmod];
1801+
return RecordCacheArray[typmod].tupdesc;
17961802
}
17971803
}
17981804
}
@@ -2005,10 +2011,10 @@ assign_record_type_typmod(TupleDesc tupDesc)
20052011
ensure_record_cache_typmod_slot_exists(entDesc->tdtypmod);
20062012
}
20072013

2008-
RecordCacheArray[entDesc->tdtypmod] = entDesc;
2014+
RecordCacheArray[entDesc->tdtypmod].tupdesc = entDesc;
20092015

20102016
/* Assign a unique tupdesc identifier, too. */
2011-
RecordIdentifierArray[entDesc->tdtypmod] = ++tupledesc_id_counter;
2017+
RecordCacheArray[entDesc->tdtypmod].id = ++tupledesc_id_counter;
20122018

20132019
/* Fully initialized; create the hash table entry */
20142020
recentry = (RecordCacheEntry *) hash_search(RecordCacheHash,
@@ -2057,10 +2063,10 @@ assign_record_type_identifier(Oid type_id, int32 typmod)
20572063
* It's a transient record type, so look in our record-type table.
20582064
*/
20592065
if (typmod >= 0 && typmod < RecordCacheArrayLen &&
2060-
RecordCacheArray[typmod] != NULL)
2066+
RecordCacheArray[typmod].tupdesc != NULL)
20612067
{
2062-
Assert(RecordIdentifierArray[typmod] != 0);
2063-
return RecordIdentifierArray[typmod];
2068+
Assert(RecordCacheArray[typmod].id != 0);
2069+
return RecordCacheArray[typmod].id;
20642070
}
20652071

20662072
/* For anonymous or unrecognized record type, generate a new ID */
@@ -2140,7 +2146,7 @@ SharedRecordTypmodRegistryInit(SharedRecordTypmodRegistry *registry,
21402146
TupleDesc tupdesc;
21412147
bool found;
21422148

2143-
tupdesc = RecordCacheArray[typmod];
2149+
tupdesc = RecordCacheArray[typmod].tupdesc;
21442150
if (tupdesc == NULL)
21452151
continue;
21462152

‎src/tools/pgindent/typedefs.list

Copy file name to clipboardExpand all lines: src/tools/pgindent/typedefs.list
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2251,6 +2251,7 @@ ReadLocalXLogPageNoWaitPrivate
22512251
ReadReplicationSlotCmd
22522252
ReassignOwnedStmt
22532253
RecheckForeignScan_function
2254+
RecordCacheArrayEntry
22542255
RecordCacheEntry
22552256
RecordCompareData
22562257
RecordIOData

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.