| From: | Peter Eisentraut <peter(at)eisentraut(dot)org> |
|---|---|
| To: | pgsql-committers(at)lists(dot)postgresql(dot)org |
| Subject: | pgsql: Fix parallel GIN index build with keys larger than 65535 bytes |
| Date: | 2026-09-14 14:55:51 |
| Message-ID: | E1x6863-00000000Ijd-2mI1@gemulon.postgresql.org |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-committers |
Fix parallel GIN index build with keys larger than 65535 bytes
During a parallel GIN build, each key is serialized into a GinTuple, a
transient representation used only while sorting. _gin_build_tuple()
lays out the whole tuple (the palloc size, the key memcpy, and the
offset of the posting list) from a local variable holding the real key
length, but then stored that length in GinTuple.keylen, which was
uint16. For a key longer than 65535 bytes, the stored length was thus
silently truncated.
On read-back, GinTupleGetFirst() and _gin_parse_tuple_items()
recompute the posting-list offset from the truncated keylen and land
inside the key data, so ginPostingListDecodeAllSegments() decodes
garbage: an assertion failure with assertions enabled, and a read past
the end of the allocation without, which could in turn lead to a crash
or garbage being written into the index. Only parallel builds are
affected, because only they materialize a GinTuple; a serial build of
the same data succeeds, as index_form_tuple() compresses large keys
before the GinMaxItemSize check.
To fix, widen GinTuple.keylen to Size, which is what VARSIZE_ANY()
returns and what GinBuffer.keylen already uses, and use Size for the
local in _gin_build_tuple() too, which was an int that truncated
VARSIZE_ANY() the same way.
Widening keylen moves GinTuple.data. The key value is accessed in
place in data, so data must be MAXALIGN'ed; before, that was only true
by accident of the field layout. Make that explicit with
alignas(MAXIMUM_ALIGNOF) on data, so that the layout stays correct on
32-bit platforms, where Size is 4 bytes and would otherwise leave data
under-aligned when MAXIMUM_ALIGNOF is 8.
Bug: #19545
Author: Ewan Young <kdbase(dot)hack(at)gmail(dot)com>
Reported-by: Yuelin Wang <1217816127(at)qq(dot)com>
Reviewed-by: Peter Eisentraut <peter(at)eisentraut(dot)org>
Discussion: https://www.postgresql.org/message-id/flat/19545-0f25b7e47351e8fc%40postgresql.org
Branch
------
master
Details
-------
https://git.postgresql.org/pg/commitdiff/bad8829872d4d16f0d5de38c2cf9c0e9db86ac22
Modified Files
--------------
src/backend/access/gin/gininsert.c | 2 +-
src/include/access/gin_tuple.h | 9 +++++++--
2 files changed, 8 insertions(+), 3 deletions(-)
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Melanie Plageman | 2026-09-14 15:27:43 | pgsql: Handle no-op visibility map set during redo |
| Previous Message | Melanie Plageman | 2026-09-14 14:47:15 | pgsql: Avoid setting pd_prune_xid when inserting frozen tuples |