From 8e5606371df544f8be48937419fe54c96a358048 Mon Sep 17 00:00:00 2001 From: Man Zeng Date: Sun, 24 May 2026 12:36:36 +0800 Subject: [PATCH] Fix variable stats leak in _int_matchsel early return path When vardata.vartype != INT4ARRAYOID, _int_matchsel returns DEFAULT_EQ_SEL without releasing the variable stats previously acquired via examine_variable(), causing a memory leak. Add the missing ReleaseVariableStats() call. --- contrib/intarray/_int_selfuncs.c | 3 +++ contrib/intarray/expected/_int.out | 21 +++++++++++++++++++++ contrib/intarray/sql/_int.sql | 20 ++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/contrib/intarray/_int_selfuncs.c b/contrib/intarray/_int_selfuncs.c index 7fce743632f..c0161928074 100644 --- a/contrib/intarray/_int_selfuncs.c +++ b/contrib/intarray/_int_selfuncs.c @@ -151,7 +151,10 @@ _int_matchsel(PG_FUNCTION_ARGS) * query_int. */ if (vardata.vartype != INT4ARRAYOID) + { + ReleaseVariableStats(vardata); PG_RETURN_FLOAT8(DEFAULT_EQ_SEL); + } /* * Can't do anything useful if the something is not a constant, either. diff --git a/contrib/intarray/expected/_int.out b/contrib/intarray/expected/_int.out index fb4086a95ca..8ae730a535d 100644 --- a/contrib/intarray/expected/_int.out +++ b/contrib/intarray/expected/_int.out @@ -1026,3 +1026,24 @@ SELECT count(*) from test__int WHERE a @@ '!2733 & (2738 | 254)'; (1 row) RESET enable_seqscan; +CREATE OR REPLACE FUNCTION my_text_eq(a text, b text) RETURNS boolean AS $$ +BEGIN + RETURN a = b; +END; +$$ LANGUAGE plpgsql; +CREATE OPERATOR %% ( + LEFTARG = text, + RIGHTARG = text, + FUNCTION = my_text_eq, + RESTRICT = _int_matchsel +); +CREATE TEMP TABLE test_vuln (t text); +INSERT INTO test_vuln SELECT md5(i::text) FROM generate_series(1, 1000) i; +ANALYZE test_vuln; +SELECT * FROM test_vuln WHERE t %% 'test'::text; + t +--- +(0 rows) + +DROP FUNCTION my_text_eq CASCADE; +NOTICE: drop cascades to operator %%(text,text) diff --git a/contrib/intarray/sql/_int.sql b/contrib/intarray/sql/_int.sql index 0d30914725e..765b1138772 100644 --- a/contrib/intarray/sql/_int.sql +++ b/contrib/intarray/sql/_int.sql @@ -252,3 +252,23 @@ SELECT count(*) from test__int WHERE a @@ '!2733 & (2738 | 254)'; RESET enable_seqscan; + +CREATE OR REPLACE FUNCTION my_text_eq(a text, b text) RETURNS boolean AS $$ +BEGIN + RETURN a = b; +END; +$$ LANGUAGE plpgsql; + +CREATE OPERATOR %% ( + LEFTARG = text, + RIGHTARG = text, + FUNCTION = my_text_eq, + RESTRICT = _int_matchsel +); + +CREATE TEMP TABLE test_vuln (t text); +INSERT INTO test_vuln SELECT md5(i::text) FROM generate_series(1, 1000) i; +ANALYZE test_vuln; + +SELECT * FROM test_vuln WHERE t %% 'test'::text; +DROP FUNCTION my_text_eq CASCADE; -- 2.45.2