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
This commit is contained in:
Tom Lane 2024-01-07 15:19:50 -05:00
parent 72d5b27763
commit 1c7443521f
3 changed files with 15 additions and 12 deletions

View File

@ -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);

View File

@ -6998,3 +6998,4 @@
{173,208,229}
{6,22,142,267,299}
{22,122,173,245,293}
{1,2,101,102,201,202,2147483647}

View File

@ -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;