Skip to content

Commit cc46eb7

Browse files
committed
The cache of PL function was changed in PostgreSQL 18. Before PostgreSQL 18,
caching PLpgSQL function was implemented in PLpgSQL. PostgreSQL 18 introduced generic PL cache (shared by PL/pgSQL and SQL functions). Generic PL cache uses CachedFunctionHashKey struction and against PLpgSQL_func_hashkey last array with args types is not fully zeroized - and then using HASH_BLOBS is wrong. This issue was detected by valgrind and reported by SergeyLubimov (#193). Fixed by using copy of hash functions from funccache.c
1 parent eced951 commit cc46eb7

File tree

1 file changed

+87
-3
lines changed

1 file changed

+87
-3
lines changed

src/check_function.c

Lines changed: 87 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@
1414

1515
#include "catalog/pg_proc.h"
1616
#include "catalog/pg_type.h"
17+
18+
#if PG_VERSION_NUM >= 180000
19+
20+
#include "common/hashfn.h"
21+
22+
#endif
23+
1724
#include "nodes/makefuncs.h"
1825
#include "utils/guc.h"
1926
#include "utils/memutils.h"
@@ -23,6 +30,7 @@
2330
#include "utils/typcache.h"
2431
#include "access/heapam.h"
2532

33+
2634
static HTAB *plpgsql_check_HashTable = NULL;
2735

2836
bool plpgsql_check_other_warnings = false;
@@ -1353,6 +1361,75 @@ copy_plpgsql_datum(PLpgSQL_checkstate *cstate, PLpgSQL_datum *datum)
13531361
return result;
13541362
}
13551363

1364+
#if PG_VERSION_NUM >= 180000
1365+
1366+
/*
1367+
* cfunc_hash: hash function for cfunc hash table (copy from funccache.c)
1368+
*
1369+
* We need special hash and match functions to deal with the optional
1370+
* presence of a TupleDesc in the hash keys. As long as we have to do
1371+
* that, we might as well also be smart about not comparing unused
1372+
* elements of the argtypes arrays.
1373+
*/
1374+
static uint32
1375+
cfunc_hash(const void *key, Size keysize)
1376+
{
1377+
const CachedFunctionHashKey *k = (const CachedFunctionHashKey *) key;
1378+
uint32 h;
1379+
1380+
Assert(keysize == sizeof(CachedFunctionHashKey));
1381+
/* Hash all the fixed fields except callResultType */
1382+
h = DatumGetUInt32(hash_any((const unsigned char *) k,
1383+
offsetof(CachedFunctionHashKey, callResultType)));
1384+
/* Incorporate input argument types */
1385+
if (k->nargs > 0)
1386+
h = hash_combine(h,
1387+
DatumGetUInt32(hash_any((const unsigned char *) k->argtypes,
1388+
k->nargs * sizeof(Oid))));
1389+
/* Incorporate callResultType if present */
1390+
if (k->callResultType)
1391+
h = hash_combine(h, hashRowType(k->callResultType));
1392+
return h;
1393+
}
1394+
1395+
/*
1396+
* cfunc_match: match function to use with cfunc_hash
1397+
*/
1398+
static int
1399+
cfunc_match(const void *key1, const void *key2, Size keysize)
1400+
{
1401+
const CachedFunctionHashKey *k1 = (const CachedFunctionHashKey *) key1;
1402+
const CachedFunctionHashKey *k2 = (const CachedFunctionHashKey *) key2;
1403+
1404+
Assert(keysize == sizeof(CachedFunctionHashKey));
1405+
/* Compare all the fixed fields except callResultType */
1406+
if (memcmp(k1, k2, offsetof(CachedFunctionHashKey, callResultType)) != 0)
1407+
return 1; /* not equal */
1408+
/* Compare input argument types (we just verified that nargs matches) */
1409+
if (k1->nargs > 0 &&
1410+
memcmp(k1->argtypes, k2->argtypes, k1->nargs * sizeof(Oid)) != 0)
1411+
return 1; /* not equal */
1412+
/* Compare callResultType */
1413+
if (k1->callResultType)
1414+
{
1415+
if (k2->callResultType)
1416+
{
1417+
if (!equalRowTypes(k1->callResultType, k2->callResultType))
1418+
return 1; /* not equal */
1419+
}
1420+
else
1421+
return 1; /* not equal */
1422+
}
1423+
else
1424+
{
1425+
if (k2->callResultType)
1426+
return 1; /* not equal */
1427+
}
1428+
return 0; /* equal */
1429+
}
1430+
1431+
#endif
1432+
13561433
void
13571434
plpgsql_check_HashTableInit(void)
13581435
{
@@ -1366,18 +1443,24 @@ plpgsql_check_HashTableInit(void)
13661443
#if PG_VERSION_NUM >= 180000
13671444

13681445
ctl.keysize = sizeof(CachedFunctionHashKey);
1446+
ctl.entrysize = sizeof(plpgsql_check_HashEnt);
1447+
ctl.hash = cfunc_hash;
1448+
ctl.match = cfunc_match;
1449+
plpgsql_check_HashTable = hash_create("plpgsql_check function cache",
1450+
FUNCS_PER_USER,
1451+
&ctl,
1452+
HASH_ELEM | HASH_FUNCTION | HASH_COMPARE);
13691453

13701454
#else
13711455

13721456
ctl.keysize = sizeof(PLpgSQL_func_hashkey);
1373-
1374-
#endif
1375-
13761457
ctl.entrysize = sizeof(plpgsql_check_HashEnt);
13771458
plpgsql_check_HashTable = hash_create("plpgsql_check function cache",
13781459
FUNCS_PER_USER,
13791460
&ctl,
13801461
HASH_ELEM | HASH_BLOBS);
1462+
#endif
1463+
13811464
}
13821465

13831466
/*
@@ -1456,6 +1539,7 @@ plpgsql_check_mark_as_checked(PLpgSQL_function *func)
14561539
hentry->fn_tid = func->fn_tid;
14571540

14581541
#endif
1542+
14591543
hentry->is_checked = true;
14601544
}
14611545
}

0 commit comments

Comments
 (0)