From b9c3b5ae71c368a280ca744134d55ba487a74975 Mon Sep 17 00:00:00 2001 From: Tender Wang Date: Mon, 17 Aug 2026 10:00:22 +0800 Subject: [PATCH v2] Fix integer overflow when constructing large hstore values --- contrib/hstore/hstore.h | 25 +++++++++++--------- contrib/hstore/hstore_io.c | 47 +++++++++++++++++++++++--------------- contrib/hstore/hstore_op.c | 2 +- 3 files changed, 44 insertions(+), 30 deletions(-) diff --git a/contrib/hstore/hstore.h b/contrib/hstore/hstore.h index 897af244a42..91aceb3ade2 100644 --- a/contrib/hstore/hstore.h +++ b/contrib/hstore/hstore.h @@ -62,15 +62,18 @@ typedef struct #define HS_SETCOUNT(hsp_,c_) ((hsp_)->size_ = (c_) | HS_FLAG_NEWVERSION) -/* - * "x" comes from an existing HS_COUNT() (as discussed, <= INT_MAX/24) or a - * Pairs array length (due to MaxAllocSize, <= INT_MAX/40). "lenstr" is no - * more than INT_MAX, that extreme case arising in hstore_from_arrays(). - * Therefore, this calculation is limited to about INT_MAX / 5 + INT_MAX. - */ #define HSHRDSIZE (sizeof(HStore)) -#define CALCDATASIZE(x, lenstr) ( (x) * 2 * sizeof(HEntry) + HSHRDSIZE + (lenstr) ) +static inline Size +hstoreCalcDataSize(Size count, Size lenstr) +{ + Size len; + + len = mul_size(count, 2 * sizeof(HEntry)); + len = add_size(len, HSHRDSIZE); + return add_size(len, lenstr); +} +#define CALCDATASIZE(x, lenstr) hstoreCalcDataSize((x), (lenstr)) /* note multiple evaluations of x */ #define ARRPTR(x) ( (HEntry*) ( (HStore*)(x) + 1 ) ) #define STRPTR(x) ( (char*)(ARRPTR(x) + HS_COUNT((HStore*)(x)) * 2) ) @@ -128,7 +131,7 @@ typedef struct /* finalize a newly-constructed hstore */ #define HS_FINALIZE(hsp_,count_,buf_,ptr_) \ do { \ - int _buflen = (ptr_) - (buf_); \ + Size _buflen = (ptr_) - (buf_); \ if ((count_)) \ ARRPTR(hsp_)[0].entry |= HENTRY_ISFIRST; \ if ((count_) != HS_COUNT((hsp_))) \ @@ -142,7 +145,7 @@ typedef struct /* ensure the varlena size of an existing hstore is correct */ #define HS_FIXSIZE(hsp_,count_) \ do { \ - int bl = (count_) ? HSE_ENDPOS(ARRPTR(hsp_)[2*(count_)-1]) : 0; \ + Size bl = (count_) ? HSE_ENDPOS(ARRPTR(hsp_)[2*(count_)-1]) : 0;\ SET_VARSIZE((hsp_), CALCDATASIZE((count_),bl)); \ } while (0) @@ -168,8 +171,8 @@ typedef struct bool needfree; /* need to pfree the value? */ } Pairs; -extern PGDLLEXPORT int hstoreUniquePairs(Pairs *a, int32 l, int32 *buflen); -extern PGDLLEXPORT HStore *hstorePairs(Pairs *pairs, int32 pcount, int32 buflen); +extern PGDLLEXPORT int hstoreUniquePairs(Pairs *a, int32 l, Size *buflen); +extern PGDLLEXPORT HStore *hstorePairs(Pairs *pairs, int32 pcount, Size buflen); extern PGDLLEXPORT size_t hstoreCheckKeyLen(size_t len); extern PGDLLEXPORT size_t hstoreCheckValLen(size_t len); diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c index 9b72efb8674..fa58f98efa1 100644 --- a/contrib/hstore/hstore_io.c +++ b/contrib/hstore/hstore_io.c @@ -356,7 +356,7 @@ comparePairs(const void *a, const void *b) * and (b) who knows whether they might be needed by some caller. */ int -hstoreUniquePairs(Pairs *a, int32 l, int32 *buflen) +hstoreUniquePairs(Pairs *a, int32 l, Size *buflen) { Pairs *ptr, *res; @@ -365,7 +365,11 @@ hstoreUniquePairs(Pairs *a, int32 l, int32 *buflen) if (l < 2) { if (l == 1) - *buflen = a->keylen + ((a->isnull) ? 0 : a->vallen); + { + *buflen = add_size(*buflen, a->keylen); + if (!a->isnull) + *buflen = add_size(*buflen, a->vallen); + } return l; } @@ -391,7 +395,9 @@ hstoreUniquePairs(Pairs *a, int32 l, int32 *buflen) } else { - *buflen += res->keylen + ((res->isnull) ? 0 : res->vallen); + *buflen = add_size(*buflen, res->keylen); + if (!res->isnull) + *buflen = add_size(*buflen, res->vallen); res++; if (res != ptr) memcpy(res, ptr, sizeof(Pairs)); @@ -400,7 +406,9 @@ hstoreUniquePairs(Pairs *a, int32 l, int32 *buflen) ptr++; } - *buflen += res->keylen + ((res->isnull) ? 0 : res->vallen); + *buflen = add_size(*buflen, res->keylen); + if (!res->isnull) + *buflen = add_size(*buflen, res->vallen); return res + 1 - a; } @@ -446,13 +454,13 @@ hstoreCheckValLength(size_t len, HSParser *state) HStore * -hstorePairs(Pairs *pairs, int32 pcount, int32 buflen) +hstorePairs(Pairs *pairs, int32 pcount, Size buflen) { HStore *out; HEntry *entry; char *ptr; char *buf; - int32 len; + Size len; int32 i; len = CALCDATASIZE(pcount, buflen); @@ -482,7 +490,7 @@ hstore_in(PG_FUNCTION_ARGS) char *str = PG_GETARG_CSTRING(0); Node *escontext = fcinfo->context; HSParser state; - int32 buflen; + Size buflen; HStore *out; state.begin = str; @@ -503,7 +511,7 @@ PG_FUNCTION_INFO_V1(hstore_recv); Datum hstore_recv(PG_FUNCTION_ARGS) { - int32 buflen; + Size buflen; HStore *out; Pairs *pairs; int32 i; @@ -592,7 +600,7 @@ hstore_from_text(PG_FUNCTION_ARGS) p.isnull = false; } - out = hstorePairs(&p, 1, p.keylen + p.vallen); + out = hstorePairs(&p, 1, add_size(p.keylen, p.vallen)); PG_RETURN_POINTER(out); } @@ -602,7 +610,7 @@ PG_FUNCTION_INFO_V1(hstore_from_arrays); Datum hstore_from_arrays(PG_FUNCTION_ARGS) { - int32 buflen; + Size buflen; HStore *out; Pairs *pairs; Datum *key_datums; @@ -721,7 +729,7 @@ hstore_from_array(PG_FUNCTION_ARGS) ArrayType *in_array = PG_GETARG_ARRAYTYPE_P(0); int ndims = ARR_NDIM(in_array); int count; - int32 buflen; + Size buflen; HStore *out; Pairs *pairs; Datum *in_datums; @@ -835,7 +843,7 @@ Datum hstore_from_record(PG_FUNCTION_ARGS) { HeapTupleHeader rec; - int32 buflen; + Size buflen; HStore *out; Pairs *pairs; Oid tupType; @@ -1226,8 +1234,8 @@ Datum hstore_out(PG_FUNCTION_ARGS) { HStore *in = PG_GETARG_HSTORE_P(0); - int buflen, - i; + Size buflen; + int i; int count = HS_COUNT(in); char *out, *ptr; @@ -1250,11 +1258,14 @@ hstore_out(PG_FUNCTION_ARGS) for (i = 0; i < count; i++) { /* include "" and => and comma-space */ - buflen += 6 + 2 * HSTORE_KEYLEN(entries, i); + buflen = add_size(buflen, 6); + buflen = add_size(buflen, mul_size(2, HSTORE_KEYLEN(entries, i))); /* include "" only if nonnull */ - buflen += 2 + (HSTORE_VALISNULL(entries, i) - ? 2 - : 2 * HSTORE_VALLEN(entries, i)); + buflen = add_size(buflen, 2); + if (HSTORE_VALISNULL(entries, i)) + buflen = add_size(buflen, 2); + else + buflen = add_size(buflen, mul_size(2, HSTORE_VALLEN(entries, i))); } out = ptr = palloc(buflen); diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c index bcba75f9258..19f8b6b9684 100644 --- a/contrib/hstore/hstore_op.c +++ b/contrib/hstore/hstore_op.c @@ -76,7 +76,7 @@ hstoreArrayToPairs(ArrayType *a, int *npairs) bool *key_nulls; int key_count; Pairs *key_pairs; - int bufsiz; + Size bufsiz; int i, j; -- 2.43.0