From 9ecc79851b704e4c4f1a18809b3aaa2836d3be55 Mon Sep 17 00:00:00 2001 From: Tender Wang Date: Sat, 15 Aug 2026 11:06:16 +0800 Subject: [PATCH] Fix integer overflow when constructing large hstore values --- contrib/hstore/hstore_io.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c index 9b72efb8674..0d537d65639 100644 --- a/contrib/hstore/hstore_io.c +++ b/contrib/hstore/hstore_io.c @@ -349,6 +349,24 @@ comparePairs(const void *a, const void *b) return (pa->keylen > pb->keylen) ? 1 : -1; } +/* + * Add the string-data length of a pair to *buflen, checking for overflow. + * Individual keys and values are each limited to HENTRY_POSMASK bytes, but + * their combined length can exceed the range of int32. + */ +static void +hstoreAddPairLen(int32 *buflen, const Pairs *pair) +{ + Size pairlen; + + pairlen = pair->keylen + (pair->isnull ? 0 : pair->vallen); + if (pairlen > MaxAllocSize - (Size) *buflen) + ereport(ERROR, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("hstore is too large"))); + *buflen += pairlen; +} + /* * this code still respects pairs.needfree, even though in general * it should never be called in a context where anything needs freeing. @@ -365,7 +383,7 @@ hstoreUniquePairs(Pairs *a, int32 l, int32 *buflen) if (l < 2) { if (l == 1) - *buflen = a->keylen + ((a->isnull) ? 0 : a->vallen); + hstoreAddPairLen(buflen, a); return l; } @@ -391,7 +409,7 @@ hstoreUniquePairs(Pairs *a, int32 l, int32 *buflen) } else { - *buflen += res->keylen + ((res->isnull) ? 0 : res->vallen); + hstoreAddPairLen(buflen, res); res++; if (res != ptr) memcpy(res, ptr, sizeof(Pairs)); @@ -400,7 +418,7 @@ hstoreUniquePairs(Pairs *a, int32 l, int32 *buflen) ptr++; } - *buflen += res->keylen + ((res->isnull) ? 0 : res->vallen); + hstoreAddPairLen(buflen, res); return res + 1 - a; } @@ -452,10 +470,15 @@ hstorePairs(Pairs *pairs, int32 pcount, int32 buflen) HEntry *entry; char *ptr; char *buf; - int32 len; + Size len; int32 i; len = CALCDATASIZE(pcount, buflen); + if (!AllocSizeIsValid(len)) + ereport(ERROR, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("hstore is too large"))); + out = palloc(len); SET_VARSIZE(out, len); HS_SETCOUNT(out, pcount); -- 2.43.0