Fix integer-overflow problem in intarray's g_int_decompress().
authorTom Lane <[email protected]>
Sun, 7 Jan 2024 20:19:50 +0000 (15:19 -0500)
committerTom Lane <[email protected]>
Sun, 7 Jan 2024 20:19:50 +0000 (15:19 -0500)
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

contrib/intarray/_int_gist.c
contrib/intarray/data/test__int.data
contrib/intarray/expected/_int.out

index 1213c5250f8fa84fc128d745feb00673113eca1e..62cd9ba9794bd8e721603b7ffaaa5c8098a4c7b2 100644 (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);
index b3903d0f33a60d2bf1a0b5ccbc797a2ddcae9d6b..0a7fac3c08722d6229040860c2ca18f488d35fe0 100644 (file)
 {173,208,229}
 {6,22,142,267,299}
 {22,122,173,245,293}
+{1,2,101,102,201,202,2147483647}
index d6218df47f8e2aeb317b12cccd40f6df4b30a3a1..28ba5bdba99fe963e61a33f8b9a0436594f52512 100644 (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;