public inbox for [email protected]
help / color / mirror / Atom feedBUG #19492: intarray: fix variable stats leak in _int_matchsel
3+ messages / 3 participants
[nested] [flat]
* BUG #19492: intarray: fix variable stats leak in _int_matchsel
@ 2026-05-24 05:13 PG Bug reporting form <[email protected]>
0 siblings, 1 reply; 3+ messages in thread
From: PG Bug reporting form @ 2026-05-24 05:13 UTC (permalink / raw)
To: [email protected]; +Cc: [email protected]
The following bug has been logged on the website:
Bug reference: 19492
Logged by: Man Zeng
Email address: [email protected]
PostgreSQL version: 18.4
Operating system: 24.04.1-Ubuntu
Description:
Hi all,
While investigating the intarray contrib module, I noticed a variable
stats leak in _int_matchsel().
When vardata.vartype != INT4ARRAYOID, the function returns
DEFAULT_EQ_SEL early without releasing the variable stats previously
acquired via examine_variable(). This causes a memory leak in the
current memory context.
The fix is straightforward: add ReleaseVariableStats(vardata) before
the early return.
Steps to reproduce:
```sql
postgres@zxm-VMware-Virtual-Platform:~/code/postgres/contrib$ psql
psql (19devel)
Type "help" for help.
postgres=# CREATE EXTENSION intarray;
CREATE EXTENSION
postgres=# CREATE OR REPLACE FUNCTION my_text_eq(a text, b text) RETURNS
boolean AS $$
BEGIN
RETURN a = b;
END;
$$ LANGUAGE plpgsql;
CREATE FUNCTION
postgres=# CREATE OPERATOR %% (
LEFTARG = text,
RIGHTARG = text,
FUNCTION = my_text_eq,
RESTRICT = _int_matchsel
);
CREATE OPERATOR
postgres=# CREATE TEMP TABLE test_vuln (t text);
CREATE TABLE
postgres=# INSERT INTO test_vuln SELECT md5(i::text) FROM generate_series(1,
1000) i;
ANALYZE test_vuln;
INSERT 0 1000
ANALYZE
postgres=# EXPLAIN (COSTS ON) SELECT * FROM test_vuln WHERE t %%
'test'::text;
2026-05-20 23:47:42.257 CST [11370] WARNING: resource was not closed: cache
pg_statistic (73), tuple 9/33 has count 1
WARNING: resource was not closed: cache pg_statistic (73), tuple 9/33 has
count 1
QUERY PLAN
------------------------------------------------------------
Seq Scan on test_vuln (cost=0.00..269.00 rows=5 width=33)
Filter: (t %% 'test'::text)
(2 rows)
postgres=#
```
SQL:
```sql
CREATE EXTENSION intarray;
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;
EXPLAIN (COSTS ON) SELECT * FROM test_vuln WHERE t %% 'test'::text;
```
Regards,
Man Zeng
^ permalink raw reply [nested|flat] 3+ messages in thread
* Re:BUG #19492: intarray: fix variable stats leak in _int_matchsel
@ 2026-05-24 05:15 =?gb18030?B?emVuZ21hbg==?= <[email protected]>
parent: PG Bug reporting form <[email protected]>
0 siblings, 1 reply; 3+ messages in thread
From: =?gb18030?B?emVuZ21hbg==?= @ 2026-05-24 05:15 UTC (permalink / raw)
To: =?gb18030?B?1PjC+g==?= <[email protected]>; =?gb18030?B?cGdzcWwtYnVncw==?= <[email protected]>
Patch attached. Also added a test case that exercises this code path
by creating a text operator with _int_matchsel as the restriction
estimator.
Regards,
Man Zeng
Attachments:
[application/octet-stream] 0001-Fix-variable-stats-leak-in-_int_matchsel-early-retur.patch (2.7K, 2-0001-Fix-variable-stats-leak-in-_int_matchsel-early-retur.patch)
download | inline diff:
From 8e5606371df544f8be48937419fe54c96a358048 Mon Sep 17 00:00:00 2001
From: Man Zeng <[email protected]>
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
^ permalink raw reply [nested|flat] 3+ messages in thread
* Re: BUG #19492: intarray: fix variable stats leak in _int_matchsel
@ 2026-05-25 22:17 Tom Lane <[email protected]>
parent: =?gb18030?B?emVuZ21hbg==?= <[email protected]>
0 siblings, 0 replies; 3+ messages in thread
From: Tom Lane @ 2026-05-25 22:17 UTC (permalink / raw)
To: =?gb18030?B?emVuZ21hbg==?= <[email protected]>; +Cc: =?gb18030?B?cGdzcWwtYnVncw==?= <[email protected]>
"=?gb18030?B?emVuZ21hbg==?=" <[email protected]> writes:
> Patch attached. Also added a test case that exercises this code path
> by creating a text operator with _int_matchsel as the restriction
> estimator.
Good catch, pushed. I didn't bother with the test case though ---
none of the other early exits in that function have test cases,
and I don't see why this one is any more fragile than the others.
regards, tom lane
^ permalink raw reply [nested|flat] 3+ messages in thread
end of thread, other threads:[~2026-05-25 22:17 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2026-05-24 05:13 BUG #19492: intarray: fix variable stats leak in _int_matchsel PG Bug reporting form <[email protected]>
2026-05-24 05:15 ` =?gb18030?B?emVuZ21hbg==?= <[email protected]>
2026-05-25 22:17 ` Tom Lane <[email protected]>
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox