8000 Fix exception safety bug in typcache.c. · postgres/postgres@6ae57f1 · GitHub
[go: up one dir, main page]

Skip to content

Commit 6ae57f1

Browse 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 feb4e21 commit 6ae57f1

File tree

2 files changed

+27
-26
lines changed

2 files changed

+27
-26
lines changed

src/backend/utils/cache/typcache.c

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -262,10 +262,15 @@ static const dshash_parameters srtr_typmod_table_params = {
262262
/* hashtable for recognizing registered record types */
263263
static HTAB *RecordCacheHash = NULL;
264264

265-
/* arrays of info about registered record types, indexed by assigned typmod */
266-
static TupleDesc *RecordCacheArray = NULL;
267-
static uint64 *RecordIdentifierArray = NULL;
268-
static int32 RecordCacheArrayLen = 0; /* allocated length of above arrays */
265+
typedef struct RecordCacheArrayEntry
266+
{
267+
uint64 id;
268+
TupleDesc tupdesc;
269+
} RecordCacheArrayEntry;
270+
271+
/* array of info about registered record types, indexed by assigned typmod */
272+
static RecordCacheArrayEntry *RecordCacheArray = NULL;
273+
static int32 RecordCacheArrayLen = 0; /* allocated length of above array */
269274
static int32 NextRecordTypmod = 0; /* number of entries used */
270275

271276
/*
@@ -1514,10 +1519,8 @@ ensure_record_cache_typmod_slot_exists(int32 typmod)
15141519
{
15151520
if (RecordCacheArray == NULL)
15161521
{
1517-
RecordCacheArray = (TupleDesc *)
1518-
MemoryContextAllocZero(CacheMemoryContext, 64 * sizeof(TupleDesc));
1519-
RecordIdentifierArray = (uint64 *)
1520-
MemoryContextAllocZero(CacheMemoryContext, 64 * sizeof(uint64));
1522+
RecordCacheArray = (RecordCacheArrayEntry *)
1523+
MemoryContextAllocZero(CacheMemoryContext, 64 * sizeof(RecordCacheArrayEntry));
15211524
RecordCacheArrayLen = 64;
15221525
}
15231526

@@ -1528,14 +1531,11 @@ ensure_record_cache_typmod_slot_exists(int32 typmod)
15281531
while (typmod >= newlen)
15291532
newlen *= 2;
15301533

1531-
RecordCacheArray = (TupleDesc *) repalloc(RecordCacheArray,
1532-
newlen * sizeof(TupleDesc));
1534+
RecordCacheArray = (RecordCacheArrayEntry *)
1535+
repalloc(RecordCacheArray,
1536+
newlen * sizeof(RecordCacheArrayEntry));
15331537
memset(RecordCacheArray + RecordCacheArrayLen, 0,
1534-
(newlen - RecordCacheArrayLen) * sizeof(TupleDesc));
1535-
RecordIdentifierArray = (uint64 *) repalloc(RecordIdentifierArray,
1536-
newlen * sizeof(uint64));
1537-
memset(RecordIdentifierArray + RecordCacheArrayLen, 0,
1538-
(newlen - RecordCacheArrayLen) * sizeof(uint64));
1538+
(newlen - RecordCacheArrayLen) * sizeof(RecordCacheArrayEntry));
15391539
RecordCacheArrayLen = newlen;
15401540
}
15411541
}
@@ -1573,8 +1573,8 @@ lookup_rowtype_tupdesc_internal(Oid type_id, int32 typmod, bool noError)
15731573
{
15741574
/* It is already in our local cache? */
15751575
if (typmod < RecordCacheArrayLen &&
1576-
RecordCacheArray[typmod] != NULL)
1577-
return RecordCacheArray[typmod];
1576+
RecordCacheArray[typmod].tupdesc != NULL)
1577+
return RecordCacheArray[typmod].tupdesc;
15781578

15791579
/* Are we attached to a shared record typmod registry? */
15801580
if (CurrentSession->shared_typmod_registry != NULL)
@@ -1600,19 +1600,19 @@ lookup_rowtype_tupdesc_internal(Oid type_id, int32 typmod, bool noError)
16001600
* Our local array can now point directly to the TupleDesc
16011601
* in shared memory, which is non-reference-counted.
16021602
*/
1603-
RecordCacheArray[typmod] = tupdesc;
1603+
RecordCacheArray[typmod].tupdesc = tupdesc;
16041604
Assert(tupdesc->tdrefcount == -1);
16051605

16061606
/*
16071607
* We don't share tupdesc identifiers across processes, so
16081608
* assign one locally.
16091609
*/
1610-
RecordIdentifierArray[typmod] = ++tupledesc_id_counter;
1610+
RecordCacheArray[typmod].id = ++tupledesc_id_counter;
16111611

16121612
dshash_release_lock(CurrentSession->shared_typmod_table,
16131613
entry);
16141614

1615-
return RecordCacheArray[typmod];
1615+
return RecordCacheArray[typmod].tupdesc;
16161616
}
16171617
}
16181618
}
@@ -1823,10 +1823,10 @@ assign_record_type_typmod(TupleDesc tupDesc)
18231823
ensure_record_cache_typmod_slot_exists(entDesc->tdtypmod);
18241824
}
18251825

1826-
RecordCacheArray[entDesc->tdtypmod] = entDesc;
1826+
RecordCacheArray[entDesc->tdtypmod].tupdesc = entDesc;
18271827

18281828
/* Assign a unique tupdesc identifier, too. */
1829-
RecordIdentifierArray[entDesc->tdtypmod] = ++tupledesc_id_counter;
1829+
RecordCacheArray[entDesc->tdtypmod].id = ++tupledesc_id_counter;
18301830

18311831
/* Fully initialized; create the hash table entry */
18321832
recentry = (RecordCacheEntry *) hash_search(RecordCacheHash,
@@ -1875,10 +1875,10 @@ assign_record_type_identifier(Oid type_id, int32 typmod)
18751875
* It's a transient record type, so look in our record-type table.
18761876
*/
18771877
if (typmod >= 0 && typmod < RecordCacheArrayLen &&
1878-
RecordCacheArray[typmod] != NULL)
1878+
RecordCacheArray[typmod].tupdesc != NULL)
18791879
{
1880-
Assert(RecordIdentifierArray[typmod] != 0);
1881-
return RecordIdentifierArray[t 57AE ypmod];
1880+
Assert(RecordCacheArray[typmod].id != 0);
1881+
return RecordCacheArray[typmod].id;
18821882
}
18831883

18841884
/* For anonymous or unrecognized record type, generate a new ID */
@@ -1958,7 +1958,7 @@ SharedRecordTypmodRegistryInit(SharedRecordTypmodRegistry *registry,
19581958
TupleDesc tupdesc;
19591959
bool found;
19601960

1961-
tupdesc = RecordCacheArray[typmod];
1961+
tupdesc = RecordCacheArray[typmod].tupdesc;
19621962
if (tupdesc == NULL)
19631963
continue;
19641964

src/tools/pgindent/typedefs.list

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1898,6 +1898,7 @@ ReadExtraTocPtrType
18981898
ReadFunc
18991899
ReassignOwnedStmt
19001900
RecheckForeignScan_function
1901+
RecordCacheArrayEntry
19011902
RecordCacheEntry
19021903
RecordCompareData
19031904
RecordIOData

0 commit comments

Comments
 (0)
0