On Fri, Oct 16, 2015 at 11:29 PM, Michael Paquier wrote:
> Well, I have played a bit with this patch and rebased it as attached.
> One major change is the use of the variables PG_INT* that have been
> added in 62e2a8d. Some places were not updated with those new checks,
> in majority a couple of routines in int.c (I haven't finished
> monitoring the whole code though). Also, I haven't played yet with my
> compilers to optimize away some of the checks and break them, but I'll
> give it a try with clang and gcc. For now, I guess that this patch is
> a good thing to begin with though, I have checked that code compiles
> and regression tests pass.

Hm. Looking at the options of clang
(http://clang.llvm.org/docs/UsersManual.html), there is no actual
equivalent of fno-wrapv and strict-overflow, there are a couple of
sanitizer functions though (-fsanitize=unsigned-integer-overflow
-fsanitize=signed-integer-overflow) that can be used at run time, but
that's not really useful for us.

I also looked at the definition of SHRT_MIN/MAX in a couple of places
(OSX, Linux, MinGW, Solaris, OpenBSD, FreeBSD, MSVC), and they are
always set as respectively -7fff-1 and 7fff. Hence do we really need
to worry about those two having potentially a different length, are
there opinions about having customs PG_SHRT_MIN/PG_SHRT_MAX in c.h?

Except that, attached is a result of all the hacking I have been doing
regarding this item:
- Addition of some macros to check overflows for INT16
- Addition of a couple of regression tests (Does testing int2inc &
friends make sense?)
- Addition of consistent overflow checks in more code paths, previous
patch missing a couple of places in int8.c, int.c and btree_gist (+
alpha). I have screened the code for existing "out of range" errors.
I'll add that to the next CF, perhaps this will interest somebody.
Regards,
-- 
Michael
diff --git a/contrib/btree_gist/btree_int2.c b/contrib/btree_gist/btree_int2.c
index 54dc1cc..202bd21 100644
--- a/contrib/btree_gist/btree_int2.c
+++ b/contrib/btree_gist/btree_int2.c
@@ -102,7 +102,7 @@ int2_dist(PG_FUNCTION_ARGS)
 	ra = Abs(r);
 
 	/* Overflow check. */
-	if (ra < 0 || (!SAMESIGN(a, b) && !SAMESIGN(r, a)))
+	if (ra < 0 || PG_INT16_SUB_OVERFLOWS(a, b))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("smallint out of range")));
diff --git a/contrib/btree_gist/btree_int4.c b/contrib/btree_gist/btree_int4.c
index ddbcf52..890a7d4 100644
--- a/contrib/btree_gist/btree_int4.c
+++ b/contrib/btree_gist/btree_int4.c
@@ -103,7 +103,7 @@ int4_dist(PG_FUNCTION_ARGS)
 	ra = Abs(r);
 
 	/* Overflow check. */
-	if (ra < 0 || (!SAMESIGN(a, b) && !SAMESIGN(r, a)))
+	if (ra < 0 || PG_INT32_SUB_OVERFLOWS(a, b))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("integer out of range")));
diff --git a/contrib/btree_gist/btree_int8.c b/contrib/btree_gist/btree_int8.c
index 44bf69a..91d4972 100644
--- a/contrib/btree_gist/btree_int8.c
+++ b/contrib/btree_gist/btree_int8.c
@@ -103,7 +103,7 @@ int8_dist(PG_FUNCTION_ARGS)
 	ra = Abs(r);
 
 	/* Overflow check. */
-	if (ra < 0 || (!SAMESIGN(a, b) && !SAMESIGN(r, a)))
+	if (ra < 0 || PG_INT64_SUB_OVERFLOWS(a, b))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("bigint out of range")));
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index 29f058c..9b4b890 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -3185,7 +3185,8 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext,
 				/* Get sub-array details from first member */
 				elem_ndims = this_ndims;
 				ndims = elem_ndims + 1;
-				if (ndims <= 0 || ndims > MAXDIM)
+
+				if (PG_INT32_ADD_OVERFLOWS(elem_ndims,1) || ndims > MAXDIM)
 					ereport(ERROR,
 							(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
 						  errmsg("number of array dimensions (%d) exceeds " \
diff --git a/src/backend/utils/adt/array_userfuncs.c b/src/backend/utils/adt/array_userfuncs.c
index c14ea23..6ad97da 100644
--- a/src/backend/utils/adt/array_userfuncs.c
+++ b/src/backend/utils/adt/array_userfuncs.c
@@ -113,8 +113,9 @@ array_append(PG_FUNCTION_ARGS)
 		ub = dimv[0] + lb[0] - 1;
 		indx = ub + 1;
 
-		/* overflow? */
-		if (indx < ub)
+		/* check for overflow in upper bound (indx + 1) */
+		if (PG_INT32_ADD_OVERFLOWS(dimv[0] ,lb[0]) ||
+			PG_INT32_ADD_OVERFLOWS(dimv[0] + lb[0], 1))
 			ereport(ERROR,
 					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 					 errmsg("integer out of range")));
@@ -168,7 +169,7 @@ array_prepend(PG_FUNCTION_ARGS)
 		lb0 = lb[0];
 
 		/* overflow? */
-		if (indx > lb[0])
+		if (PG_INT32_ADD_OVERFLOWS(lb[0], -1))
 			ereport(ERROR,
 					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 					 errmsg("integer out of range")));
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index 4e927d8..cc4c570 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -2763,12 +2763,12 @@ width_bucket_float8(PG_FUNCTION_ARGS)
 			result = 0;
 		else if (operand >= bound2)
 		{
-			result = count + 1;
 			/* check for overflow */
-			if (result < count)
+			if (PG_INT32_ADD_OVERFLOWS(count, 1))
 				ereport(ERROR,
 						(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 						 errmsg("integer out of range")));
+			result = count + 1;
 		}
 		else
 			result = ((float8) count * (operand - bound1) / (bound2 - bound1)) + 1;
@@ -2779,12 +2779,12 @@ width_bucket_float8(PG_FUNCTION_ARGS)
 			result = 0;
 		else if (operand <= bound2)
 		{
-			result = count + 1;
 			/* check for overflow */
-			if (result < count)
+			if (PG_INT32_ADD_OVERFLOWS(count, 1))
 				ereport(ERROR,
 						(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 						 errmsg("integer out of range")));
+			result = count + 1;
 		}
 		else
 			result = ((float8) count * (bound1 - operand) / (bound1 - bound2)) + 1;
diff --git a/src/backend/utils/adt/int.c b/src/backend/utils/adt/int.c
index 1a91b29..3c0572c 100644
--- a/src/backend/utils/adt/int.c
+++ b/src/backend/utils/adt/int.c
@@ -613,15 +613,13 @@ Datum
 int4um(PG_FUNCTION_ARGS)
 {
 	int32		arg = PG_GETARG_INT32(0);
-	int32		result;
 
-	result = -arg;
 	/* overflow check (needed for INT_MIN) */
-	if (arg != 0 && SAMESIGN(result, arg))
+	if (arg == PG_INT32_MIN)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("integer out of range")));
-	PG_RETURN_INT32(result);
+	PG_RETURN_INT32(-arg);
 }
 
 Datum
@@ -637,20 +635,14 @@ int4pl(PG_FUNCTION_ARGS)
 {
 	int32		arg1 = PG_GETARG_INT32(0);
 	int32		arg2 = PG_GETARG_INT32(1);
-	int32		result;
 
-	result = arg1 + arg2;
-
-	/*
-	 * Overflow check.  If the inputs are of different signs then their sum
-	 * cannot overflow.  If the inputs are of the same sign, their sum had
-	 * better be that sign too.
-	 */
-	if (SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
+	/* Overflow check */
+	if (PG_INT32_ADD_OVERFLOWS(arg1, arg2))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("integer out of range")));
-	PG_RETURN_INT32(result);
+
+	PG_RETURN_INT32(arg1 + arg2);
 }
 
 Datum
@@ -658,20 +650,14 @@ int4mi(PG_FUNCTION_ARGS)
 {
 	int32		arg1 = PG_GETARG_INT32(0);
 	int32		arg2 = PG_GETARG_INT32(1);
-	int32		result;
-
-	result = arg1 - arg2;
 
-	/*
-	 * Overflow check.  If the inputs are of the same sign then their
-	 * difference cannot overflow.  If they are of different signs then the
-	 * result should be of the same sign as the first input.
-	 */
-	if (!SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
+	/* Overflow check */
+	if (PG_INT32_SUB_OVERFLOWS(arg1, arg2))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("integer out of range")));
-	PG_RETURN_INT32(result);
+
+	PG_RETURN_INT32(arg1 - arg2);
 }
 
 Datum
@@ -679,30 +665,14 @@ int4mul(PG_FUNCTION_ARGS)
 {
 	int32		arg1 = PG_GETARG_INT32(0);
 	int32		arg2 = PG_GETARG_INT32(1);
-	int32		result;
 
-	result = arg1 * arg2;
-
-	/*
-	 * Overflow check.  We basically check to see if result / arg2 gives arg1
-	 * again.  There are two cases where this fails: arg2 = 0 (which cannot
-	 * overflow) and arg1 = INT_MIN, arg2 = -1 (where the division itself will
-	 * overflow and thus incorrectly match).
-	 *
-	 * Since the division is likely much more expensive than the actual
-	 * multiplication, we'd like to skip it where possible.  The best bang for
-	 * the buck seems to be to check whether both inputs are in the int16
-	 * range; if so, no overflow is possible.
-	 */
-	if (!(arg1 >= (int32) SHRT_MIN && arg1 <= (int32) SHRT_MAX &&
-		  arg2 >= (int32) SHRT_MIN && arg2 <= (int32) SHRT_MAX) &&
-		arg2 != 0 &&
-		((arg2 == -1 && arg1 < 0 && result < 0) ||
-		 result / arg2 != arg1))
+	/* Overflow check */
+	if (PG_INT32_MUL_OVERFLOWS(arg1, arg2))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("integer out of range")));
-	PG_RETURN_INT32(result);
+
+	PG_RETURN_INT32(arg1 * arg2);
 }
 
 Datum
@@ -729,12 +699,12 @@ int4div(PG_FUNCTION_ARGS)
 	 */
 	if (arg2 == -1)
 	{
-		result = -arg1;
 		/* overflow check (needed for INT_MIN) */
-		if (arg1 != 0 && SAMESIGN(result, arg1))
+		if (arg1 == PG_INT32_MIN)
 			ereport(ERROR,
 					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 					 errmsg("integer out of range")));
+		result = -arg1;
 		PG_RETURN_INT32(result);
 	}
 
@@ -749,31 +719,26 @@ Datum
 int4inc(PG_FUNCTION_ARGS)
 {
 	int32		arg = PG_GETARG_INT32(0);
-	int32		result;
 
-	result = arg + 1;
-	/* Overflow check */
-	if (arg > 0 && result < 0)
+	if (PG_INT32_ADD_OVERFLOWS(arg, 1))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("integer out of range")));
 
-	PG_RETURN_INT32(result);
+	PG_RETURN_INT32(arg + 1);
 }
 
 Datum
 int2um(PG_FUNCTION_ARGS)
 {
 	int16		arg = PG_GETARG_INT16(0);
-	int16		result;
 
-	result = -arg;
-	/* overflow check (needed for SHRT_MIN) */
-	if (arg != 0 && SAMESIGN(result, arg))
+	if (arg == PG_INT16_MIN)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("smallint out of range")));
-	PG_RETURN_INT16(result);
+
+	PG_RETURN_INT16(-arg);
 }
 
 Datum
@@ -789,20 +754,13 @@ int2pl(PG_FUNCTION_ARGS)
 {
 	int16		arg1 = PG_GETARG_INT16(0);
 	int16		arg2 = PG_GETARG_INT16(1);
-	int16		result;
 
-	result = arg1 + arg2;
-
-	/*
-	 * Overflow check.  If the inputs are of different signs then their sum
-	 * cannot overflow.  If the inputs are of the same sign, their sum had
-	 * better be that sign too.
-	 */
-	if (SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
+	if (PG_INT16_ADD_OVERFLOWS(arg1, arg2))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("smallint out of range")));
-	PG_RETURN_INT16(result);
+
+	PG_RETURN_INT16(arg1 + arg2);
 }
 
 Datum
@@ -810,20 +768,13 @@ int2mi(PG_FUNCTION_ARGS)
 {
 	int16		arg1 = PG_GETARG_INT16(0);
 	int16		arg2 = PG_GETARG_INT16(1);
-	int16		result;
-
-	result = arg1 - arg2;
 
-	/*
-	 * Overflow check.  If the inputs are of the same sign then their
-	 * difference cannot overflow.  If they are of different signs then the
-	 * result should be of the same sign as the first input.
-	 */
-	if (!SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
+	if (PG_INT16_SUB_OVERFLOWS(arg1, arg2))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("smallint out of range")));
-	PG_RETURN_INT16(result);
+
+	PG_RETURN_INT16(arg1 - arg2);
 }
 
 Datum
@@ -831,20 +782,13 @@ int2mul(PG_FUNCTION_ARGS)
 {
 	int16		arg1 = PG_GETARG_INT16(0);
 	int16		arg2 = PG_GETARG_INT16(1);
-	int32		result32;
-
-	/*
-	 * The most practical way to detect overflow is to do the arithmetic in
-	 * int32 (so that the result can't overflow) and then do a range check.
-	 */
-	result32 = (int32) arg1 *(int32) arg2;
 
-	if (result32 < SHRT_MIN || result32 > SHRT_MAX)
+	if (PG_INT16_MUL_OVERFLOWS(arg1, arg2))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("smallint out of range")));
 
-	PG_RETURN_INT16((int16) result32);
+	PG_RETURN_INT16(arg1 * arg2);
 }
 
 Datum
@@ -871,12 +815,12 @@ int2div(PG_FUNCTION_ARGS)
 	 */
 	if (arg2 == -1)
 	{
-		result = -arg1;
 		/* overflow check (needed for SHRT_MIN) */
-		if (arg1 != 0 && SAMESIGN(result, arg1))
+		if (arg1 == PG_INT16_MIN)
 			ereport(ERROR,
 					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 					 errmsg("smallint out of range")));
+		result = -arg1;
 		PG_RETURN_INT16(result);
 	}
 
@@ -892,20 +836,12 @@ int24pl(PG_FUNCTION_ARGS)
 {
 	int16		arg1 = PG_GETARG_INT16(0);
 	int32		arg2 = PG_GETARG_INT32(1);
-	int32		result;
-
-	result = arg1 + arg2;
 
-	/*
-	 * Overflow check.  If the inputs are of different signs then their sum
-	 * cannot overflow.  If the inputs are of the same sign, their sum had
-	 * better be that sign too.
-	 */
-	if (SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
+	if (PG_INT32_ADD_OVERFLOWS(arg1, arg2))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("integer out of range")));
-	PG_RETURN_INT32(result);
+	PG_RETURN_INT32(arg1 + arg2);
 }
 
 Datum
@@ -913,20 +849,12 @@ int24mi(PG_FUNCTION_ARGS)
 {
 	int16		arg1 = PG_GETARG_INT16(0);
 	int32		arg2 = PG_GETARG_INT32(1);
-	int32		result;
-
-	result = arg1 - arg2;
 
-	/*
-	 * Overflow check.  If the inputs are of the same sign then their
-	 * difference cannot overflow.  If they are of different signs then the
-	 * result should be of the same sign as the first input.
-	 */
-	if (!SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
+	if (PG_INT32_SUB_OVERFLOWS(arg1, arg2))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("integer out of range")));
-	PG_RETURN_INT32(result);
+	PG_RETURN_INT32(arg1 - arg2);
 }
 
 Datum
@@ -934,26 +862,12 @@ int24mul(PG_FUNCTION_ARGS)
 {
 	int16		arg1 = PG_GETARG_INT16(0);
 	int32		arg2 = PG_GETARG_INT32(1);
-	int32		result;
 
-	result = arg1 * arg2;
-
-	/*
-	 * Overflow check.  We basically check to see if result / arg2 gives arg1
-	 * again.  There is one case where this fails: arg2 = 0 (which cannot
-	 * overflow).
-	 *
-	 * Since the division is likely much more expensive than the actual
-	 * multiplication, we'd like to skip it where possible.  The best bang for
-	 * the buck seems to be to check whether both inputs are in the int16
-	 * range; if so, no overflow is possible.
-	 */
-	if (!(arg2 >= (int32) SHRT_MIN && arg2 <= (int32) SHRT_MAX) &&
-		result / arg2 != arg1)
+	if (PG_INT32_MUL_OVERFLOWS(arg1, arg2))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("integer out of range")));
-	PG_RETURN_INT32(result);
+	PG_RETURN_INT32(arg1 * arg2);
 }
 
 Datum
@@ -980,20 +894,12 @@ int42pl(PG_FUNCTION_ARGS)
 {
 	int32		arg1 = PG_GETARG_INT32(0);
 	int16		arg2 = PG_GETARG_INT16(1);
-	int32		result;
 
-	result = arg1 + arg2;
-
-	/*
-	 * Overflow check.  If the inputs are of different signs then their sum
-	 * cannot overflow.  If the inputs are of the same sign, their sum had
-	 * better be that sign too.
-	 */
-	if (SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
+	if (PG_INT32_ADD_OVERFLOWS(arg1, arg2))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("integer out of range")));
-	PG_RETURN_INT32(result);
+	PG_RETURN_INT32(arg1 + arg2);
 }
 
 Datum
@@ -1001,20 +907,12 @@ int42mi(PG_FUNCTION_ARGS)
 {
 	int32		arg1 = PG_GETARG_INT32(0);
 	int16		arg2 = PG_GETARG_INT16(1);
-	int32		result;
-
-	result = arg1 - arg2;
 
-	/*
-	 * Overflow check.  If the inputs are of the same sign then their
-	 * difference cannot overflow.  If they are of different signs then the
-	 * result should be of the same sign as the first input.
-	 */
-	if (!SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
+	if (PG_INT32_SUB_OVERFLOWS(arg1, arg2))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("integer out of range")));
-	PG_RETURN_INT32(result);
+	PG_RETURN_INT32(arg1 - arg2);
 }
 
 Datum
@@ -1022,26 +920,12 @@ int42mul(PG_FUNCTION_ARGS)
 {
 	int32		arg1 = PG_GETARG_INT32(0);
 	int16		arg2 = PG_GETARG_INT16(1);
-	int32		result;
-
-	result = arg1 * arg2;
 
-	/*
-	 * Overflow check.  We basically check to see if result / arg1 gives arg2
-	 * again.  There is one case where this fails: arg1 = 0 (which cannot
-	 * overflow).
-	 *
-	 * Since the division is likely much more expensive than the actual
-	 * multiplication, we'd like to skip it where possible.  The best bang for
-	 * the buck seems to be to check whether both inputs are in the int16
-	 * range; if so, no overflow is possible.
-	 */
-	if (!(arg1 >= (int32) SHRT_MIN && arg1 <= (int32) SHRT_MAX) &&
-		result / arg1 != arg2)
+	if (PG_INT32_MUL_OVERFLOWS(arg1, arg2))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("integer out of range")));
-	PG_RETURN_INT32(result);
+	PG_RETURN_INT32(arg1 * arg2);
 }
 
 Datum
@@ -1068,12 +952,12 @@ int42div(PG_FUNCTION_ARGS)
 	 */
 	if (arg2 == -1)
 	{
-		result = -arg1;
 		/* overflow check (needed for INT_MIN) */
-		if (arg1 != 0 && SAMESIGN(result, arg1))
+		if (arg1 == PG_INT32_MIN)
 			ereport(ERROR,
 					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 					 errmsg("integer out of range")));
+		result = -arg1;
 		PG_RETURN_INT32(result);
 	}
 
@@ -1151,12 +1035,12 @@ int4abs(PG_FUNCTION_ARGS)
 	int32		arg1 = PG_GETARG_INT32(0);
 	int32		result;
 
-	result = (arg1 < 0) ? -arg1 : arg1;
 	/* overflow check (needed for INT_MIN) */
-	if (result < 0)
+	if (arg1 == PG_INT32_MIN)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("integer out of range")));
+	result = (arg1 < 0) ? -arg1 : arg1;
 	PG_RETURN_INT32(result);
 }
 
@@ -1166,12 +1050,13 @@ int2abs(PG_FUNCTION_ARGS)
 	int16		arg1 = PG_GETARG_INT16(0);
 	int16		result;
 
-	result = (arg1 < 0) ? -arg1 : arg1;
 	/* overflow check (needed for SHRT_MIN) */
-	if (result < 0)
+	if (arg1 == PG_INT16_MIN)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("smallint out of range")));
+	result = (arg1 < 0) ? -arg1 : arg1;
+
 	PG_RETURN_INT16(result);
 }
 
diff --git a/src/backend/utils/adt/int8.c b/src/backend/utils/adt/int8.c
index 63a4fbb..eb5a5bb 100644
--- a/src/backend/utils/adt/int8.c
+++ b/src/backend/utils/adt/int8.c
@@ -102,19 +102,19 @@ scanint8(const char *str, bool errorOK, int64 *result)
 	/* process digits */
 	while (*ptr && isdigit((unsigned char) *ptr))
 	{
-		int64		newtmp = tmp * 10 + (*ptr++ - '0');
-
-		if ((newtmp / 10) != tmp)		/* overflow? */
+		if (PG_INT64_MUL_OVERFLOWS(tmp, 10) ||
+			PG_INT64_ADD_OVERFLOWS(tmp * 10, *ptr - '0'))
 		{
 			if (errorOK)
 				return false;
 			else
 				ereport(ERROR,
 						(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
-					   errmsg("value \"%s\" is out of range for type bigint",
-							  str)));
+						 errmsg("value \"%s\" is out of range for type bigint",
+								str)));
 		}
-		tmp = newtmp;
+
+		tmp = tmp * 10 + (*ptr++ - '0');
 	}
 
 gotdigits:
@@ -490,15 +490,12 @@ Datum
 int8um(PG_FUNCTION_ARGS)
 {
 	int64		arg = PG_GETARG_INT64(0);
-	int64		result;
 
-	result = -arg;
-	/* overflow check (needed for INT64_MIN) */
-	if (arg != 0 && SAMESIGN(result, arg))
+	if (arg == PG_INT64_MIN)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("bigint out of range")));
-	PG_RETURN_INT64(result);
+	PG_RETURN_INT64(-arg);
 }
 
 Datum
@@ -516,17 +513,13 @@ int8pl(PG_FUNCTION_ARGS)
 	int64		arg2 = PG_GETARG_INT64(1);
 	int64		result;
 
-	result = arg1 + arg2;
-
-	/*
-	 * Overflow check.  If the inputs are of different signs then their sum
-	 * cannot overflow.  If the inputs are of the same sign, their sum had
-	 * better be that sign too.
-	 */
-	if (SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
+	/* Overflow check */
+	if (PG_INT64_ADD_OVERFLOWS(arg1, arg2))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("bigint out of range")));
+
+	result = arg1 + arg2;
 	PG_RETURN_INT64(result);
 }
 
@@ -535,20 +528,13 @@ int8mi(PG_FUNCTION_ARGS)
 {
 	int64		arg1 = PG_GETARG_INT64(0);
 	int64		arg2 = PG_GETARG_INT64(1);
-	int64		result;
-
-	result = arg1 - arg2;
 
-	/*
-	 * Overflow check.  If the inputs are of the same sign then their
-	 * difference cannot overflow.  If they are of different signs then the
-	 * result should be of the same sign as the first input.
-	 */
-	if (!SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
+	if (PG_INT64_SUB_OVERFLOWS(arg1, arg2))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("bigint out of range")));
-	PG_RETURN_INT64(result);
+
+	PG_RETURN_INT64(arg1 - arg2);
 }
 
 Datum
@@ -556,31 +542,12 @@ int8mul(PG_FUNCTION_ARGS)
 {
 	int64		arg1 = PG_GETARG_INT64(0);
 	int64		arg2 = PG_GETARG_INT64(1);
-	int64		result;
 
-	result = arg1 * arg2;
-
-	/*
-	 * Overflow check.  We basically check to see if result / arg2 gives arg1
-	 * again.  There are two cases where this fails: arg2 = 0 (which cannot
-	 * overflow) and arg1 = INT64_MIN, arg2 = -1 (where the division itself
-	 * will overflow and thus incorrectly match).
-	 *
-	 * Since the division is likely much more expensive than the actual
-	 * multiplication, we'd like to skip it where possible.  The best bang for
-	 * the buck seems to be to check whether both inputs are in the int32
-	 * range; if so, no overflow is possible.
-	 */
-	if (arg1 != (int64) ((int32) arg1) || arg2 != (int64) ((int32) arg2))
-	{
-		if (arg2 != 0 &&
-			((arg2 == -1 && arg1 < 0 && result < 0) ||
-			 result / arg2 != arg1))
-			ereport(ERROR,
-					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
-					 errmsg("bigint out of range")));
-	}
-	PG_RETURN_INT64(result);
+	if (PG_INT64_MUL_OVERFLOWS(arg1, arg2))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("bigint out of range")));
+	PG_RETURN_INT64(arg1 * arg2);
 }
 
 Datum
@@ -607,12 +574,12 @@ int8div(PG_FUNCTION_ARGS)
 	 */
 	if (arg2 == -1)
 	{
-		result = -arg1;
-		/* overflow check (needed for INT64_MIN) */
-		if (arg1 != 0 && SAMESIGN(result, arg1))
+		if (arg1 == PG_INT64_MIN)
 			ereport(ERROR,
 					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 					 errmsg("bigint out of range")));
+
+		result = -arg1;
 		PG_RETURN_INT64(result);
 	}
 
@@ -632,12 +599,12 @@ int8abs(PG_FUNCTION_ARGS)
 	int64		arg1 = PG_GETARG_INT64(0);
 	int64		result;
 
-	result = (arg1 < 0) ? -arg1 : arg1;
-	/* overflow check (needed for INT64_MIN) */
-	if (result < 0)
+	if (arg1 == PG_INT64_MIN)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("bigint out of range")));
+
+	result = (arg1 < 0) ? -arg1 : arg1;
 	PG_RETURN_INT64(result);
 }
 
@@ -687,15 +654,13 @@ int8inc(PG_FUNCTION_ARGS)
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
 		int64	   *arg = (int64 *) PG_GETARG_POINTER(0);
-		int64		result;
+		int64		result = *arg;
 
-		result = *arg + 1;
-		/* Overflow check */
-		if (result < 0 && *arg > 0)
+		if (PG_INT64_ADD_OVERFLOWS(result, 1))
 			ereport(ERROR,
 					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 					 errmsg("bigint out of range")));
-
+		result += 1;
 		*arg = result;
 		PG_RETURN_POINTER(arg);
 	}
@@ -704,16 +669,12 @@ int8inc(PG_FUNCTION_ARGS)
 	{
 		/* Not called as an aggregate, so just do it the dumb way */
 		int64		arg = PG_GETARG_INT64(0);
-		int64		result;
 
-		result = arg + 1;
-		/* Overflow check */
-		if (result < 0 && arg > 0)
+		if (PG_INT64_ADD_OVERFLOWS(arg, 1))
 			ereport(ERROR,
 					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 					 errmsg("bigint out of range")));
-
-		PG_RETURN_INT64(result);
+		PG_RETURN_INT64(arg + 1);
 	}
 }
 
@@ -819,20 +780,12 @@ int84pl(PG_FUNCTION_ARGS)
 {
 	int64		arg1 = PG_GETARG_INT64(0);
 	int32		arg2 = PG_GETARG_INT32(1);
-	int64		result;
 
-	result = arg1 + arg2;
-
-	/*
-	 * Overflow check.  If the inputs are of different signs then their sum
-	 * cannot overflow.  If the inputs are of the same sign, their sum had
-	 * better be that sign too.
-	 */
-	if (SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
+	if (PG_INT64_ADD_OVERFLOWS(arg1, arg2))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("bigint out of range")));
-	PG_RETURN_INT64(result);
+	PG_RETURN_INT64(arg1 + (int64) arg2);
 }
 
 Datum
@@ -840,20 +793,12 @@ int84mi(PG_FUNCTION_ARGS)
 {
 	int64		arg1 = PG_GETARG_INT64(0);
 	int32		arg2 = PG_GETARG_INT32(1);
-	int64		result;
-
-	result = arg1 - arg2;
 
-	/*
-	 * Overflow check.  If the inputs are of the same sign then their
-	 * difference cannot overflow.  If they are of different signs then the
-	 * result should be of the same sign as the first input.
-	 */
-	if (!SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
+	if (PG_INT64_SUB_OVERFLOWS(arg1, arg2))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("bigint out of range")));
-	PG_RETURN_INT64(result);
+	PG_RETURN_INT64(arg1 - (int64) arg2);
 }
 
 Datum
@@ -861,26 +806,12 @@ int84mul(PG_FUNCTION_ARGS)
 {
 	int64		arg1 = PG_GETARG_INT64(0);
 	int32		arg2 = PG_GETARG_INT32(1);
-	int64		result;
-
-	result = arg1 * arg2;
 
-	/*
-	 * Overflow check.  We basically check to see if result / arg1 gives arg2
-	 * again.  There is one case where this fails: arg1 = 0 (which cannot
-	 * overflow).
-	 *
-	 * Since the division is likely much more expensive than the actual
-	 * multiplication, we'd like to skip it where possible.  The best bang for
-	 * the buck seems to be to check whether both inputs are in the int32
-	 * range; if so, no overflow is possible.
-	 */
-	if (arg1 != (int64) ((int32) arg1) &&
-		result / arg1 != arg2)
+	if (PG_INT64_MUL_OVERFLOWS(arg1, arg2))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("bigint out of range")));
-	PG_RETURN_INT64(result);
+	PG_RETURN_INT64(arg1 * (int64) arg2);
 }
 
 Datum
@@ -907,13 +838,11 @@ int84div(PG_FUNCTION_ARGS)
 	 */
 	if (arg2 == -1)
 	{
-		result = -arg1;
-		/* overflow check (needed for INT64_MIN) */
-		if (arg1 != 0 && SAMESIGN(result, arg1))
+		if (arg1 == PG_INT64_MIN)
 			ereport(ERROR,
 					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 					 errmsg("bigint out of range")));
-		PG_RETURN_INT64(result);
+		PG_RETURN_INT64(-arg1);
 	}
 
 	/* No overflow is possible */
@@ -928,20 +857,12 @@ int48pl(PG_FUNCTION_ARGS)
 {
 	int32		arg1 = PG_GETARG_INT32(0);
 	int64		arg2 = PG_GETARG_INT64(1);
-	int64		result;
 
-	result = arg1 + arg2;
-
-	/*
-	 * Overflow check.  If the inputs are of different signs then their sum
-	 * cannot overflow.  If the inputs are of the same sign, their sum had
-	 * better be that sign too.
-	 */
-	if (SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
+	if (PG_INT64_ADD_OVERFLOWS(arg1, arg2))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("bigint out of range")));
-	PG_RETURN_INT64(result);
+	PG_RETURN_INT64((int64) arg1 + arg2);
 }
 
 Datum
@@ -949,20 +870,12 @@ int48mi(PG_FUNCTION_ARGS)
 {
 	int32		arg1 = PG_GETARG_INT32(0);
 	int64		arg2 = PG_GETARG_INT64(1);
-	int64		result;
 
-	result = arg1 - arg2;
-
-	/*
-	 * Overflow check.  If the inputs are of the same sign then their
-	 * difference cannot overflow.  If they are of different signs then the
-	 * result should be of the same sign as the first input.
-	 */
-	if (!SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
+	if (PG_INT64_SUB_OVERFLOWS(arg1, arg2))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("bigint out of range")));
-	PG_RETURN_INT64(result);
+	PG_RETURN_INT64((int64) arg1 - arg2);
 }
 
 Datum
@@ -970,26 +883,12 @@ int48mul(PG_FUNCTION_ARGS)
 {
 	int32		arg1 = PG_GETARG_INT32(0);
 	int64		arg2 = PG_GETARG_INT64(1);
-	int64		result;
 
-	result = arg1 * arg2;
-
-	/*
-	 * Overflow check.  We basically check to see if result / arg2 gives arg1
-	 * again.  There is one case where this fails: arg2 = 0 (which cannot
-	 * overflow).
-	 *
-	 * Since the division is likely much more expensive than the actual
-	 * multiplication, we'd like to skip it where possible.  The best bang for
-	 * the buck seems to be to check whether both inputs are in the int32
-	 * range; if so, no overflow is possible.
-	 */
-	if (arg2 != (int64) ((int32) arg2) &&
-		result / arg2 != arg1)
+	if (PG_INT64_MUL_OVERFLOWS(arg1, arg2))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("bigint out of range")));
-	PG_RETURN_INT64(result);
+	PG_RETURN_INT64((int64) arg1 * arg2);
 }
 
 Datum
@@ -1016,20 +915,13 @@ int82pl(PG_FUNCTION_ARGS)
 {
 	int64		arg1 = PG_GETARG_INT64(0);
 	int16		arg2 = PG_GETARG_INT16(1);
-	int64		result;
-
-	result = arg1 + arg2;
 
-	/*
-	 * Overflow check.  If the inputs are of different signs then their sum
-	 * cannot overflow.  If the inputs are of the same sign, their sum had
-	 * better be that sign too.
-	 */
-	if (SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
+	if (PG_INT64_ADD_OVERFLOWS(arg1, arg2))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("bigint out of range")));
-	PG_RETURN_INT64(result);
+
+	PG_RETURN_INT64(arg1 + (int64) arg2);
 }
 
 Datum
@@ -1037,20 +929,13 @@ int82mi(PG_FUNCTION_ARGS)
 {
 	int64		arg1 = PG_GETARG_INT64(0);
 	int16		arg2 = PG_GETARG_INT16(1);
-	int64		result;
 
-	result = arg1 - arg2;
-
-	/*
-	 * Overflow check.  If the inputs are of the same sign then their
-	 * difference cannot overflow.  If they are of different signs then the
-	 * result should be of the same sign as the first input.
-	 */
-	if (!SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
+	if (PG_INT64_SUB_OVERFLOWS(arg1, arg2))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("bigint out of range")));
-	PG_RETURN_INT64(result);
+
+	PG_RETURN_INT64(arg1 - (int64) arg2);
 }
 
 Datum
@@ -1058,26 +943,13 @@ int82mul(PG_FUNCTION_ARGS)
 {
 	int64		arg1 = PG_GETARG_INT64(0);
 	int16		arg2 = PG_GETARG_INT16(1);
-	int64		result;
-
-	result = arg1 * arg2;
 
-	/*
-	 * Overflow check.  We basically check to see if result / arg1 gives arg2
-	 * again.  There is one case where this fails: arg1 = 0 (which cannot
-	 * overflow).
-	 *
-	 * Since the division is likely much more expensive than the actual
-	 * multiplication, we'd like to skip it where possible.  The best bang for
-	 * the buck seems to be to check whether both inputs are in the int32
-	 * range; if so, no overflow is possible.
-	 */
-	if (arg1 != (int64) ((int32) arg1) &&
-		result / arg1 != arg2)
+	if (PG_INT64_MUL_OVERFLOWS(arg1, arg2))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("bigint out of range")));
-	PG_RETURN_INT64(result);
+
+	PG_RETURN_INT64(arg1 * (int64) arg2);
 }
 
 Datum
@@ -1104,12 +976,12 @@ int82div(PG_FUNCTION_ARGS)
 	 */
 	if (arg2 == -1)
 	{
-		result = -arg1;
 		/* overflow check (needed for INT64_MIN) */
-		if (arg1 != 0 && SAMESIGN(result, arg1))
+		if (arg1 == PG_INT64_MIN)
 			ereport(ERROR,
 					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 					 errmsg("bigint out of range")));
+		result = -arg1;
 		PG_RETURN_INT64(result);
 	}
 
@@ -1125,20 +997,13 @@ int28pl(PG_FUNCTION_ARGS)
 {
 	int16		arg1 = PG_GETARG_INT16(0);
 	int64		arg2 = PG_GETARG_INT64(1);
-	int64		result;
 
-	result = arg1 + arg2;
-
-	/*
-	 * Overflow check.  If the inputs are of different signs then their sum
-	 * cannot overflow.  If the inputs are of the same sign, their sum had
-	 * better be that sign too.
-	 */
-	if (SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
+	if (PG_INT64_ADD_OVERFLOWS(arg1, arg2))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("bigint out of range")));
-	PG_RETURN_INT64(result);
+
+	PG_RETURN_INT64((int64) arg1 + arg2);
 }
 
 Datum
@@ -1146,20 +1011,13 @@ int28mi(PG_FUNCTION_ARGS)
 {
 	int16		arg1 = PG_GETARG_INT16(0);
 	int64		arg2 = PG_GETARG_INT64(1);
-	int64		result;
-
-	result = arg1 - arg2;
 
-	/*
-	 * Overflow check.  If the inputs are of the same sign then their
-	 * difference cannot overflow.  If they are of different signs then the
-	 * result should be of the same sign as the first input.
-	 */
-	if (!SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
+	if (PG_INT64_SUB_OVERFLOWS(arg1, arg2))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("bigint out of range")));
-	PG_RETURN_INT64(result);
+
+	PG_RETURN_INT64((int64) arg1 - arg2);
 }
 
 Datum
@@ -1167,26 +1025,14 @@ int28mul(PG_FUNCTION_ARGS)
 {
 	int16		arg1 = PG_GETARG_INT16(0);
 	int64		arg2 = PG_GETARG_INT64(1);
-	int64		result;
 
-	result = arg1 * arg2;
-
-	/*
-	 * Overflow check.  We basically check to see if result / arg2 gives arg1
-	 * again.  There is one case where this fails: arg2 = 0 (which cannot
-	 * overflow).
-	 *
-	 * Since the division is likely much more expensive than the actual
-	 * multiplication, we'd like to skip it where possible.  The best bang for
-	 * the buck seems to be to check whether both inputs are in the int32
-	 * range; if so, no overflow is possible.
-	 */
-	if (arg2 != (int64) ((int32) arg2) &&
-		result / arg2 != arg1)
+	/* Overflow check */
+	if (PG_INT64_MUL_OVERFLOWS(arg1, arg2))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("bigint out of range")));
-	PG_RETURN_INT64(result);
+
+	PG_RETURN_INT64((int64) arg1 * arg2);
 }
 
 Datum
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 1667d80..df866b4 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -5197,8 +5197,7 @@ numericvar_to_int64(NumericVar *var, int64 *result)
 	int			ndigits;
 	int			weight;
 	int			i;
-	int64		val,
-				oldval;
+	int64		val;
 	bool		neg;
 	NumericVar	rounded;
 
@@ -5224,37 +5223,34 @@ numericvar_to_int64(NumericVar *var, int64 *result)
 	weight = rounded.weight;
 	Assert(weight >= 0 && ndigits <= weight + 1);
 
-	/* Construct the result */
+	/*
+	 * Construct the result by accumulating the absolute value in "val" as
+	 * a negative value to avoid overflow with PG_INT64_MIN.
+	 */
 	digits = rounded.digits;
 	neg = (rounded.sign == NUMERIC_NEG);
-	val = digits[0];
+	val = -digits[0];
 	for (i = 1; i <= weight; i++)
 	{
-		oldval = val;
-		val *= NBASE;
-		if (i < ndigits)
-			val += digits[i];
-
-		/*
-		 * The overflow check is a bit tricky because we want to accept
-		 * INT64_MIN, which will overflow the positive accumulator.  We can
-		 * detect this case easily though because INT64_MIN is the only
-		 * nonzero value for which -val == val (on a two's complement machine,
-		 * anyway).
-		 */
-		if ((val / NBASE) != oldval)	/* possible overflow? */
-		{
-			if (!neg || (-val) != val || val == 0 || oldval < 0)
+		NumericDigit digit = (i < ndigits) ? digits[i] : 0;
+		if (PG_INT64_MUL_OVERFLOWS(val, NBASE) ||
+			PG_INT64_SUB_OVERFLOWS(val * NBASE, digit))
 			{
 				free_var(&rounded);
 				return false;
 			}
-		}
+		val = val * NBASE - digit;
 	}
 
 	free_var(&rounded);
 
-	*result = neg ? -val : val;
+	if (!neg && val == PG_INT64_MIN)
+		/* overflows signed int64 */
+		return false;
+	else if (!neg)
+		*result = -val;
+	else
+		*result = val;
 	return true;
 }
 
diff --git a/src/backend/utils/adt/oracle_compat.c b/src/backend/utils/adt/oracle_compat.c
index 8e896eb..afdbd44 100644
--- a/src/backend/utils/adt/oracle_compat.c
+++ b/src/backend/utils/adt/oracle_compat.c
@@ -175,14 +175,14 @@ lpad(PG_FUNCTION_ARGS)
 	if (s2len <= 0)
 		len = s1len;			/* nothing to pad with, so don't pad */
 
-	bytelen = pg_database_encoding_max_length() * len;
-
 	/* check for integer overflow */
-	if (len != 0 && bytelen / pg_database_encoding_max_length() != len)
+	if (len > PG_INT32_MAX / pg_database_encoding_max_length() - VARHDRSZ)
 		ereport(ERROR,
 				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
 				 errmsg("requested length too large")));
 
+	bytelen = pg_database_encoding_max_length() * len;
+
 	ret = (text *) palloc(VARHDRSZ + bytelen);
 
 	m = len - s1len;
@@ -1041,24 +1041,25 @@ repeat(PG_FUNCTION_ARGS)
 	char	   *cp,
 			   *sp;
 
+	slen = VARSIZE_ANY_EXHDR(string);
+
 	if (count < 0)
 		count = 0;
 
-	slen = VARSIZE_ANY_EXHDR(string);
-	tlen = VARHDRSZ + (count * slen);
-
-	/* Check for integer overflow */
-	if (slen != 0 && count != 0)
+	else if (slen != 0 &&
+			 count > (PG_INT32_MAX - VARHDRSZ) / slen)
 	{
-		int			check = count * slen;
-		int			check2 = check + VARHDRSZ;
-
-		if ((check / slen) != count || check2 <= check)
-			ereport(ERROR,
-					(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
-					 errmsg("requested length too large")));
+		/*
+		 * The palloc will actually fail at a lower value but we must protect
+		 * against signed integer overflow separately
+		 */
+		ereport(ERROR,
+				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+				 errmsg("requested length too large")));
 	}
 
+	tlen = VARHDRSZ + (count * slen);
+
 	result = (text *) palloc(tlen);
 
 	SET_VARSIZE(result, tlen);
diff --git a/src/backend/utils/adt/varbit.c b/src/backend/utils/adt/varbit.c
index 77b05c8..2583ab4 100644
--- a/src/backend/utils/adt/varbit.c
+++ b/src/backend/utils/adt/varbit.c
@@ -1054,16 +1054,12 @@ bitsubstring(VarBit *arg, int32 s, int32 l, bool length_not_specified)
 	}
 	else
 	{
-		e = s + l;
-
-		/*
-		 * A negative value for L is the only way for the end position to be
-		 * before the start. SQL99 says to throw an error.
-		 */
-		if (e < s)
+		/* SQL99 says to throw an error. */
+		if (l < 0)
 			ereport(ERROR,
 					(errcode(ERRCODE_SUBSTRING_ERROR),
 					 errmsg("negative substring length not allowed")));
+		e = s + l;
 		e1 = Min(e, bitlen + 1);
 	}
 	if (s1 > bitlen || e1 <= s1)
@@ -1166,12 +1162,14 @@ bit_overlay(VarBit *t1, VarBit *t2, int sp, int sl)
 		ereport(ERROR,
 				(errcode(ERRCODE_SUBSTRING_ERROR),
 				 errmsg("negative substring length not allowed")));
-	sp_pl_sl = sp + sl;
-	if (sp_pl_sl <= sl)
+
+	if (PG_INT32_ADD_OVERFLOWS(sp, sl))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("integer out of range")));
 
+	sp_pl_sl = sp + sl;
+
 	s1 = bitsubstring(t1, 1, sp - 1, false);
 	s2 = bitsubstring(t1, sp_pl_sl, -1, true);
 	result = bit_catenate(s1, t2);
diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c
index d545c34..7d8bf99 100644
--- a/src/backend/utils/adt/varlena.c
+++ b/src/backend/utils/adt/varlena.c
@@ -818,32 +818,36 @@ text_substring(Datum str, int32 start, int32 length, bool length_not_specified)
 	{
 		S1 = Max(S, 1);
 
-		if (length_not_specified)		/* special case - get length to end of
-										 * string */
+		/* special case - get length to end of string */
+		if (length_not_specified)
 			L1 = -1;
+		else if (length < 0)
+		{
+			/* SQL99 says to throw an error. */
+			ereport(ERROR,
+					(errcode(ERRCODE_SUBSTRING_ERROR),
+					 errmsg("negative substring length not allowed")));
+		}
+		else if (PG_INT32_MAX - length < start)
+		{
+			/*
+			 * overflow (but the string can't be that large so just get length
+			 * to end of string) */
+			L1 = -1;
+		}
 		else
 		{
-			/* end position */
-			int			E = S + length;
-
 			/*
-			 * A negative value for L is the only way for the end position to
-			 * be before the start. SQL99 says to throw an error.
+			 * Calculate length adjusted to actual start of string (input
+			 * start could have been negative) and note that according to
+			 * SQL99 we should return an empty string if the entire string is
+			 * left of 1.
 			 */
-			if (E < S)
-				ereport(ERROR,
-						(errcode(ERRCODE_SUBSTRING_ERROR),
-						 errmsg("negative substring length not allowed")));
 
-			/*
-			 * A zero or negative value for the end position can happen if the
-			 * start was negative or one. SQL99 says to return a zero-length
-			 * string.
-			 */
-			if (E < 1)
-				return cstring_to_text("");
+			L1 = S + length - S1;
 
-			L1 = E - S1;
+			if (L1 <= 0)
+				return cstring_to_text("");
 		}
 
 		/*
@@ -883,21 +887,29 @@ text_substring(Datum str, int32 start, int32 length, bool length_not_specified)
 		 */
 		slice_start = 0;
 
-		if (length_not_specified)		/* special case - get length to end of
-										 * string */
+		if (length_not_specified)
+		{
+			/* special case - get length to end of string */
 			slice_size = L1 = -1;
-		else
+		}
+		else if (length < 0)
+		{
+			/* SQL99 says to throw an error. */
+			ereport(ERROR,
+					(errcode(ERRCODE_SUBSTRING_ERROR),
+					 errmsg("negative substring length not allowed")));
+		}
+		else if (PG_INT32_MAX - length < start)
 		{
-			int			E = S + length;
-
 			/*
-			 * A negative value for L is the only way for the end position to
-			 * be before the start. SQL99 says to throw an error.
+			 * Overflow but the string can't be that large so just get length
+			 * to end of string.
 			 */
-			if (E < S)
-				ereport(ERROR,
-						(errcode(ERRCODE_SUBSTRING_ERROR),
-						 errmsg("negative substring length not allowed")));
+			slice_size = L1 = -1;
+		}
+		else
+		{
+			int			E = S + length;
 
 			/*
 			 * A zero or negative value for the end position can happen if the
@@ -1042,12 +1054,14 @@ text_overlay(text *t1, text *t2, int sp, int sl)
 		ereport(ERROR,
 				(errcode(ERRCODE_SUBSTRING_ERROR),
 				 errmsg("negative substring length not allowed")));
-	sp_pl_sl = sp + sl;
-	if (sp_pl_sl <= sl)
+
+	if (PG_INT32_MAX - sp < sl)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("integer out of range")));
 
+	sp_pl_sl = sp + sl;
+
 	s1 = text_substring(PointerGetDatum(t1), 1, sp - 1, false);
 	s2 = text_substring(PointerGetDatum(t1), sp_pl_sl, -1, true);
 	result = text_catenate(s1, t2);
@@ -2573,21 +2587,27 @@ bytea_substring(Datum str,
 		 */
 		L1 = -1;
 	}
+	else if (L < 0)
+	{
+		/* SQL99 says to throw an error. */
+		ereport(ERROR,
+				(errcode(ERRCODE_SUBSTRING_ERROR),
+				 errmsg("negative substring length not allowed")));
+	}
+	else if (PG_INT32_MAX - L < S)
+	{
+		/*
+		 * Overflow, but the string can't be so large so just fetch to end of
+		 * the string.
+		 */
+		L1 = -1;
+	}
 	else
 	{
 		/* end position */
 		int			E = S + L;
 
 		/*
-		 * A negative value for L is the only way for the end position to be
-		 * before the start. SQL99 says to throw an error.
-		 */
-		if (E < S)
-			ereport(ERROR,
-					(errcode(ERRCODE_SUBSTRING_ERROR),
-					 errmsg("negative substring length not allowed")));
-
-		/*
 		 * A zero or negative value for the end position can happen if the
 		 * start was negative or one. SQL99 says to return a zero-length
 		 * string.
@@ -2653,12 +2673,14 @@ bytea_overlay(bytea *t1, bytea *t2, int sp, int sl)
 		ereport(ERROR,
 				(errcode(ERRCODE_SUBSTRING_ERROR),
 				 errmsg("negative substring length not allowed")));
-	sp_pl_sl = sp + sl;
-	if (sp_pl_sl <= sl)
+
+	if (PG_INT32_MAX - sp < sl)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("integer out of range")));
 
+	sp_pl_sl = sp + sl;
+
 	s1 = bytea_substring(PointerGetDatum(t1), 1, sp - 1, false);
 	s2 = bytea_substring(PointerGetDatum(t1), sp_pl_sl, -1, true);
 	result = bytea_catenate(s1, t2);
diff --git a/src/include/c.h b/src/include/c.h
index 8163b00..2af3b5f 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -793,6 +793,88 @@ typedef NameData *Name;
 #define Abs(x)			((x) >= 0 ? (x) : -(x))
 
 /*
+ * Detect overflow for signed INT32 and INT64
+ *
+ * Note that this has to be done before doing the suspect arithmetic rather
+ * than afterwards by examining the signs because signed overflow is not well
+ * defined and compilers take liberties to optimize away the checks.
+ *
+ * Also note that SUB_OVERFLOWS is not just the same as doing ADD_OVERFLOWS
+ * with -b because if b = INT_MIN then that would itself cause an overflow...
+ */
+
+#define PG_INT16_ADD_OVERFLOWS(a, b) (						\
+		((a) > 0 && (b) > 0 && (a) > PG_INT16_MAX - (b)) ||	\
+		((a) < 0 && (b) < 0 && (a) < PG_INT16_MIN - (b)))
+
+#define PG_INT16_SUB_OVERFLOWS(a, b) (						\
+		((a) < 0 && (b) > 0 && (a) < PG_INT16_MIN + (b)) ||	\
+		((a) > 0 && (b) < 0 && (a) > PG_INT16_MAX + (b)))
+
+#define PG_INT32_ADD_OVERFLOWS(a, b) (						\
+		((a) > 0 && (b) > 0 && (a) > PG_INT32_MAX - (b)) ||	\
+		((a) < 0 && (b) < 0 && (a) < PG_INT32_MIN - (b)))
+
+#define PG_INT32_SUB_OVERFLOWS(a, b) (						\
+		((a) < 0 && (b) > 0 && (a) < PG_INT32_MIN + (b)) ||	\
+		((a) > 0 && (b) < 0 && (a) > PG_INT32_MAX + (b)))
+
+#define PG_INT64_ADD_OVERFLOWS(a, b) (						\
+		((a) > 0 && (b) > 0 && (a) > PG_INT64_MAX - (b)) ||	\
+		((a) < 0 && (b) < 0 && (a) < PG_INT64_MIN - (b)))
+
+#define PG_INT64_SUB_OVERFLOWS(a, b) (						\
+		((a) < 0 && (b) > 0 && (a) < PG_INT64_MIN + (b)) ||	\
+		((a) > 0 && (b) < 0 && (a) > PG_INT64_MAX + (b)))
+
+/*
+ * Overflow can only happen if at least one value is outside the range
+ * sqrt(min)..sqrt(max) so check that first as the division can be quite
+ * a bit more expensive than the multiplication.
+ *
+ * Multiplying by 0 or 1 can't overflow of course and checking for 0
+ * separately avoids any risk of dividing by 0.  Be careful about dividing
+ * PG_INT32_MIN by -1 also, note reversing the a and b to ensure we are
+ * always dividing it by a positive value.
+ */
+
+#define PG_INT16_MUL_OVERFLOWS(a,b) (							\
+		((a) > PG_INT8_MAX || (a) < PG_INT8_MIN  ||			\
+		 (b) > PG_INT8_MAX || (b) < PG_INT8_MIN) &&			\
+		(a) != 0 && (a) != 1 && (b) != 0 && (b) != 1 &&			\
+		(														\
+			((a) > 0 && (b) > 0 && (a) > PG_INT16_MAX / (b)) ||	\
+			((a) > 0 && (b) < 0 && (b) < PG_INT16_MIN / (a)) ||	\
+			((a) < 0 && (b) > 0 && (a) < PG_INT16_MIN / (b)) ||	\
+			((a) < 0 && (b) < 0 && (a) < PG_INT16_MAX / (b))	\
+			)													\
+		)
+
+#define PG_INT32_MUL_OVERFLOWS(a,b) (							\
+		((a) > PG_INT16_MAX || (a) < PG_INT16_MIN  ||			\
+		 (b) > PG_INT16_MAX || (b) < PG_INT16_MIN) &&			\
+		(a) != 0 && (a) != 1 && (b) != 0 && (b) != 1 &&			\
+		(														\
+			((a) > 0 && (b) > 0 && (a) > PG_INT32_MAX / (b)) ||	\
+			((a) > 0 && (b) < 0 && (b) < PG_INT32_MIN / (a)) ||	\
+			((a) < 0 && (b) > 0 && (a) < PG_INT32_MIN / (b)) ||	\
+			((a) < 0 && (b) < 0 && (a) < PG_INT32_MAX / (b))	\
+			)													\
+		)
+
+#define PG_INT64_MUL_OVERFLOWS(a,b) (							\
+		((a) > PG_INT32_MAX || (a) < PG_INT32_MIN  ||			\
+		 (b) > PG_INT32_MAX || (b) < PG_INT32_MIN) &&			\
+		(a) != 0 && (a) != 1 && (b) != 0 && (b) != 1 &&			\
+		(														\
+			((a) > 0 && (b) > 0 && (a) > PG_INT64_MAX / (b)) ||	\
+			((a) > 0 && (b) < 0 && (b) < PG_INT64_MIN / (a)) ||	\
+			((a) < 0 && (b) > 0 && (a) < PG_INT64_MIN / (b)) ||	\
+			((a) < 0 && (b) < 0 && (a) < PG_INT64_MAX / (b))	\
+			)													\
+		)
+
+/*
  * StrNCpy
  *	Like standard library function strncpy(), except that result string
  *	is guaranteed to be null-terminated --- that is, at most N-1 bytes
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index c73f20b..77ad1a4 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -2068,13 +2068,13 @@ exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
 		 */
 		if (stmt->reverse)
 		{
-			if ((int32) (loop_value - step_value) > loop_value)
+			if (PG_INT32_SUB_OVERFLOWS(loop_value, step_value))
 				break;
 			loop_value -= step_value;
 		}
 		else
 		{
-			if ((int32) (loop_value + step_value) < loop_value)
+			if (PG_INT32_ADD_OVERFLOWS(loop_value, step_value))
 				break;
 			loop_value += step_value;
 		}
diff --git a/src/test/regress/expected/int2.out b/src/test/regress/expected/int2.out
index 3ea4ed9..0f9e6b7 100644
--- a/src/test/regress/expected/int2.out
+++ b/src/test/regress/expected/int2.out
@@ -266,6 +266,9 @@ SELECT (-32768)::int2 % (-1)::int2;
         0
 (1 row)
 
+-- check handling of overflow cases for int2 functions
+SELECT int2um((-32768)::int2);
+ERROR:  smallint out of range
 -- check rounding when casting from float
 SELECT x, x::int2 AS int2_value
 FROM (VALUES (-2.5::float8),
diff --git a/src/test/regress/expected/int4.out b/src/test/regress/expected/int4.out
index 372fd4d..4de05c4 100644
--- a/src/test/regress/expected/int4.out
+++ b/src/test/regress/expected/int4.out
@@ -363,6 +363,11 @@ SELECT (-2147483648)::int4 % (-1)::int2;
         0
 (1 row)
 
+-- check handling of overflow cases for int4 functions
+SELECT int4inc(2147483647::int4);
+ERROR:  integer out of range
+SELECT int4um((-2147483648)::int4);
+ERROR:  integer out of range
 -- check rounding when casting from float
 SELECT x, x::int4 AS int4_value
 FROM (VALUES (-2.5::float8),
diff --git a/src/test/regress/expected/int8.out b/src/test/regress/expected/int8.out
index ed0bd34..9722a79 100644
--- a/src/test/regress/expected/int8.out
+++ b/src/test/regress/expected/int8.out
@@ -846,6 +846,11 @@ SELECT (-9223372036854775808)::int8 % (-1)::int2;
         0
 (1 row)
 
+-- check handling of overflow cases for int8 functions
+SELECT int8inc(9223372036854775807::int8);
+ERROR:  bigint out of range
+SELECT int8um((-9223372036854775808)::int8);
+ERROR:  bigint out of range
 -- check rounding when casting from float
 SELECT x, x::int8 AS int8_value
 FROM (VALUES (-2.5::float8),
diff --git a/src/test/regress/sql/int2.sql b/src/test/regress/sql/int2.sql
index 7dbafb6..a5947fc 100644
--- a/src/test/regress/sql/int2.sql
+++ b/src/test/regress/sql/int2.sql
@@ -93,6 +93,9 @@ SELECT (-32768)::int2 * (-1)::int2;
 SELECT (-32768)::int2 / (-1)::int2;
 SELECT (-32768)::int2 % (-1)::int2;
 
+-- check handling of overflow cases for int2 functions
+SELECT int2um((-32768)::int2);
+
 -- check rounding when casting from float
 SELECT x, x::int2 AS int2_value
 FROM (VALUES (-2.5::float8),
diff --git a/src/test/regress/sql/int4.sql b/src/test/regress/sql/int4.sql
index f014cb2..734158a 100644
--- a/src/test/regress/sql/int4.sql
+++ b/src/test/regress/sql/int4.sql
@@ -136,6 +136,10 @@ SELECT (-2147483648)::int4 * (-1)::int2;
 SELECT (-2147483648)::int4 / (-1)::int2;
 SELECT (-2147483648)::int4 % (-1)::int2;
 
+-- check handling of overflow cases for int4 functions
+SELECT int4inc(2147483647::int4);
+SELECT int4um((-2147483648)::int4);
+
 -- check rounding when casting from float
 SELECT x, x::int4 AS int4_value
 FROM (VALUES (-2.5::float8),
diff --git a/src/test/regress/sql/int8.sql b/src/test/regress/sql/int8.sql
index e890452..0208ea3 100644
--- a/src/test/regress/sql/int8.sql
+++ b/src/test/regress/sql/int8.sql
@@ -206,6 +206,10 @@ SELECT (-9223372036854775808)::int8 * (-1)::int2;
 SELECT (-9223372036854775808)::int8 / (-1)::int2;
 SELECT (-9223372036854775808)::int8 % (-1)::int2;
 
+-- check handling of overflow cases for int8 functions
+SELECT int8inc(9223372036854775807::int8);
+SELECT int8um((-9223372036854775808)::int8);
+
 -- check rounding when casting from float
 SELECT x, x::int8 AS int8_value
 FROM (VALUES (-2.5::float8),
diff --git a/src/timezone/localtime.c b/src/timezone/localtime.c
index 19a24e1..02714ad 100644
--- a/src/timezone/localtime.c
+++ b/src/timezone/localtime.c
@@ -1278,17 +1278,20 @@ timesub(const pg_time_t *timep, long offset,
 }
 
 /*
- * Simplified normalize logic courtesy Paul Eggert.
+ * signed overflow cannot be detected by looking for wraparound after the fact
+ * as newer compilers optimize away such checks. Return 1 if overflow would
+ * occur and 0 otherwise.
  */
 
 static int
 increment_overflow(int *number, int delta)
 {
-	int			number0;
+	if ((delta > 0 && *number > INT_MAX - delta) ||
+		(delta < 0 && *number < INT_MIN - delta))
+		return 1;
 
-	number0 = *number;
 	*number += delta;
-	return (*number < number0) != (delta < 0);
+	return 0;
 }
 
 /*
diff --git a/src/timezone/zic.c b/src/timezone/zic.c
index 1a7ec68..6b974cc 100644
--- a/src/timezone/zic.c
+++ b/src/timezone/zic.c
@@ -2650,33 +2650,27 @@ getfields(char *cp)
 static long
 oadd(long t1, long t2)
 {
-	long		t;
-
-	t = t1 + t2;
-	if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1))
-	{
+	if (t1 < 0 ? t2 < LONG_MIN - t1 : LONG_MAX - t1 < t2) {
 		error(_("time overflow"));
 		exit(EXIT_FAILURE);
 	}
-	return t;
+
+	return t1 + t2;
 }
 
 static zic_t
 tadd(const zic_t t1, long t2)
 {
-	zic_t		t;
-
 	if (t1 == max_time && t2 > 0)
 		return max_time;
 	if (t1 == min_time && t2 < 0)
 		return min_time;
-	t = t1 + t2;
-	if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1))
-	{
+	if (t1 < 0 ? t2 < min_time - t1 : max_time - t1 < t2) {
 		error(_("time overflow"));
 		exit(EXIT_FAILURE);
 	}
-	return t;
+
+	return t1 + t2;
 }
 
 /*
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to