From b78b6b6f0e71403cf93fb15d4ed4470a7dbb9ad9 Mon Sep 17 00:00:00 2001 From: Ewan Young Date: Wed, 8 Jul 2026 22:18:56 +0800 Subject: [PATCH v1] Widen GinTuple.keylen to uint32 to fix parallel GIN builds with large keys During a parallel GIN index build, _gin_build_tuple() computes the key length as an int from VARSIZE_ANY() (up to ~1GB for a varlena key) and lays out the serialized GinTuple -- its palloc size, the key memcpy, and the offset of the compressed TID list -- using that full length. But GinTuple.keylen was declared uint16, so the stored field wrapped around for keys larger than 65535 bytes while the rest of the tuple used the untruncated length. On read-back GinTupleGetFirst() and _gin_parse_tuple_items() recompute the TID-list offset from the truncated keylen, so it points into the key data instead of at the compressed posting list. ginPostingListDecodeAllSegments() then decodes arbitrary key bytes, which aborts the build (Assert in ginpostinglist.c) or reads past the allocation on non-assert builds. Any user able to run CREATE INDEX with parallel workers can hit this, e.g. a gin index on a text[] column with an element wider than 65535 bytes. This is specific to parallel builds: the serial path never materializes a GinTuple. The general index-tuple size limit is still enforced by GinFormTuple() in both cases. Widen keylen to uint32 so the stored length matches the length used to build the tuple. A parallel build then correctly indexes large keys that compress below the entry-tree item limit (as a serial build already does), and still rejects genuinely oversized keys cleanly via GinFormTuple() instead of crashing. Reported-by: Yuelin Wang <1217816127@qq.com> Bug: #19545 --- src/include/access/gin_tuple.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/access/gin_tuple.h b/src/include/access/gin_tuple.h index 7bde05e2de4..a116f3a1a77 100644 --- a/src/include/access/gin_tuple.h +++ b/src/include/access/gin_tuple.h @@ -23,7 +23,7 @@ typedef struct GinTuple { int tuplen; /* length of the whole tuple */ OffsetNumber attrnum; /* attnum of index key */ - uint16 keylen; /* bytes in data for key value */ + uint32 keylen; /* bytes in data for key value */ int16 typlen; /* typlen for key */ bool typbyval; /* typbyval for key */ signed char category; /* category: normal or NULL? */ -- 2.47.3