Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 9034a2d

Browse files
committed
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 757c518) but missed this. Report and diagnosis by Alexander Lakhin (bug #18273); patch by me Discussion: https://postgr.es/m/18273-9a832d1da122600c@postgresql.org
1 parent 2a67b5a commit 9034a2d

File tree

4 files changed

+27
-22
lines changed

4 files changed

+27
-22
lines changed

contrib/intarray/_int_gist.c

+6-4
Original file line numberDiff line numberDiff line change
@@ -297,8 +297,7 @@ g_int_decompress(PG_FUNCTION_ARGS)
297297
ArrayType *in;
298298
int lenin;
299299
int *din;
300-
int i,
301-
j;
300+
int i;
302301

303302
in = DatumGetArrayTypeP(entry->key);
304303

@@ -342,9 +341,12 @@ g_int_decompress(PG_FUNCTION_ARGS)
342341
dr = ARRPTR(r);
343342

344343
for (i = 0; i < lenin; i += 2)
345-
for (j = din[i]; j <= din[i + 1]; j++)
344+
{
345+
/* use int64 for j in case din[i + 1] is INT_MAX */
346+
for (int64 j = din[i]; j <= din[i + 1]; j++)
346347
if ((!i) || *(dr - 1) != j)
347-
*dr++ = j;
348+
*dr++ = (int) j;
349+
}
348350

349351
if (in != (ArrayType *) DatumGetPointer(entry->key))
350352
pfree(in);

contrib/intarray/data/test__int.data

+1
Original file line numberDiff line numberDiff line change
@@ -6998,3 +6998,4 @@
69986998
{173,208,229}
69996999
{6,22,142,267,299}
70007000
{22,122,173,245,293}
7001+
{1,2,101,102,201,202,2147483647}

contrib/intarray/expected/_int.out

+17-16
Original file line numberDiff line numberDiff line change
@@ -483,13 +483,13 @@ SELECT count(*) from test__int WHERE a @@ '(20&23)|(50&68)';
483483
SELECT count(*) from test__int WHERE a @@ '20 | !21';
484484
count
485485
-------
486-
6566
486+
6567
487487
(1 row)
488488

489489
SELECT count(*) from test__int WHERE a @@ '!20 & !21';
490490
count
491491
-------
492-
6343
492+
6344
493493
(1 row)
494494

495495
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)';
557557
SELECT count(*) from test__int WHERE a @@ '20 | !21';
558558
count
559559
-------
560-
6566
560+
6567
561561
(1 row)
562562

563563
SELECT count(*) from test__int WHERE a @@ '!20 & !21';
564564
count
565565
-------
566-
6343
566+
6344
567567
(1 row)
568568

569569
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)';
639639
SELECT count(*) from test__int WHERE a @@ '20 | !21';
640640
count
641641
-------
642-
6566
642+
6567
643643
(1 row)
644644

645645
SELECT count(*) from test__int WHERE a @@ '!20 & !21';
646646
count
647647
-------
648-
6343
648+
6344
649649
(1 row)
650650

651651
DROP INDEX text_idx;
@@ -719,13 +719,13 @@ SELECT count(*) from test__int WHERE a @@ '(20&23)|(50&68)';
719719
SELECT count(*) from test__int WHERE a @@ '20 | !21';
720720
count
721721
-------
722-
6566
722+
6567
723723
(1 row)
724724

725725
SELECT count(*) from test__int WHERE a @@ '!20 & !21';
726726
count
727727
-------
728-
6343
728+
6344
729729
(1 row)
730730

731731
DROP INDEX text_idx;
@@ -793,13 +793,13 @@ SELECT count(*) from test__int WHERE a @@ '(20&23)|(50&68)';
793793
SELECT count(*) from test__int WHERE a @@ '20 | !21';
794794
count
795795
-------
796-
6566
796+
6567
797797
(1 row)
798798

799799
SELECT count(*) from test__int WHERE a @@ '!20 & !21';
800800
count
801801
-------
802-
6343
802+
6344
803803
(1 row)
804804

805805
DROP INDEX text_idx;
@@ -867,13 +867,13 @@ SELECT count(*) from test__int WHERE a @@ '(20&23)|(50&68)';
867867
SELECT count(*) from test__int WHERE a @@ '20 | !21';
868868
count
869869
-------
870-
6566
870+
6567
871871
(1 row)
872872

873873
SELECT count(*) from test__int WHERE a @@ '!20 & !21';
874874
count
875875
-------
876-
6343
876+
6344
877877
(1 row)
878878

879879
DROP INDEX text_idx;
@@ -889,9 +889,10 @@ DROP INDEX text_idx;
889889
-- core that would reach the same codepaths.
890890
CREATE TABLE more__int AS SELECT
891891
-- Leave alone NULLs, empty arrays and the one row that we use to test
892-
-- equality
892+
-- equality; also skip INT_MAX
893893
CASE WHEN a IS NULL OR a = '{}' OR a = '{73,23,20}' THEN a ELSE
894-
(select array_agg(u) || array_agg(u + 1000) || array_agg(u + 2000) from (select unnest(a) u) x)
894+
(select array_agg(u) || array_agg(u + 1000) || array_agg(u + 2000)
895+
from unnest(a) u where u < 2000000000)
895896
END AS a, a as b
896897
FROM test__int;
897898
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)';
958959
SELECT count(*) from more__int WHERE a @@ '20 | !21';
959960
count
960961
-------
961-
6566
962+
6567
962963
(1 row)
963964

964965
SELECT count(*) from more__int WHERE a @@ '!20 & !21';
965966
count
966967
-------
967-
6343
968+
6344
968969
(1 row)
969970

970971
RESET enable_seqscan;

contrib/intarray/sql/_int.sql

+3-2
Original file line numberDiff line numberDiff line change
@@ -209,9 +209,10 @@ DROP INDEX text_idx;
209209
-- core that would reach the same codepaths.
210210
CREATE TABLE more__int AS SELECT
211211
-- Leave alone NULLs, empty arrays and the one row that we use to test
212-
-- equality
212+
-- equality; also skip INT_MAX
213213
CASE WHEN a IS NULL OR a = '{}' OR a = '{73,23,20}' THEN a ELSE
214-
(select array_agg(u) || array_agg(u + 1000) || array_agg(u + 2000) from (select unnest(a) u) x)
214+
(select array_agg(u) || array_agg(u + 1000) || array_agg(u + 2000)
215+
from unnest(a) u where u < 2000000000)
215216
END AS a, a as b
216217
FROM test__int;
217218
CREATE INDEX ON more__int using gist (a gist__int_ops(numranges = 252));

0 commit comments

Comments
 (0)