mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-11-21 03:13:05 +08:00
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:
parent
714a987bc1
commit
cf6f802bf5
@ -297,8 +297,7 @@ g_int_decompress(PG_FUNCTION_ARGS)
|
||||
ArrayType *in;
|
||||
int lenin;
|
||||
int *din;
|
||||
int i,
|
||||
j;
|
||||
int i;
|
||||
|
||||
in = DatumGetArrayTypeP(entry->key);
|
||||
|
||||
@ -342,9 +341,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);
|
||||
|
@ -6998,3 +6998,4 @@
|
||||
{173,208,229}
|
||||
{6,22,142,267,299}
|
||||
{22,122,173,245,293}
|
||||
{1,2,101,102,201,202,2147483647}
|
||||
|
@ -483,13 +483,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
|
||||
@ -557,13 +557,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
|
||||
@ -639,13 +639,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;
|
||||
@ -719,13 +719,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;
|
||||
@ -793,13 +793,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;
|
||||
@ -867,13 +867,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;
|
||||
@ -889,9 +889,10 @@ DROP INDEX text_idx;
|
||||
-- core that would reach the same codepaths.
|
||||
CREATE TABLE more__int AS SELECT
|
||||
-- Leave alone NULLs, empty arrays and the one row that we use to test
|
||||
-- equality
|
||||
-- equality; also skip INT_MAX
|
||||
CASE WHEN a IS NULL OR a = '{}' OR a = '{73,23,20}' THEN a ELSE
|
||||
(select array_agg(u) || array_agg(u + 1000) || array_agg(u + 2000) from (select unnest(a) u) x)
|
||||
(select array_agg(u) || array_agg(u + 1000) || array_agg(u + 2000)
|
||||
from unnest(a) u where u < 2000000000)
|
||||
END AS a, a as b
|
||||
FROM test__int;
|
||||
CREATE INDEX ON more__int using gist (a gist__int_ops(numranges = 252));
|
||||
@ -958,13 +959,13 @@ SELECT count(*) from more__int WHERE a @@ '(20&23)|(50&68)';
|
||||
SELECT count(*) from more__int WHERE a @@ '20 | !21';
|
||||
count
|
||||
-------
|
||||
6566
|
||||
6567
|
||||
(1 row)
|
||||
|
||||
SELECT count(*) from more__int WHERE a @@ '!20 & !21';
|
||||
count
|
||||
-------
|
||||
6343
|
||||
6344
|
||||
(1 row)
|
||||
|
||||
RESET enable_seqscan;
|
||||
|
@ -209,9 +209,10 @@ DROP INDEX text_idx;
|
||||
-- core that would reach the same codepaths.
|
||||
CREATE TABLE more__int AS SELECT
|
||||
-- Leave alone NULLs, empty arrays and the one row that we use to test
|
||||
-- equality
|
||||
-- equality; also skip INT_MAX
|
||||
CASE WHEN a IS NULL OR a = '{}' OR a = '{73,23,20}' THEN a ELSE
|
||||
(select array_agg(u) || array_agg(u + 1000) || array_agg(u + 2000) from (select unnest(a) u) x)
|
||||
(select array_agg(u) || array_agg(u + 1000) || array_agg(u + 2000)
|
||||
from unnest(a) u where u < 2000000000)
|
||||
END AS a, a as b
|
||||
FROM test__int;
|
||||
CREATE INDEX ON more__int using gist (a gist__int_ops(numranges = 252));
|
||||
|
Loading…
Reference in New Issue
Block a user