[PATCH] pg_restore_extended_stats() can store an MCV list that cannot be read back

From: Ewan Young <kdbase(dot)hack(at)gmail(dot)com>
To: PostgreSQL Hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org>
Cc: Michael Paquier <michael(at)paquier(dot)xyz>
Subject: [PATCH] pg_restore_extended_stats() can store an MCV list that cannot be read back
Date: 2026-06-16 03:15:46
Message-ID: CAON2xHORd2ESXm1KcVeeZ0Kd_aJk4dL4M2WLtzVDM4puaZ-20w@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hi,

pg_restore_extended_stats() does not bound the number of items in an
imported MCV list, but the read path rejects any list with more than
STATS_MCVLIST_MAX_ITEMS (= 10000) items. So an oversized list imports
successfully, gets written to pg_statistic_ext_data, and then makes
every read of that statistics object fail.

Reproduction (current master):

CREATE TABLE t (a int, b int);
INSERT INTO t SELECT g % 100, g % 50 FROM generate_series(1, 1000) g;
CREATE STATISTICS t_s (mcv) ON a, b FROM t;
ANALYZE t;

SELECT pg_restore_extended_stats(
'schemaname', 'public', 'relname', 't',
'statistics_schemaname', 'public', 'statistics_name', 't_s',
'inherited', false,
'most_common_vals', (SELECT array_agg(ARRAY[g::text, (g*7)::text])
FROM generate_series(1, 10001) g),
'most_common_freqs', (SELECT array_agg((0.5/10001)::float8)
FROM generate_series(1, 10001) g),
'most_common_base_freqs', (SELECT array_agg((0.5/10001)::float8)
FROM generate_series(1, 10001) g));
-- returns t

EXPLAIN SELECT * FROM t WHERE a = 1 AND b = 7;
-- ERROR: invalid length (10001) item array in MCVList (XX000)

The statistics object is then unusable until cleared. With more than
65535 items, an assertion-enabled build crashes instead (the Assert in
mcv_get_match_bitmap()).

The cause is a write/read asymmetry: import_mcv()
(extended_stats_funcs.c) hands the input item count to
statext_mcv_import() unbounded, while statext_mcv_deserialize()
(mcv.c) rejects nitems > STATS_MCVLIST_MAX_ITEMS. This is the same
family as 6d6348f0329 (CVE-2026-6575) and 0b8fa5fd37b, both of which
note import_mcv() was not affected by their issue -- the item-count
bound is a separate, still-open gap.

The attached patch adds that bound to import_mcv(), rejecting an
oversized list with a WARNING before anything is stored. A regression
test is added to stats_import.sql; "make check" passes.

Thanks,
Ewan Young

Attachment Content-Type Size
v1-0001-Reject-oversized-MCV-lists-in-extended-statistics.patch application/octet-stream 4.8 KB

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Bharath Rupireddy 2026-06-16 03:20:13 Re: Disable startup progress timeout during standby WAL replay
Previous Message Yingying Chen 2026-06-16 03:09:58 Re: Make frontend programs relink after libpgfeutils changes