aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2024-01-07 15:19:50 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2024-01-07 15:19:50 -0500
commit1c7443521f856dfb5f6731ff6fc0865a67a29f14 (patch)
treeb1f6c2b412e149d2a8136817fc49f1d546d42fc9
parent72d5b27763a86c1d9af79e3169aef885b79373a3 (diff)
downloadpostgresql-1c7443521f856dfb5f6731ff6fc0865a67a29f14.tar.gz
postgresql-1c7443521f856dfb5f6731ff6fc0865a67a29f14.zip
Fix integer-overflow problem in intarray's g_int_decompress().
An array element equal to INT_MAX gave this code indigestion, causing an infinite loop that surely ended in SIGSEGV. We fixed some nearby problems awhile ago (cf 757c5182f) but missed this. Report and diagnosis by Alexander Lakhin (bug #18273); patch by me Discussion: https://postgr.es/m/18273-9a832d1da122600c@postgresql.org
-rw-r--r--contrib/intarray/_int_gist.c10
-rw-r--r--contrib/intarray/data/test__int.data1
-rw-r--r--contrib/intarray/expected/_int.out16
3 files changed, 15 insertions, 12 deletions
diff --git a/contrib/intarray/_int_gist.c b/contrib/intarray/_int_gist.c
index 1213c5250f8..62cd9ba9794 100644
--- a/contrib/intarray/_int_gist.c
+++ b/contrib/intarray/_int_gist.c
@@ -287,8 +287,7 @@ g_int_decompress(PG_FUNCTION_ARGS)
ArrayType *in;
int lenin;
int *din;
- int i,
- j;
+ int i;
in = DatumGetArrayTypeP(entry->key);
@@ -332,9 +331,12 @@ g_int_decompress(PG_FUNCTION_ARGS)
dr = ARRPTR(r);
for (i = 0; i < lenin; i += 2)
- for (j = din[i]; j <= din[i + 1]; j++)
+ {
+ /* use int64 for j in case din[i + 1] is INT_MAX */
+ for (int64 j = din[i]; j <= din[i + 1]; j++)
if ((!i) || *(dr - 1) != j)
- *dr++ = j;
+ *dr++ = (int) j;
+ }
if (in != (ArrayType *) DatumGetPointer(entry->key))
pfree(in);
diff --git a/contrib/intarray/data/test__int.data b/contrib/intarray/data/test__int.data
index b3903d0f33a..0a7fac3c087 100644
--- a/contrib/intarray/data/test__int.data
+++ b/contrib/intarray/data/test__int.data
@@ -6998,3 +6998,4 @@
{173,208,229}
{6,22,142,267,299}
{22,122,173,245,293}
+{1,2,101,102,201,202,2147483647}
diff --git a/contrib/intarray/expected/_int.out b/contrib/intarray/expected/_int.out
index d6218df47f8..28ba5bdba99 100644
--- a/contrib/intarray/expected/_int.out
+++ b/contrib/intarray/expected/_int.out
@@ -464,13 +464,13 @@ SELECT count(*) from test__int WHERE a @@ '(20&23)|(50&68)';
SELECT count(*) from test__int WHERE a @@ '20 | !21';
count
-------
- 6566
+ 6567
(1 row)
SELECT count(*) from test__int WHERE a @@ '!20 & !21';
count
-------
- 6343
+ 6344
(1 row)
SET enable_seqscan = off; -- not all of these would use index by default
@@ -538,13 +538,13 @@ SELECT count(*) from test__int WHERE a @@ '(20&23)|(50&68)';
SELECT count(*) from test__int WHERE a @@ '20 | !21';
count
-------
- 6566
+ 6567
(1 row)
SELECT count(*) from test__int WHERE a @@ '!20 & !21';
count
-------
- 6343
+ 6344
(1 row)
INSERT INTO test__int SELECT array(SELECT x FROM generate_series(1, 1001) x); -- should fail
@@ -614,13 +614,13 @@ SELECT count(*) from test__int WHERE a @@ '(20&23)|(50&68)';
SELECT count(*) from test__int WHERE a @@ '20 | !21';
count
-------
- 6566
+ 6567
(1 row)
SELECT count(*) from test__int WHERE a @@ '!20 & !21';
count
-------
- 6343
+ 6344
(1 row)
DROP INDEX text_idx;
@@ -688,13 +688,13 @@ SELECT count(*) from test__int WHERE a @@ '(20&23)|(50&68)';
SELECT count(*) from test__int WHERE a @@ '20 | !21';
count
-------
- 6566
+ 6567
(1 row)
SELECT count(*) from test__int WHERE a @@ '!20 & !21';
count
-------
- 6343
+ 6344
(1 row)
RESET enable_seqscan;