aboutsummaryrefslogtreecommitdiff
path: root/contrib/intarray/_int_tool.c
diff options
context:
space:
mode:
authorAndrew Gierth <rhodiumtoad@postgresql.org>2018-11-23 23:56:39 +0000
committerAndrew Gierth <rhodiumtoad@postgresql.org>2018-11-24 08:39:58 +0000
commitf0bfc7a2b13a6cd48b6cea253b0e9f918e457c6d (patch)
treeda8281645c25c81e39e3d9054abb7279ada737a3 /contrib/intarray/_int_tool.c
parent4dc94485f57a56ce2838136cff73bc80265f04c9 (diff)
downloadpostgresql-f0bfc7a2b13a6cd48b6cea253b0e9f918e457c6d.tar.gz
postgresql-f0bfc7a2b13a6cd48b6cea253b0e9f918e457c6d.zip
Avoid crashes in contrib/intarray gist__int_ops (bug #15518)
1. Integer overflow in internal_size could result in memory corruption in decompression since a zero-length array would be allocated and then written to. This leads to crashes or corruption when traversing an index which has been populated with sufficiently sparse values. Fix by using int64 for computations and checking for overflow. 2. Integer overflow in g_int_compress could cause pessimal merge choices, resulting in unnecessarily large ranges (which would in turn trigger issue 1 above). Fix by using int64 again. 3. Even without overflow, array sizes could become large enough to cause unexplained memory allocation errors. Fix by capping the sizes to a safe limit and report actual errors pointing at gist__intbig_ops as needed. 4. Large inputs to the compression function always consist of large runs of consecutive integers, and the compression loop was processing these one at a time in an O(N^2) manner with a lot of overhead. The expected runtime of this function could easily exceed 6 months for a single call as a result. Fix by performing a linear-time first pass, which reduces the worst case to something on the order of seconds. Backpatch all the way, since this has been wrong forever. Per bug #15518 from report from irc user "dymk", analysis and patch by me. Discussion: https://postgr.es/m/15518-799e426c3b4f8358@postgresql.org
Diffstat (limited to 'contrib/intarray/_int_tool.c')
-rw-r--r--contrib/intarray/_int_tool.c12
1 files changed, 8 insertions, 4 deletions
diff --git a/contrib/intarray/_int_tool.c b/contrib/intarray/_int_tool.c
index 3c52912bbf4..b2ca0573f26 100644
--- a/contrib/intarray/_int_tool.c
+++ b/contrib/intarray/_int_tool.c
@@ -3,6 +3,8 @@
*/
#include "postgres.h"
+#include <limits.h>
+
#include "catalog/pg_type.h"
#include "_int.h"
@@ -277,16 +279,18 @@ copy_intArrayType(ArrayType *a)
int
internal_size(int *a, int len)
{
- int i,
- size = 0;
+ int i;
+ int64 size = 0;
for (i = 0; i < len; i += 2)
{
if (!i || a[i] != a[i - 1]) /* do not count repeated range */
- size += a[i + 1] - a[i] + 1;
+ size += (int64)(a[i + 1]) - (int64)(a[i]) + 1;
}
- return size;
+ if (size > (int64)INT_MAX || size < (int64)INT_MIN)
+ return -1; /* overflow */
+ return (int) size;
}
/* unique-ify elements of r in-place ... r must be sorted already */