[RFC] overflow checks optimized away

Started by Xi Wangalmost 13 years ago43 messages
#1Xi Wang
xi.wang@gmail.com

Intel's icc and PathScale's pathcc compilers optimize away several
overflow checks, since they consider signed integer overflow as
undefined behavior. This leads to a vulnerable binary.

Currently we use -fwrapv to disable such (mis)optimizations in gcc,
but not in other compilers.

Examples
========

1) x + 1 <= 0 (assuming x > 0).

src/backend/executor/execQual.c:3088

Below is the simplified code.

-----------------------------------------
void bar(void);
void foo(int this_ndims)
{
if (this_ndims <= 0)
return;
int elem_ndims = this_ndims;
int ndims = elem_ndims + 1;
if (ndims <= 0)
bar();
}
-----------------------------------------

$ icc -S -o - sadd1.c
...
foo:
# parameter 1: %edi
..B1.1:
..___tag_value_foo.1:
..B1.2:
ret

2) x + 1 < x

src/backend/utils/adt/float.c:2769
src/backend/utils/adt/float.c:2785
src/backend/utils/adt/oracle_compat.c:1045 (x + C < x)

Below is the simplified code.

-----------------------------------------
void bar(void);
void foo(int count)
{
int result = count + 1;
if (result < count)
bar();
}
-----------------------------------------

$ icc -S -o - sadd2.c
...
foo:
# parameter 1: %edi
..B1.1:
..___tag_value_foo.1:
ret
3) x + y <= x (assuming y > 0)

src/backend/utils/adt/varbit.c:1142
src/backend/utils/adt/varlena.c:1001
src/backend/utils/adt/varlena.c:2024
src/pl/plpgsql/src/pl_exec.c:1975
src/pl/plpgsql/src/pl_exec.c:1981

Below is the simplified code.

-----------------------------------------
void bar(void);
void foo(int sp, int sl)
{
if (sp <= 0)
return;
int sp_pl_sl = sp + sl;
if (sp_pl_sl <= sl)
bar();
}
-----------------------------------------

$ icc -S -o - sadd3.c
foo:
# parameter 1: %edi
# parameter 2: %esi
..B1.1:
..___tag_value_foo.1:
..B1.2:
ret

Possible fixes
==============

* Recent versions of icc and pathcc support gcc's workaround option,
-fno-strict-overflow, to disable some optimizations based on signed
integer overflow. It's better to add this option to configure.
They don't support gcc's -fwrapv yet.

* This -fno-strict-overflow option cannot help in all cases: it cannot
prevent the latest icc from (mis)compiling the 1st case. We could also
fix the source code by avoiding signed integer overflows, as follows.

x + y <= 0 (assuming x > 0, y > 0)
--> x > INT_MAX - y

x + y <= x (assuming y > 0)
--> x > INT_MAX - y

I'd suggest to fix the code rather than trying to work around the
compilers since the fix seems simple and portable.

See two recent compiler bugs of -fwrapv/-fno-strict-overflow as well.

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55883
http://software.intel.com/en-us/forums/topic/358200

* I don't have access to IBM's xlc compiler. Not sure how it works for
the above cases.

- xi

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#2Xi Wang
xi.wang@gmail.com
In reply to: Xi Wang (#1)
[PATCH 0/3] Work around icc miscompilation

I'm sending three smaller patches for review, which try to fix icc
and pathscale (mis)compilation problems described in my last email.

Not sure if we need to fix the overflow check x + 1 <= 0 (x > 0) at
src/backend/executor/execQual.c:3088, which icc optimizes away, too.

Fix x + y < x overflow checks
Fix x + 1 < x overflow checks
Fix overflow checking in repeat()

src/backend/utils/adt/float.c | 8 ++++----
src/backend/utils/adt/oracle_compat.c | 18 +++++++-----------
src/backend/utils/adt/varbit.c | 7 +++++--
src/backend/utils/adt/varlena.c | 10 ++++++----
src/pl/plpgsql/src/pl_exec.c | 4 ++--
5 files changed, 24 insertions(+), 23 deletions(-)

On 1/20/13 2:58 AM, Xi Wang wrote:

Intel's icc and PathScale's pathcc compilers optimize away several
overflow checks, since they consider signed integer overflow as
undefined behavior. This leads to a vulnerable binary.

Currently we use -fwrapv to disable such (mis)optimizations in gcc,
but not in other compilers.

Examples
========

1) x + 1 <= 0 (assuming x > 0).

src/backend/executor/execQual.c:3088

Below is the simplified code.

-----------------------------------------
void bar(void);
void foo(int this_ndims)
{
if (this_ndims <= 0)
return;
int elem_ndims = this_ndims;
int ndims = elem_ndims + 1;
if (ndims <= 0)
bar();
}
-----------------------------------------

$ icc -S -o - sadd1.c
...
foo:
# parameter 1: %edi
..B1.1:
..___tag_value_foo.1:
..B1.2:
ret

2) x + 1 < x

src/backend/utils/adt/float.c:2769
src/backend/utils/adt/float.c:2785
src/backend/utils/adt/oracle_compat.c:1045 (x + C < x)

Below is the simplified code.

-----------------------------------------
void bar(void);
void foo(int count)
{
int result = count + 1;
if (result < count)
bar();
}
-----------------------------------------

$ icc -S -o - sadd2.c
...
foo:
# parameter 1: %edi
..B1.1:
..___tag_value_foo.1:
ret
3) x + y <= x (assuming y > 0)

src/backend/utils/adt/varbit.c:1142
src/backend/utils/adt/varlena.c:1001
src/backend/utils/adt/varlena.c:2024
src/pl/plpgsql/src/pl_exec.c:1975
src/pl/plpgsql/src/pl_exec.c:1981

Below is the simplified code.

-----------------------------------------
void bar(void);
void foo(int sp, int sl)
{
if (sp <= 0)
return;
int sp_pl_sl = sp + sl;
if (sp_pl_sl <= sl)
bar();
}
-----------------------------------------

$ icc -S -o - sadd3.c
foo:
# parameter 1: %edi
# parameter 2: %esi
..B1.1:
..___tag_value_foo.1:
..B1.2:
ret

Possible fixes
==============

* Recent versions of icc and pathcc support gcc's workaround option,
-fno-strict-overflow, to disable some optimizations based on signed
integer overflow. It's better to add this option to configure.
They don't support gcc's -fwrapv yet.

* This -fno-strict-overflow option cannot help in all cases: it cannot
prevent the latest icc from (mis)compiling the 1st case. We could also
fix the source code by avoiding signed integer overflows, as follows.

x + y <= 0 (assuming x > 0, y > 0)
--> x > INT_MAX - y

x + y <= x (assuming y > 0)
--> x > INT_MAX - y

I'd suggest to fix the code rather than trying to work around the
compilers since the fix seems simple and portable.

See two recent compiler bugs of -fwrapv/-fno-strict-overflow as well.

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55883
http://software.intel.com/en-us/forums/topic/358200

* I don't have access to IBM's xlc compiler. Not sure how it works for
the above cases.

- xi

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#3Xi Wang
xi.wang@gmail.com
In reply to: Xi Wang (#2)
[PATCH 1/3] Fix x + y < x overflow checks

icc optimizes away the overflow check x + y < x (y > 0), because
signed integer overflow is undefined behavior in C. Instead, use
a safe precondition test x > INT_MAX - y.
---
src/backend/utils/adt/varbit.c | 7 +++++--
src/backend/utils/adt/varlena.c | 10 ++++++----
src/pl/plpgsql/src/pl_exec.c | 4 ++--
3 files changed, 13 insertions(+), 8 deletions(-)

diff --git a/src/backend/utils/adt/varbit.c b/src/backend/utils/adt/varbit.c
index 1712c12..af69200 100644
--- a/src/backend/utils/adt/varbit.c
+++ b/src/backend/utils/adt/varbit.c
@@ -16,6 +16,8 @@

#include "postgres.h"

+#include <limits.h>
+
#include "access/htup_details.h"
#include "libpq/pqformat.h"
#include "nodes/nodeFuncs.h"
@@ -1138,12 +1140,13 @@ 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 (sl > INT_MAX - sp)
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 95e41bf..c907f44 100644
--- a/src/backend/utils/adt/varlena.c
+++ b/src/backend/utils/adt/varlena.c
@@ -997,12 +997,13 @@ 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 (sl > INT_MAX - sp)
 		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);
@@ -2020,12 +2021,13 @@ 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 (sl > INT_MAX - sp)
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/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 0ecf651..a9cf6df 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -1972,13 +1972,13 @@ exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
 		 */
 		if (stmt->reverse)
 		{
-			if ((int32) (loop_value - step_value) > loop_value)
+			if (loop_value < INT_MIN + step_value)
 				break;
 			loop_value -= step_value;
 		}
 		else
 		{
-			if ((int32) (loop_value + step_value) < loop_value)
+			if (loop_value > INT_MAX - step_value)
 				break;
 			loop_value += step_value;
 		}
-- 
1.7.10.4

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#4Xi Wang
xi.wang@gmail.com
In reply to: Xi Wang (#2)
[PATCH 2/3] Fix x + 1 < x overflow checks

icc optimizes away x + 1 < x because signed integer overflow is
undefined behavior in C. Instead, simply check if x is INT_MAX.
---
src/backend/utils/adt/float.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index b73e0d5..344b092 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -2764,12 +2764,12 @@ width_bucket_float8(PG_FUNCTION_ARGS)
 			result = 0;
 		else if (operand >= bound2)
 		{
-			result = count + 1;
 			/* check for overflow */
-			if (result < count)
+			if (count == INT_MAX)
 				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;
@@ -2780,12 +2780,12 @@ width_bucket_float8(PG_FUNCTION_ARGS)
 			result = 0;
 		else if (operand <= bound2)
 		{
-			result = count + 1;
 			/* check for overflow */
-			if (result < count)
+			if (count == INT_MAX)
 				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;
-- 
1.7.10.4

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#5Xi Wang
xi.wang@gmail.com
In reply to: Xi Wang (#2)
[PATCH 3/3] Fix overflow checking in repeat()

icc optimizes away `check + VARHDRSZ <= check' since signed integer
overflow is undefined behavior. Simplify the overflow check for
`VARHDRSZ + count * slen' as `count > (INT_MAX - VARHDRSZ) / slen'.
---
src/backend/utils/adt/oracle_compat.c | 18 +++++++-----------
1 file changed, 7 insertions(+), 11 deletions(-)

diff --git a/src/backend/utils/adt/oracle_compat.c b/src/backend/utils/adt/oracle_compat.c
index d448088..a85a672 100644
--- a/src/backend/utils/adt/oracle_compat.c
+++ b/src/backend/utils/adt/oracle_compat.c
@@ -15,6 +15,8 @@
  */
 #include "postgres.h"

+#include <limits.h>
+
#include "utils/builtins.h"
#include "utils/formatting.h"
#include "mb/pg_wchar.h"
@@ -1034,20 +1036,14 @@ repeat(PG_FUNCTION_ARGS)
count = 0;

slen = VARSIZE_ANY_EXHDR(string);
- tlen = VARHDRSZ + (count * slen);

 	/* Check for integer overflow */
-	if (slen != 0 && count != 0)
-	{
-		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")));
-	}
+	if (slen != 0 && count > (INT_MAX - VARHDRSZ) / slen)
+		ereport(ERROR,
+				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+				 errmsg("requested length too large")));

+ tlen = VARHDRSZ + (count * slen);
result = (text *) palloc(tlen);

SET_VARSIZE(result, tlen);
--
1.7.10.4

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#6Heikki Linnakangas
hlinnakangas@vmware.com
In reply to: Xi Wang (#2)
Re: [PATCH 0/3] Work around icc miscompilation

On 24.01.2013 11:33, Xi Wang wrote:

I'm sending three smaller patches for review, which try to fix icc
and pathscale (mis)compilation problems described in my last email.

These patches look ok at a quick glance, but how do we ensure this kind
of problems don't crop back again in the future? Does icc give a warning
about these? Do we have a buildfarm animal that produces the warnings?

If we fix these, can we stop using -frapv on gcc? Is there any way to
get gcc to warn about these?

- Heikki

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#7Xi Wang
xi.wang@gmail.com
In reply to: Heikki Linnakangas (#6)
Re: [PATCH 0/3] Work around icc miscompilation

On 1/24/13 5:02 AM, Heikki Linnakangas wrote:

These patches look ok at a quick glance, but how do we ensure this kind
of problems don't crop back again in the future? Does icc give a warning
about these? Do we have a buildfarm animal that produces the warnings?

If we fix these, can we stop using -frapv on gcc? Is there any way to
get gcc to warn about these?

Thanks for reviewing.

gcc has this -Wstrict-overflow option to warn against overflow checks
that may be optimized away. The result in inaccurate: it may produce
a large number of false warnings, and it may also miss many cases (esp.
when gcc's value-range-propagation fails to compute variables' ranges).

Not sure if other compilers have similar options.

I find these broken checks using a static checker I'm developing, and
only report cases that existing compilers do miscompile. If you are
interested, I'll post a complete list of overflow checks in pgsql that
invoke undefined behavior and thus may be killed by future compilers.

I believe we can get rid of -fwrapv once we fix all such checks.

- xi

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#8Claudio Freire
klaussfreire@gmail.com
In reply to: Xi Wang (#3)
Re: [PATCH 1/3] Fix x + y < x overflow checks

On Thu, Jan 24, 2013 at 6:36 AM, Xi Wang <xi.wang@gmail.com> wrote:

icc optimizes away the overflow check x + y < x (y > 0), because
signed integer overflow is undefined behavior in C. Instead, use
a safe precondition test x > INT_MAX - y.

I should mention gcc 4.7 does the same, and it emits a warning.

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#9Tom Lane
tgl@sss.pgh.pa.us
In reply to: Xi Wang (#7)
Re: [PATCH 0/3] Work around icc miscompilation

Xi Wang <xi.wang@gmail.com> writes:

On 1/24/13 5:02 AM, Heikki Linnakangas wrote:

If we fix these, can we stop using -frapv on gcc? Is there any way to
get gcc to warn about these?

I believe we can get rid of -fwrapv once we fix all such checks.

TBH, I find that statement to be nonsense, and these patches to be
completely the wrong way to go about it.

The fundamental problem here is that the compiler, unless told otherwise
by a compilation switch, believes it is entitled to assume that no
integer overflow will happen anywhere in the program. Therefore, any
error check that is looking for overflow *should* get optimized away.
The only reason the compiler would fail to do that is if its optimizer
isn't quite smart enough to prove that the code is testing for an
overflow condition. So what you are proposing here is merely the next
move in an arms race with the compiler writers, and it will surely
break again in a future generation of compilers. Or even if these
particular trouble spots don't break, something else will. The only
reliable solution is to not let the compiler make that type of
assumption.

So I think we should just reject all of these, and instead fix configure
to make sure it turns on icc's equivalent of -fwrapv.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#10Xi Wang
xi.wang@gmail.com
In reply to: Tom Lane (#9)
Re: [PATCH 0/3] Work around icc miscompilation

On 1/24/13 10:48 AM, Tom Lane wrote:

The fundamental problem here is that the compiler, unless told otherwise
by a compilation switch, believes it is entitled to assume that no
integer overflow will happen anywhere in the program. Therefore, any
error check that is looking for overflow *should* get optimized away.
The only reason the compiler would fail to do that is if its optimizer
isn't quite smart enough to prove that the code is testing for an
overflow condition. So what you are proposing here is merely the next
move in an arms race with the compiler writers, and it will surely
break again in a future generation of compilers. Or even if these
particular trouble spots don't break, something else will. The only
reliable solution is to not let the compiler make that type of
assumption.

What I am proposing here is the opposite: _not_ to enter an arm race
with the compiler writers. Instead, make the code conform to the C
standard, something both sides can agree on.

Particularly, avoid using (signed) overflowed results to detect
overflows, which the C standard clearly specifies as undefined
behavior and many compilers are actively exploiting.

We could use either unsigned overflows (which is well defined) or
precondition testing (like `x > INT_MAX - y' in the patches).

So I think we should just reject all of these, and instead fix configure
to make sure it turns on icc's equivalent of -fwrapv.

While I agree it's better to turn on icc's -fno-strict-overflow as a
workaround, the fundamental problem here is that we are _not_
programming in the C language. Rather, we are programming in some
C-with-signed-wrapraround dialect.

The worst part of this C dialect is that it has never been specified
clearly what it means by "signed wraparound":

gcc's -fwrapv assumes signed wraparound for add/sub/mul, but not for
div (e.g., INT_MIN/-1 traps on x86) nor shift (e.g., 1<<32 produces
undef with clang).

clang's -fwrapv also assumes workaround for pointer arithmetic, while
gcc's does not.

I have no idea what icc and pathscale's -fno-strict-overflow option
does (probably the closest thing to -fwrapv). Sometimes it prevents
such checks from being optimized away, sometimes it doesn't.

Anyway, it would not be surprising if future C compilers break this
dialect again. But they shouldn't break standard-conforming code.

- xi

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#11Robert Haas
robertmhaas@gmail.com
In reply to: Xi Wang (#3)
Re: [PATCH 1/3] Fix x + y < x overflow checks

On Thu, Jan 24, 2013 at 4:36 AM, Xi Wang <xi.wang@gmail.com> wrote:

icc optimizes away the overflow check x + y < x (y > 0), because
signed integer overflow is undefined behavior in C. Instead, use
a safe precondition test x > INT_MAX - y.

As you post these patches, please add them to:

https://commitfest.postgresql.org/action/commitfest_view/open

This will ensure that they (eventually) get looked at.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#12Noah Misch
noah@leadboat.com
In reply to: Xi Wang (#10)
Re: [PATCH 0/3] Work around icc miscompilation

On Thu, Jan 24, 2013 at 11:40:41AM -0500, Xi Wang wrote:

On 1/24/13 10:48 AM, Tom Lane wrote:

The fundamental problem here is that the compiler, unless told otherwise
by a compilation switch, believes it is entitled to assume that no
integer overflow will happen anywhere in the program. Therefore, any
error check that is looking for overflow *should* get optimized away.
The only reason the compiler would fail to do that is if its optimizer
isn't quite smart enough to prove that the code is testing for an
overflow condition. So what you are proposing here is merely the next
move in an arms race with the compiler writers, and it will surely
break again in a future generation of compilers. Or even if these
particular trouble spots don't break, something else will. The only
reliable solution is to not let the compiler make that type of
assumption.

What I am proposing here is the opposite: _not_ to enter an arm race
with the compiler writers. Instead, make the code conform to the C
standard, something both sides can agree on.

Particularly, avoid using (signed) overflowed results to detect
overflows, which the C standard clearly specifies as undefined
behavior and many compilers are actively exploiting.

We could use either unsigned overflows (which is well defined) or
precondition testing (like `x > INT_MAX - y' in the patches).

So I think we should just reject all of these, and instead fix configure
to make sure it turns on icc's equivalent of -fwrapv.

While I agree it's better to turn on icc's -fno-strict-overflow as a
workaround, the fundamental problem here is that we are _not_
programming in the C language. Rather, we are programming in some
C-with-signed-wrapraround dialect.

I could not have said it better.

All other things being similar, I'd rather have PostgreSQL be written in C,
not C-with-signed-wrapraround. The latter has been a second class citizen for
over 20 years, and that situation won't be improving. However, compiler
options selecting it are common and decently-maintained. Changes along these
lines would become much more interesting if PostgreSQL has a live bug on a
modern compiler despite the use of available options comparable to -fwrapv.

When, if ever, to stop using -fwrapv (and use -ftrapv under --enable-cassert)
is another question. GCC 4.7 reports 999 warnings at -fstrict-overflow
-Wstrict-overflow=5. That doesn't mean 999 bugs to fix before we could remove
-fwrapv, but it does mean 999 places where the compiler will start generating
different code. That has a high chance of breaking something not covered by
the regression tests, so I'd hope to see a notable upside, perhaps a benchmark
improvement. It would also be instructive to know how much code actually
needs to change. Fixing 20 code sites in exchange for standard-conformance
and an X% performance improvement is a different proposition from fixing 200
code sites for the same benefit.

If we do start off in this direction at any scale, I suggest defining macros
like INT_MULT_OVERFLOWS(a, b) to wrap the checks. Then these changes would at
least make the code clearer, not less so.

Thanks,
nm

--
Noah Misch
EnterpriseDB http://www.enterprisedb.com

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#13Greg Stark
stark@mit.edu
In reply to: Tom Lane (#9)
Re: [PATCH 0/3] Work around icc miscompilation

On Thu, Jan 24, 2013 at 3:48 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

The fundamental problem here is that the compiler, unless told otherwise
by a compilation switch, believes it is entitled to assume that no
integer overflow will happen anywhere in the program. Therefore, any
error check that is looking for overflow *should* get optimized away.
The only reason the compiler would fail to do that is if its optimizer
isn't quite smart enough to prove that the code is testing for an
overflow condition.

He's changing things to do

if (INT_MAX - a > b)
PG_THROW ("a+b would overflow")
else
x=a+b;

Why would a smarter compiler be licensed to conclude that it can
optimize away anything? "INT_MAX-a > b" is always well defined. And
the x = a+b won't execute unless it's well defined too. (Actually
we'll probably depend on the non-local exit behaviour of PG_THROW but
any compiler has to be able to deal with that anyways).

The point that we have no way to be sure we've gotten rid of any such
case is a good one. Logically as long as we're afraid of such things
we should continue to use -fwrapv and if we're using -fwrapv there's
no urgency to fix the code. But if we do get rid of all the known ones
then at least we have the option if we decide we've inspected the code
enough and had enough compilers check it to feel confident.

--
greg

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#14Tom Lane
tgl@sss.pgh.pa.us
In reply to: Greg Stark (#13)
Re: [PATCH 0/3] Work around icc miscompilation

Greg Stark <stark@mit.edu> writes:

He's changing things to do

if (INT_MAX - a > b)
PG_THROW ("a+b would overflow")
else
x=a+b;

Why would a smarter compiler be licensed to conclude that it can
optimize away anything? "INT_MAX-a > b" is always well defined.

Really? Can't "INT_MAX - a" overflow?

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#15Xi Wang
xi.wang@gmail.com
In reply to: Tom Lane (#14)
Re: [PATCH 0/3] Work around icc miscompilation

It depends on the context. In the patches, `a' is known to be
non-negative, so `INT_MAX - a' cannot overflow. If you ignore the
context and talk about the general case, then it can.

- xi

On Sat, Feb 23, 2013 at 12:25 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Greg Stark <stark@mit.edu> writes:

He's changing things to do

if (INT_MAX - a > b)
PG_THROW ("a+b would overflow")
else
x=a+b;

Why would a smarter compiler be licensed to conclude that it can
optimize away anything? "INT_MAX-a > b" is always well defined.

Really? Can't "INT_MAX - a" overflow?

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#16Greg Stark
stark@mit.edu
In reply to: Tom Lane (#14)
Re: [PATCH 0/3] Work around icc miscompilation

On Sat, Feb 23, 2013 at 5:25 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Really? Can't "INT_MAX - a" overflow?

I guess I shouldn't have tried summarizing the code and just pasted
some real code in for fear of getting it wrong. I was thinking of
unsigned arithmetic when I wrote that.

The point being that the compiler isn't going to make optimization
based on code that comes later if that code wouldn't have run in the
same flow of execution.

--
greg

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#17Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Xi Wang (#1)
Re: [RFC] overflow checks optimized away

Xi Wang escribi�:

Intel's icc and PathScale's pathcc compilers optimize away several
overflow checks, since they consider signed integer overflow as
undefined behavior. This leads to a vulnerable binary.

This thread died without reaching a conclusion. Noah Misch, Robert Haas
and Greg Stark each gave a +1 to the patches, but Tom Lane gave them a
-inf; so they weren't applied. However, I think everyone walked away
with the feeling that Tom is wrong on this.

Meanwhile Xi Wang and team published a paper:
http://pdos.csail.mit.edu/~xi/papers/stack-sosp13.pdf

Postgres is mentioned a number of times in this paper -- mainly to talk
about the bugs we leave unfixed.

It might prove useful to have usable these guys' STACK checker output
available continuously, so that if we happen to introduce more bugs in
the future, it alerts us about that.

--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#18Robert Haas
robertmhaas@gmail.com
In reply to: Alvaro Herrera (#17)
Re: [RFC] overflow checks optimized away

On Mon, Jul 15, 2013 at 5:59 PM, Alvaro Herrera
<alvherre@2ndquadrant.com> wrote:

Xi Wang escribió:

Intel's icc and PathScale's pathcc compilers optimize away several
overflow checks, since they consider signed integer overflow as
undefined behavior. This leads to a vulnerable binary.

This thread died without reaching a conclusion. Noah Misch, Robert Haas
and Greg Stark each gave a +1 to the patches, but Tom Lane gave them a
-inf; so they weren't applied. However, I think everyone walked away
with the feeling that Tom is wrong on this.

Meanwhile Xi Wang and team published a paper:
http://pdos.csail.mit.edu/~xi/papers/stack-sosp13.pdf

Postgres is mentioned a number of times in this paper -- mainly to talk
about the bugs we leave unfixed.

It might prove useful to have usable these guys' STACK checker output
available continuously, so that if we happen to introduce more bugs in
the future, it alerts us about that.

Yeah, I think we ought to apply those patches. I don't suppose you
have links handy?

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#19Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Robert Haas (#18)
Re: [RFC] overflow checks optimized away

Robert Haas escribi�:

On Mon, Jul 15, 2013 at 5:59 PM, Alvaro Herrera
<alvherre@2ndquadrant.com> wrote:

Xi Wang escribi�:

Intel's icc and PathScale's pathcc compilers optimize away several
overflow checks, since they consider signed integer overflow as
undefined behavior. This leads to a vulnerable binary.

This thread died without reaching a conclusion. Noah Misch, Robert Haas
and Greg Stark each gave a +1 to the patches, but Tom Lane gave them a
-inf; so they weren't applied. However, I think everyone walked away
with the feeling that Tom is wrong on this.

Meanwhile Xi Wang and team published a paper:
http://pdos.csail.mit.edu/~xi/papers/stack-sosp13.pdf

Postgres is mentioned a number of times in this paper -- mainly to talk
about the bugs we leave unfixed.

It might prove useful to have usable these guys' STACK checker output
available continuously, so that if we happen to introduce more bugs in
the future, it alerts us about that.

Yeah, I think we ought to apply those patches. I don't suppose you
have links handy?

Sure, see this thread in the archives: first one is at
/messages/by-id/510100AA.4050105@gmail.com and you
can see the others in the dropdown (though since the subjects are not
shown, only date and author, it's a bit hard to follow. The "flat" URL
is useful.)

--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#20Bruce Momjian
bruce@momjian.us
In reply to: Alvaro Herrera (#19)
Re: [RFC] overflow checks optimized away

On Mon, Jul 15, 2013 at 06:19:27PM -0400, Alvaro Herrera wrote:

Robert Haas escribi�:

On Mon, Jul 15, 2013 at 5:59 PM, Alvaro Herrera
<alvherre@2ndquadrant.com> wrote:

Xi Wang escribi�:

Intel's icc and PathScale's pathcc compilers optimize away several
overflow checks, since they consider signed integer overflow as
undefined behavior. This leads to a vulnerable binary.

This thread died without reaching a conclusion. Noah Misch, Robert Haas
and Greg Stark each gave a +1 to the patches, but Tom Lane gave them a
-inf; so they weren't applied. However, I think everyone walked away
with the feeling that Tom is wrong on this.

Meanwhile Xi Wang and team published a paper:
http://pdos.csail.mit.edu/~xi/papers/stack-sosp13.pdf

Postgres is mentioned a number of times in this paper -- mainly to talk
about the bugs we leave unfixed.

It might prove useful to have usable these guys' STACK checker output
available continuously, so that if we happen to introduce more bugs in
the future, it alerts us about that.

Yeah, I think we ought to apply those patches. I don't suppose you
have links handy?

Sure, see this thread in the archives: first one is at
/messages/by-id/510100AA.4050105@gmail.com and you
can see the others in the dropdown (though since the subjects are not
shown, only date and author, it's a bit hard to follow. The "flat" URL
is useful.)

Should these patches be applied?

--
Bruce Momjian <bruce@momjian.us> http://momjian.us
EnterpriseDB http://enterprisedb.com

+ It's impossible for everything to be true. +

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#21Greg Stark
stark@mit.edu
In reply to: Bruce Momjian (#20)
Re: [RFC] overflow checks optimized away

Should these patches be applied?

I have a copy of the program and was going to take care of this.

--
greg

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#22Robert Haas
robertmhaas@gmail.com
In reply to: Greg Stark (#21)
Re: [RFC] overflow checks optimized away

On Sat, Sep 7, 2013 at 6:55 PM, Greg Stark <stark@mit.edu> wrote:

Should these patches be applied?

I have a copy of the program and was going to take care of this.

When?

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#23Bruce Momjian
bruce@momjian.us
In reply to: Robert Haas (#22)
Re: [RFC] overflow checks optimized away

On Mon, Sep 9, 2013 at 12:21:56PM -0400, Robert Haas wrote:

On Sat, Sep 7, 2013 at 6:55 PM, Greg Stark <stark@mit.edu> wrote:

Should these patches be applied?

I have a copy of the program and was going to take care of this.

When?

2.5 months later, status report?

--
Bruce Momjian <bruce@momjian.us> http://momjian.us
EnterpriseDB http://enterprisedb.com

+ Everyone has their own god. +

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#24Greg Stark
stark@mit.edu
In reply to: Bruce Momjian (#23)
1 attachment(s)
Re: [RFC] overflow checks optimized away

On Wed, Nov 27, 2013 at 10:48 PM, Bruce Momjian <bruce@momjian.us> wrote:

On Mon, Sep 9, 2013 at 12:21:56PM -0400, Robert Haas wrote:

On Sat, Sep 7, 2013 at 6:55 PM, Greg Stark <stark@mit.edu> wrote:

Should these patches be applied?

I have a copy of the program and was going to take care of this.

When?

2.5 months later, status report?

Attached is what I have so far. I have to say I'm starting to come
around to Tom's point of view. This is a lot of hassle for not much
gain. i've noticed a number of other overflow checks that the llvm
optimizer is not picking up on so even after this patch it's not clear
that all the signed overflow checks that depend on -fwrapv will be
gone.

This patch still isn't quite finished though.

a) It triggers a spurious gcc warning about overflows on constant
expressions. These value of these expressions aren't actually being
used as they're used in the other branch of the overflow test. I think
I see how to work around it for gcc using __builtin_choose_expr but it
might be pretty grotty.

b) I'm concerned these checks depend on INT_MIN/MAX and SHRT_MIN/MAX
which may not be exactly the right length. I'm kind of confused why
c.h assumes long is 32 bits and short is 16 bits though so I don't
think I'm making it any worse. It may be better for us to just define
our own limits since we know exactly how large we expect these data
types to be.

c) I want to add regression tests that will ensure that the overflow
checks are all working. So far I haven't been able to catch any being
optimized away even with -fno-wrapv and -fstrict-overflow. I think I
just didn't build with the right options though and it should be
possible.

The goal here imho is to allow building with -fno-wrapv
-fstrict-overflow safely. Whether we actually do or not is another
question but it means we would be able to use new compilers like clang
without worrying about finding the equivalent of -fwrapv for them.

--
greg

Attachments:

overflow.difftext/plain; charset=US-ASCII; name=overflow.diffDownload
*** a/.gitignore
--- b/.gitignore
***************
*** 34,36 **** lib*.pc
--- 34,38 ----
  /pgsql.sln.cache
  /Debug/
  /Release/
+ *.ll
+ *.ll.out
*** a/src/backend/commands/view.c
--- b/src/backend/commands/view.c
***************
*** 342,347 **** UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse)
--- 342,348 ----
  	List	   *new_rt;
  	RangeTblEntry *rt_entry1,
  			   *rt_entry2;
+ 	ParseState *pstate;
  
  	/*
  	 * Make a copy of the given parsetree.	It's not so much that we don't
***************
*** 360,371 **** UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse)
  	 * Create the 2 new range table entries and form the new range table...
  	 * OLD first, then NEW....
  	 */
! 	rt_entry1 = addRangeTableEntryForRelation(NULL, viewRel,
  											  makeAlias("old", NIL),
  											  false, false);
! 	rt_entry2 = addRangeTableEntryForRelation(NULL, viewRel,
  											  makeAlias("new", NIL),
  											  false, false);
  	/* Must override addRangeTableEntry's default access-check flags */
  	rt_entry1->requiredPerms = 0;
  	rt_entry2->requiredPerms = 0;
--- 361,377 ----
  	 * Create the 2 new range table entries and form the new range table...
  	 * OLD first, then NEW....
  	 */
! 
! 	pstate = make_parsestate(NULL);
! 
! 	rt_entry1 = addRangeTableEntryForRelation(pstate, viewRel,
  											  makeAlias("old", NIL),
  											  false, false);
! 	rt_entry2 = addRangeTableEntryForRelation(pstate, viewRel,
  											  makeAlias("new", NIL),
  											  false, false);
+ 	free_parsestate(pstate);
+ 
  	/* Must override addRangeTableEntry's default access-check flags */
  	rt_entry1->requiredPerms = 0;
  	rt_entry2->requiredPerms = 0;
*** a/src/backend/executor/execQual.c
--- b/src/backend/executor/execQual.c
***************
*** 3095,3105 **** 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)
  					ereport(ERROR,
  							(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
! 						  errmsg("number of array dimensions (%d) exceeds " \
! 								 "the maximum allowed (%d)", ndims, MAXDIM)));
  
  				elem_dims = (int *) palloc(elem_ndims * sizeof(int));
  				memcpy(elem_dims, ARR_DIMS(array), elem_ndims * sizeof(int));
--- 3095,3106 ----
  				/* Get sub-array details from first member */
  				elem_ndims = this_ndims;
  				ndims = elem_ndims + 1;
! 
! 				if (INT32_ADD_OVERFLOWS(elem_ndims,1) || ndims > MAXDIM)
  					ereport(ERROR,
  							(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
! 							 errmsg("number of array dimensions (%d) exceeds " \
! 									"the maximum allowed (%d)", ndims, MAXDIM)));
  
  				elem_dims = (int *) palloc(elem_ndims * sizeof(int));
  				memcpy(elem_dims, ARR_DIMS(array), elem_ndims * sizeof(int));
*** a/src/backend/optimizer/plan/subselect.c
--- b/src/backend/optimizer/plan/subselect.c
***************
*** 1168,1173 **** convert_ANY_sublink_to_join(PlannerInfo *root, SubLink *sublink,
--- 1168,1174 ----
  	Query	   *parse = root->parse;
  	Query	   *subselect = (Query *) sublink->subselect;
  	Relids		upper_varnos;
+ 	ParseState *pstate;
  	int			rtindex;
  	RangeTblEntry *rte;
  	RangeTblRef *rtr;
***************
*** 1212,1222 **** convert_ANY_sublink_to_join(PlannerInfo *root, SubLink *sublink,
  	 * below). Therefore this is a lot easier than what pull_up_subqueries has
  	 * to go through.
  	 */
! 	rte = addRangeTableEntryForSubquery(NULL,
  										subselect,
  										makeAlias("ANY_subquery", NIL),
  										false,
  										false);
  	parse->rtable = lappend(parse->rtable, rte);
  	rtindex = list_length(parse->rtable);
  
--- 1213,1225 ----
  	 * below). Therefore this is a lot easier than what pull_up_subqueries has
  	 * to go through.
  	 */
! 	pstate = make_parsestate(NULL);
! 	rte = addRangeTableEntryForSubquery(pstate,
  										subselect,
  										makeAlias("ANY_subquery", NIL),
  										false,
  										false);
+ 	free_parsestate(pstate);
  	parse->rtable = lappend(parse->rtable, rte);
  	rtindex = list_length(parse->rtable);
  
*** a/src/backend/parser/parse_relation.c
--- b/src/backend/parser/parse_relation.c
***************
*** 981,989 **** parserOpenTable(ParseState *pstate, const RangeVar *relation, int lockmode)
  /*
   * Add an entry for a relation to the pstate's range table (p_rtable).
   *
-  * If pstate is NULL, we just build an RTE and return it without adding it
-  * to an rtable list.
-  *
   * Note: formerly this checked for refname conflicts, but that's wrong.
   * Caller is responsible for checking for conflicts in the appropriate scope.
   */
--- 981,986 ----
***************
*** 1002,1007 **** addRangeTableEntry(ParseState *pstate,
--- 999,1006 ----
  	rte->rtekind = RTE_RELATION;
  	rte->alias = alias;
  
+ 	Assert(pstate);
+ 
  	/*
  	 * Get the rel's OID.  This access also ensures that we have an up-to-date
  	 * relcache entry for the rel.	Since this is typically the first access
***************
*** 1046,1053 **** addRangeTableEntry(ParseState *pstate,
  	 * Add completed RTE to pstate's range table list, but not to join list
  	 * nor namespace --- caller must do that if appropriate.
  	 */
! 	if (pstate != NULL)
! 		pstate->p_rtable = lappend(pstate->p_rtable, rte);
  
  	return rte;
  }
--- 1045,1051 ----
  	 * Add completed RTE to pstate's range table list, but not to join list
  	 * nor namespace --- caller must do that if appropriate.
  	 */
! 	pstate->p_rtable = lappend(pstate->p_rtable, rte);
  
  	return rte;
  }
***************
*** 1073,1078 **** addRangeTableEntryForRelation(ParseState *pstate,
--- 1071,1078 ----
  	rte->relid = RelationGetRelid(rel);
  	rte->relkind = rel->rd_rel->relkind;
  
+ 	Assert(pstate);
+ 
  	/*
  	 * Build the list of effective column names using user-supplied aliases
  	 * and/or actual column names.
***************
*** 1099,1106 **** addRangeTableEntryForRelation(ParseState *pstate,
  	 * Add completed RTE to pstate's range table list, but not to join list
  	 * nor namespace --- caller must do that if appropriate.
  	 */
! 	if (pstate != NULL)
! 		pstate->p_rtable = lappend(pstate->p_rtable, rte);
  
  	return rte;
  }
--- 1099,1105 ----
  	 * Add completed RTE to pstate's range table list, but not to join list
  	 * nor namespace --- caller must do that if appropriate.
  	 */
! 	pstate->p_rtable = lappend(pstate->p_rtable, rte);
  
  	return rte;
  }
***************
*** 1125,1130 **** addRangeTableEntryForSubquery(ParseState *pstate,
--- 1124,1131 ----
  	int			varattno;
  	ListCell   *tlistitem;
  
+ 	Assert(pstate);
+ 
  	rte->rtekind = RTE_SUBQUERY;
  	rte->relid = InvalidOid;
  	rte->subquery = subquery;
***************
*** 1177,1184 **** addRangeTableEntryForSubquery(ParseState *pstate,
  	 * Add completed RTE to pstate's range table list, but not to join list
  	 * nor namespace --- caller must do that if appropriate.
  	 */
! 	if (pstate != NULL)
! 		pstate->p_rtable = lappend(pstate->p_rtable, rte);
  
  	return rte;
  }
--- 1178,1184 ----
  	 * Add completed RTE to pstate's range table list, but not to join list
  	 * nor namespace --- caller must do that if appropriate.
  	 */
! 	pstate->p_rtable = lappend(pstate->p_rtable, rte);
  
  	return rte;
  }
***************
*** 1214,1219 **** addRangeTableEntryForFunction(ParseState *pstate,
--- 1214,1221 ----
  	int			natts,
  				totalatts;
  
+ 	Assert(pstate);
+ 
  	rte->rtekind = RTE_FUNCTION;
  	rte->relid = InvalidOid;
  	rte->subquery = NULL;
***************
*** 1431,1438 **** addRangeTableEntryForFunction(ParseState *pstate,
  	 * Add completed RTE to pstate's range table list, but not to join list
  	 * nor namespace --- caller must do that if appropriate.
  	 */
! 	if (pstate != NULL)
! 		pstate->p_rtable = lappend(pstate->p_rtable, rte);
  
  	return rte;
  }
--- 1433,1439 ----
  	 * Add completed RTE to pstate's range table list, but not to join list
  	 * nor namespace --- caller must do that if appropriate.
  	 */
! 	pstate->p_rtable = lappend(pstate->p_rtable, rte);
  
  	return rte;
  }
***************
*** 1456,1461 **** addRangeTableEntryForValues(ParseState *pstate,
--- 1457,1464 ----
  	int			numaliases;
  	int			numcolumns;
  
+ 	Assert(pstate);
+ 
  	rte->rtekind = RTE_VALUES;
  	rte->relid = InvalidOid;
  	rte->subquery = NULL;
***************
*** 1503,1510 **** addRangeTableEntryForValues(ParseState *pstate,
  	 * Add completed RTE to pstate's range table list, but not to join list
  	 * nor namespace --- caller must do that if appropriate.
  	 */
! 	if (pstate != NULL)
! 		pstate->p_rtable = lappend(pstate->p_rtable, rte);
  
  	return rte;
  }
--- 1506,1512 ----
  	 * Add completed RTE to pstate's range table list, but not to join list
  	 * nor namespace --- caller must do that if appropriate.
  	 */
! 	pstate->p_rtable = lappend(pstate->p_rtable, rte);
  
  	return rte;
  }
***************
*** 1526,1531 **** addRangeTableEntryForJoin(ParseState *pstate,
--- 1528,1535 ----
  	Alias	   *eref;
  	int			numaliases;
  
+ 	Assert(pstate);
+ 
  	/*
  	 * Fail if join has too many columns --- we must be able to reference any
  	 * of the columns with an AttrNumber.
***************
*** 1571,1578 **** addRangeTableEntryForJoin(ParseState *pstate,
  	 * Add completed RTE to pstate's range table list, but not to join list
  	 * nor namespace --- caller must do that if appropriate.
  	 */
! 	if (pstate != NULL)
! 		pstate->p_rtable = lappend(pstate->p_rtable, rte);
  
  	return rte;
  }
--- 1575,1581 ----
  	 * Add completed RTE to pstate's range table list, but not to join list
  	 * nor namespace --- caller must do that if appropriate.
  	 */
! 	pstate->p_rtable = lappend(pstate->p_rtable, rte);
  
  	return rte;
  }
***************
*** 1597,1602 **** addRangeTableEntryForCTE(ParseState *pstate,
--- 1600,1607 ----
  	int			varattno;
  	ListCell   *lc;
  
+ 	Assert(pstate);
+ 
  	rte->rtekind = RTE_CTE;
  	rte->ctename = cte->ctename;
  	rte->ctelevelsup = levelsup;
***************
*** 1671,1678 **** addRangeTableEntryForCTE(ParseState *pstate,
  	 * Add completed RTE to pstate's range table list, but not to join list
  	 * nor namespace --- caller must do that if appropriate.
  	 */
! 	if (pstate != NULL)
! 		pstate->p_rtable = lappend(pstate->p_rtable, rte);
  
  	return rte;
  }
--- 1676,1682 ----
  	 * Add completed RTE to pstate's range table list, but not to join list
  	 * nor namespace --- caller must do that if appropriate.
  	 */
! 	pstate->p_rtable = lappend(pstate->p_rtable, rte);
  
  	return rte;
  }
*** a/src/backend/storage/lmgr/proc.c
--- b/src/backend/storage/lmgr/proc.c
***************
*** 1120,1125 **** ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
--- 1120,1127 ----
  	 */
  	do
  	{
+ 		PGPROC *autovac;
+ 
  		PGSemaphoreLock(&MyProc->sem, true);
  
  		/*
***************
*** 1133,1141 **** ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
  		 * If we are not deadlocked, but are waiting on an autovacuum-induced
  		 * task, send a signal to interrupt it.
  		 */
! 		if (deadlock_state == DS_BLOCKED_BY_AUTOVACUUM && allow_autovacuum_cancel)
  		{
- 			PGPROC	   *autovac = GetBlockingAutoVacuumPgproc();
  			PGXACT	   *autovac_pgxact = &ProcGlobal->allPgXact[autovac->pgprocno];
  
  			LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
--- 1135,1144 ----
  		 * If we are not deadlocked, but are waiting on an autovacuum-induced
  		 * task, send a signal to interrupt it.
  		 */
! 		if (deadlock_state == DS_BLOCKED_BY_AUTOVACUUM && 
! 			allow_autovacuum_cancel &&
! 			(autovac = GetBlockingAutoVacuumPgproc()))
  		{
  			PGXACT	   *autovac_pgxact = &ProcGlobal->allPgXact[autovac->pgprocno];
  
  			LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
*** a/src/backend/utils/adt/array_userfuncs.c
--- b/src/backend/utils/adt/array_userfuncs.c
***************
*** 93,116 **** array_push(PG_FUNCTION_ARGS)
  		if (arg0_elemid != InvalidOid)
  		{
  			/* append newelem */
- 			int			ub = dimv[0] + lb[0] - 1;
  
! 			indx = ub + 1;
! 			/* overflow? */
! 			if (indx < ub)
  				ereport(ERROR,
  						(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  						 errmsg("integer out of range")));
  		}
  		else
  		{
  			/* prepend newelem */
! 			indx = lb[0] - 1;
! 			/* overflow? */
! 			if (indx > lb[0])
  				ereport(ERROR,
  						(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  						 errmsg("integer out of range")));
  		}
  	}
  	else if (ARR_NDIM(v) == 0)
--- 93,117 ----
  		if (arg0_elemid != InvalidOid)
  		{
  			/* append newelem */
  
! 			/* check for overflow in upper bound (indx+1) */
! 			if (INT32_ADD_OVERFLOWS(dimv[0],lb[0]) || 
! 				INT32_ADD_OVERFLOWS(dimv[0]+lb[0],1))
  				ereport(ERROR,
  						(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  						 errmsg("integer out of range")));
+ 
+ 			indx = dimv[0] + lb[0];
  		}
  		else
  		{
  			/* prepend newelem */
! 			if (INT32_ADD_OVERFLOWS(lb[0],-1))
  				ereport(ERROR,
  						(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  						 errmsg("integer out of range")));
+ 
+ 			indx = lb[0] - 1;
  		}
  	}
  	else if (ARR_NDIM(v) == 0)
*** a/src/backend/utils/adt/float.c
--- b/src/backend/utils/adt/float.c
***************
*** 2752,2763 **** width_bucket_float8(PG_FUNCTION_ARGS)
  			result = 0;
  		else if (operand >= bound2)
  		{
- 			result = count + 1;
  			/* check for overflow */
! 			if (result < count)
  				ereport(ERROR,
  						(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  						 errmsg("integer out of range")));
  		}
  		else
  			result = ((float8) count * (operand - bound1) / (bound2 - bound1)) + 1;
--- 2752,2763 ----
  			result = 0;
  		else if (operand >= bound2)
  		{
  			/* check for overflow */
! 			if (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;
***************
*** 2768,2779 **** width_bucket_float8(PG_FUNCTION_ARGS)
  			result = 0;
  		else if (operand <= bound2)
  		{
- 			result = count + 1;
  			/* check for overflow */
! 			if (result < count)
  				ereport(ERROR,
  						(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  						 errmsg("integer out of range")));
  		}
  		else
  			result = ((float8) count * (bound1 - operand) / (bound1 - bound2)) + 1;
--- 2768,2779 ----
  			result = 0;
  		else if (operand <= bound2)
  		{
  			/* check for overflow */
! 			if (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;
*** a/src/backend/utils/adt/int.c
--- b/src/backend/utils/adt/int.c
***************
*** 694,704 **** int4mul(PG_FUNCTION_ARGS)
  	 * 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))
  		ereport(ERROR,
  				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  				 errmsg("integer out of range")));
--- 694,700 ----
  	 * the buck seems to be to check whether both inputs are in the int16
  	 * range; if so, no overflow is possible.
  	 */
! 	if (INT32_MUL_OVERFLOWS(arg1, arg2))
  		ereport(ERROR,
  				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  				 errmsg("integer out of range")));
***************
*** 749,779 **** Datum
  int4inc(PG_FUNCTION_ARGS)
  {
  	int32		arg = PG_GETARG_INT32(0);
- 	int32		result;
  
! 	result = arg + 1;
! 	/* Overflow check */
! 	if (arg > 0 && result < 0)
  		ereport(ERROR,
  				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  				 errmsg("integer out of range")));
  
! 	PG_RETURN_INT32(result);
  }
  
  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))
  		ereport(ERROR,
  				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  				 errmsg("smallint out of range")));
! 	PG_RETURN_INT16(result);
  }
  
  Datum
--- 745,769 ----
  int4inc(PG_FUNCTION_ARGS)
  {
  	int32		arg = PG_GETARG_INT32(0);
  
! 	if (INT32_ADD_OVERFLOWS(arg, 1))
  		ereport(ERROR,
  				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  				 errmsg("integer out of range")));
  
! 	PG_RETURN_INT32(arg + 1);
  }
  
  Datum
  int2um(PG_FUNCTION_ARGS)
  {
  	int16		arg = PG_GETARG_INT16(0);
  
! 	if (arg == SHRT_MIN)
  		ereport(ERROR,
  				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  				 errmsg("smallint out of range")));
! 	PG_RETURN_INT16(-arg);
  }
  
  Datum
*** a/src/backend/utils/adt/int8.c
--- b/src/backend/utils/adt/int8.c
***************
*** 102,120 **** 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 (errorOK)
  				return false;
  			else
  				ereport(ERROR,
  						(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
! 					   errmsg("value \"%s\" is out of range for type bigint",
! 							  str)));
  		}
! 		tmp = newtmp;
  	}
  
  gotdigits:
--- 102,120 ----
  	/* process digits */
  	while (*ptr && isdigit((unsigned char) *ptr))
  	{
! 		if (INT64_MUL_OVERFLOWS(tmp, 10) ||
! 			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)));
  		}
! 
! 		tmp = tmp * 10 + (*ptr++ - '0');
  	}
  
  gotdigits:
***************
*** 490,504 **** 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))
  		ereport(ERROR,
  				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  				 errmsg("bigint out of range")));
! 	PG_RETURN_INT64(result);
  }
  
  Datum
--- 490,501 ----
  int8um(PG_FUNCTION_ARGS)
  {
  	int64		arg = PG_GETARG_INT64(0);
  
! 	if (arg == INT64_MIN)
  		ereport(ERROR,
  				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  				 errmsg("bigint out of range")));
! 	PG_RETURN_INT64(-arg);
  }
  
  Datum
***************
*** 518,529 **** int8pl(PG_FUNCTION_ARGS)
  
  	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))
  		ereport(ERROR,
  				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  				 errmsg("bigint out of range")));
--- 515,522 ----
  
  	result = arg1 + arg2;
  
! 	/* Overflow check. */
! 	if (INT64_ADD_OVERFLOWS(arg1, arg2))
  		ereport(ERROR,
  				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  				 errmsg("bigint out of range")));
***************
*** 540,550 **** int8mi(PG_FUNCTION_ARGS)
  	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))
  		ereport(ERROR,
  				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  				 errmsg("bigint out of range")));
--- 533,541 ----
  	result = arg1 - arg2;
  
  	/*
! 	 * Overflow check. 
  	 */
! 	if (INT64_SUB_OVERFLOWS(arg1, arg2))
  		ereport(ERROR,
  				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  				 errmsg("bigint out of range")));
***************
*** 558,585 **** int8mul(PG_FUNCTION_ARGS)
  	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);
  }
  
--- 549,561 ----
  	int64		arg2 = PG_GETARG_INT64(1);
  	int64		result;
  
+ 	if (INT64_MUL_OVERFLOWS(arg1, arg2))
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ 				 errmsg("bigint out of range")));
+ 
  	result = arg1 * arg2;
  
  	PG_RETURN_INT64(result);
  }
  
***************
*** 607,618 **** int8div(PG_FUNCTION_ARGS)
  	 */
  	if (arg2 == -1)
  	{
! 		result = -arg1;
! 		/* overflow check (needed for INT64_MIN) */
! 		if (arg1 != 0 && SAMESIGN(result, arg1))
  			ereport(ERROR,
  					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  					 errmsg("bigint out of range")));
  		PG_RETURN_INT64(result);
  	}
  
--- 583,594 ----
  	 */
  	if (arg2 == -1)
  	{
! 		if (arg1 == INT64_MIN)
  			ereport(ERROR,
  					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  					 errmsg("bigint out of range")));
+ 
+ 		result = -arg1;
  		PG_RETURN_INT64(result);
  	}
  
***************
*** 632,643 **** 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)
  		ereport(ERROR,
  				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  				 errmsg("bigint out of range")));
  	PG_RETURN_INT64(result);
  }
  
--- 608,619 ----
  	int64		arg1 = PG_GETARG_INT64(0);
  	int64		result;
  
! 	if (arg1 == 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,701 **** int8inc(PG_FUNCTION_ARGS)
  	if (AggCheckCallContext(fcinfo, NULL))
  	{
  		int64	   *arg = (int64 *) PG_GETARG_POINTER(0);
! 		int64		result;
  
! 		result = *arg + 1;
! 		/* Overflow check */
! 		if (result < 0 && *arg > 0)
  			ereport(ERROR,
  					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  					 errmsg("bigint out of range")));
! 
  		*arg = result;
  		PG_RETURN_POINTER(arg);
  	}
--- 663,675 ----
  	if (AggCheckCallContext(fcinfo, NULL))
  	{
  		int64	   *arg = (int64 *) PG_GETARG_POINTER(0);
! 		int64		result = *arg;
  
! 		if (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,719 **** 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)
  			ereport(ERROR,
  					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  					 errmsg("bigint out of range")));
! 
! 		PG_RETURN_INT64(result);
  	}
  }
  
--- 678,689 ----
  	{
  		/* Not called as an aggregate, so just do it the dumb way */
  		int64		arg = PG_GETARG_INT64(0);
  
! 		if (INT64_ADD_OVERFLOWS(arg, 1))
  			ereport(ERROR,
  					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  					 errmsg("bigint out of range")));
! 		PG_RETURN_INT64(arg + 1);
  	}
  }
  
***************
*** 768,787 **** 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))
  		ereport(ERROR,
  				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  				 errmsg("bigint out of range")));
! 	PG_RETURN_INT64(result);
  }
  
  Datum
--- 738,750 ----
  {
  	int64		arg1 = PG_GETARG_INT64(0);
  	int32		arg2 = PG_GETARG_INT32(1);
  
! 	if (INT64_ADD_OVERFLOWS(arg1, arg2))
  		ereport(ERROR,
  				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  				 errmsg("bigint out of range")));
! 
! 	PG_RETURN_INT64(arg1 + arg2);
  }
  
  Datum
***************
*** 789,808 **** 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))
  		ereport(ERROR,
  				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  				 errmsg("bigint out of range")));
! 	PG_RETURN_INT64(result);
  }
  
  Datum
--- 752,764 ----
  {
  	int64		arg1 = PG_GETARG_INT64(0);
  	int32		arg2 = PG_GETARG_INT32(1);
  
! 	if (INT64_SUB_OVERFLOWS(arg1, arg2))
  		ereport(ERROR,
  				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  				 errmsg("bigint out of range")));
! 
! 	PG_RETURN_INT64(arg1 - arg2);
  }
  
  Datum
***************
*** 810,835 **** 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)
  		ereport(ERROR,
  				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  				 errmsg("bigint out of range")));
! 	PG_RETURN_INT64(result);
  }
  
  Datum
--- 766,778 ----
  {
  	int64		arg1 = PG_GETARG_INT64(0);
  	int32		arg2 = PG_GETARG_INT32(1);
  
! 	if (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
***************
*** 856,868 **** int84div(PG_FUNCTION_ARGS)
  	 */
  	if (arg2 == -1)
  	{
! 		result = -arg1;
! 		/* overflow check (needed for INT64_MIN) */
! 		if (arg1 != 0 && SAMESIGN(result, arg1))
  			ereport(ERROR,
  					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  					 errmsg("bigint out of range")));
! 		PG_RETURN_INT64(result);
  	}
  
  	/* No overflow is possible */
--- 799,809 ----
  	 */
  	if (arg2 == -1)
  	{
! 		if (arg1 == INT64_MIN)
  			ereport(ERROR,
  					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  					 errmsg("bigint out of range")));
! 		PG_RETURN_INT64(-arg1);
  	}
  
  	/* No overflow is possible */
***************
*** 877,896 **** 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))
  		ereport(ERROR,
  				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  				 errmsg("bigint out of range")));
! 	PG_RETURN_INT64(result);
  }
  
  Datum
--- 818,829 ----
  {
  	int32		arg1 = PG_GETARG_INT32(0);
  	int64		arg2 = PG_GETARG_INT64(1);
  
! 	if (INT64_ADD_OVERFLOWS(arg1, arg2))
  		ereport(ERROR,
  				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  				 errmsg("bigint out of range")));
! 	PG_RETURN_INT64(arg1 + arg2);
  }
  
  Datum
*** a/src/backend/utils/adt/numeric.c
--- b/src/backend/utils/adt/numeric.c
***************
*** 3943,3950 **** numericvar_to_int8(NumericVar *var, int64 *result)
  	int			ndigits;
  	int			weight;
  	int			i;
! 	int64		val,
! 				oldval;
  	bool		neg;
  	NumericVar	rounded;
  
--- 3943,3949 ----
  	int			ndigits;
  	int			weight;
  	int			i;
! 	int64		val;
  	bool		neg;
  	NumericVar	rounded;
  
***************
*** 3970,4006 **** numericvar_to_int8(NumericVar *var, int64 *result)
  	weight = rounded.weight;
  	Assert(weight >= 0 && ndigits <= weight + 1);
  
! 	/* Construct the result */
  	digits = rounded.digits;
  	neg = (rounded.sign == NUMERIC_NEG);
! 	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)
  			{
  				free_var(&rounded);
  				return false;
  			}
! 		}
  	}
  
  	free_var(&rounded);
  
! 	*result = neg ? -val : val;
  	return true;
  }
  
--- 3969,4003 ----
  	weight = rounded.weight;
  	Assert(weight >= 0 && ndigits <= weight + 1);
  
! 	/* Construct the result. 
! 	 *
! 	 * Accumulate the absolute value in "val" as a negative value to avoid
! 	 * overflow with INT64_MIN.
! 	 */
  	digits = rounded.digits;
  	neg = (rounded.sign == NUMERIC_NEG);
! 	val = -digits[0];
  	for (i = 1; i <= weight; i++)
  	{
! 		NumericDigit digit = (i < ndigits) ? digits[i] : 0;
! 		if (INT64_MUL_OVERFLOWS(val, NBASE) ||
! 			INT64_SUB_OVERFLOWS(val*NBASE, digit))
  			{
  				free_var(&rounded);
  				return false;
  			}
! 		val = val * NBASE - digit;
  	}
  
  	free_var(&rounded);
  
! 	if (!neg && val == INT64_MIN)
! 		/* overflows signed int64 */
! 		return false;
! 	else if (!neg)
! 		*result = -val;
! 	else
! 		*result = val;
  	return true;
  }
  
*** a/src/backend/utils/adt/oracle_compat.c
--- b/src/backend/utils/adt/oracle_compat.c
***************
*** 15,20 ****
--- 15,22 ----
   */
  #include "postgres.h"
  
+ #include <limits.h>
+ 
  #include "utils/builtins.h"
  #include "utils/formatting.h"
  #include "mb/pg_wchar.h"
***************
*** 175,188 **** 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)
  		ereport(ERROR,
  				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
  				 errmsg("requested length too large")));
  
  	ret = (text *) palloc(VARHDRSZ + bytelen);
  
  	m = len - s1len;
--- 177,190 ----
  	if (s2len <= 0)
  		len = s1len;			/* nothing to pad with, so don't pad */
  
  	/* check for integer overflow */
! 	if (len > INT_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;
***************
*** 1030,1052 **** repeat(PG_FUNCTION_ARGS)
  	char	   *cp,
  			   *sp;
  
  	if (count < 0)
  		count = 0;
  
! 	slen = VARSIZE_ANY_EXHDR(string);
! 	tlen = VARHDRSZ + (count * slen);
! 
! 	/* Check for integer overflow */
! 	if (slen != 0 && count != 0)
! 	{
! 		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")));
! 	}
  
  	result = (text *) palloc(tlen);
  
--- 1032,1051 ----
  	char	   *cp,
  			   *sp;
  
+ 	slen = VARSIZE_ANY_EXHDR(string);
+ 
  	if (count < 0)
  		count = 0;
  
! 	else if (slen != 0 && count > (INT_MAX-VARHDRSZ) / slen)
! 		/* 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);
  
*** a/src/backend/utils/adt/varbit.c
--- b/src/backend/utils/adt/varbit.c
***************
*** 1026,1041 **** 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)
  			ereport(ERROR,
  					(errcode(ERRCODE_SUBSTRING_ERROR),
  					 errmsg("negative substring length not allowed")));
  		e1 = Min(e, bitlen + 1);
  	}
  	if (s1 > bitlen || e1 <= s1)
--- 1026,1037 ----
  	}
  	else
  	{
! 		/* 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)
***************
*** 1138,1149 **** 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)
  		ereport(ERROR,
  				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  				 errmsg("integer out of range")));
  
  	s1 = bitsubstring(t1, 1, sp - 1, false);
  	s2 = bitsubstring(t1, sp_pl_sl, -1, true);
  	result = bit_catenate(s1, t2);
--- 1134,1147 ----
  		ereport(ERROR,
  				(errcode(ERRCODE_SUBSTRING_ERROR),
  				 errmsg("negative substring length not allowed")));
! 
! 	if (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);
*** a/src/backend/utils/adt/varlena.c
--- b/src/backend/utils/adt/varlena.c
***************
*** 782,813 **** 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 */
  			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.
! 			 */
! 			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 = E - S1;
  		}
  
  		/*
--- 782,813 ----
  	{
  		S1 = Max(S, 1);
  
! 		/* 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 (INT_MAX - length < start)
+ 			/* overflow (but the string can't be that large so just get length
+ 			 * to end of string) */
+ 			L1 = -1;
+ 
  		else
  		{
! 			/* 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 */
  
! 			L1 = S + length - S1;
  
! 			if (L1 <= 0)
  				return cstring_to_text("");
  		}
  
  		/*
***************
*** 847,869 **** 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 */
  			slice_size = L1 = -1;
  		else
  		{
  			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.
- 			 */
- 			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.
--- 847,872 ----
  		 */
  		slice_start = 0;
  
! 		if (length_not_specified)
! 			/* special case - get length to end of string */
! 			slice_size = 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 (INT_MAX - length < start)
! 			/* overflow but the string can't be that large so just get length
! 			 * to end of string */
  			slice_size = L1 = -1;
+ 
  		else
  		{
  			int			E = S + length;
  
  			/*
  			 * 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.
***************
*** 1006,1017 **** 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)
  		ereport(ERROR,
  				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  				 errmsg("integer out of range")));
  
  	s1 = text_substring(PointerGetDatum(t1), 1, sp - 1, false);
  	s2 = text_substring(PointerGetDatum(t1), sp_pl_sl, -1, true);
  	result = text_catenate(s1, t2);
--- 1009,1022 ----
  		ereport(ERROR,
  				(errcode(ERRCODE_SUBSTRING_ERROR),
  				 errmsg("negative substring length not allowed")));
! 
! 	if (INT_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);
***************
*** 1949,1969 **** bytea_substring(Datum str,
  		 */
  		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.
--- 1954,1976 ----
  		 */
  		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 (INT_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 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.
***************
*** 2029,2040 **** 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)
  		ereport(ERROR,
  				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  				 errmsg("integer out of range")));
  
  	s1 = bytea_substring(PointerGetDatum(t1), 1, sp - 1, false);
  	s2 = bytea_substring(PointerGetDatum(t1), sp_pl_sl, -1, true);
  	result = bytea_catenate(s1, t2);
--- 2036,2049 ----
  		ereport(ERROR,
  				(errcode(ERRCODE_SUBSTRING_ERROR),
  				 errmsg("negative substring length not allowed")));
! 
! 	if (INT_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);
*** a/src/include/c.h
--- b/src/include/c.h
***************
*** 81,86 ****
--- 81,87 ----
  #include <stdint.h>
  #endif
  #include <sys/types.h>
+ #include <limits.h>
  
  #include <errno.h>
  #if defined(WIN32) || defined(__CYGWIN__)
***************
*** 272,277 **** typedef long int int64;
--- 273,285 ----
  #ifndef HAVE_UINT64
  typedef unsigned long int uint64;
  #endif
+ #ifndef INT64_MAX
+ #define INT64_MAX LONG_MAX
+ #endif
+ #ifndef INT64_MIN
+ #define INT64_MIN LONG_MIN
+ #endif
+ 
  #elif defined(HAVE_LONG_LONG_INT_64)
  /* We have working support for "long long int", use that */
  
***************
*** 281,286 **** typedef long long int int64;
--- 289,309 ----
  #ifndef HAVE_UINT64
  typedef unsigned long long int uint64;
  #endif
+ #ifndef INT64_MAX
+ #ifdef LLONG_MAX
+ #define INT64_MAX LLONG_MAX
+ #else
+ #define INT64_MAX INT64CONST(0x7FFFFFFFFFFFFFFF)
+ #endif
+ #endif
+ #ifndef INT64_MIN
+ #ifdef LLONG_MIN
+ #define INT64_MIN LLONG_MIN
+ #else
+ #define INT64_MIN (-INT64_MAX-1)
+ #endif
+ #endif
+ 
  #else
  /* neither HAVE_LONG_INT_64 nor HAVE_LONG_LONG_INT_64 */
  #error must have a working 64-bit integer datatype
***************
*** 713,718 **** typedef NameData *Name;
--- 736,808 ----
  #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 INT32_ADD_OVERFLOWS(a,b) (					\
+ 		((a)>0 && (b)>0 && (a) > INT_MAX - (b)) ||	\
+ 		((a)<0 && (b)<0 && (a) < INT_MIN - (b))		\
+ 		)
+ 
+ #define INT32_SUB_OVERFLOWS(a,b) (						\
+ 		((a)<0 && (b)>0 && (a) < INT_MIN + (b)) ||		\
+ 		((a)>0 && (b)<0 && (a) > INT_MAX + (b))			\
+ 		)
+ 
+ #define INT64_ADD_OVERFLOWS(a,b) (						\
+ 		((a)>0 && (b)>0 && (a) > INT64_MAX - (b)) ||	\
+ 		((a)<0 && (b)<0 && (a) < INT64_MIN - (b))		\
+ 		)
+ 
+ #define INT64_SUB_OVERFLOWS(a,b) (							\
+ 		((a)<0 && (b)>0 && (a) < INT64_MIN + (b)) ||		\
+ 		((a)>0 && (b)<0 && (a) > 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
+  * INT_MIN by -1 also, note reversing the a and b to ensure we're always
+  * dividing it by a positive value.
+  *
+  */
+ 
+ #define INT32_MUL_OVERFLOWS(a,b) (										\
+ 		((a) > SHRT_MAX || (a) < SHRT_MIN  ||							\
+ 		 (b) > SHRT_MAX || (b) < SHRT_MIN) &&							\
+ 		(a) != 0 && (a) != 1 && (b) != 0 && (b) != 1 &&					\
+ 		(																\
+  			((a) > 0 && (b) > 0 && (a) > INT_MAX / (b)) ||				\
+ 			((a) > 0 && (b) < 0 && (b) < INT_MIN / (a)) ||				\
+ 			((a) < 0 && (b) > 0 && (a) < INT_MIN / (b)) ||				\
+ 			((a) < 0 && (b) < 0 && (a) < INT_MAX / (b))					\
+ 			)															\
+ 		)
+ 
+ #define INT64_MUL_OVERFLOWS(a,b) (										\
+ 		((a) > INT_MAX || (a) < INT_MIN  ||								\
+ 		 (b) > INT_MAX || (b) < INT_MIN) &&								\
+ 		(a) != 0 && (a) != 1 && (b) != 0 && (b) != 1 &&					\
+ 		(																\
+  			((a) > 0 && (b) > 0 && (a) > INT64_MAX / (b)) ||			\
+ 			((a) > 0 && (b) < 0 && (b) < INT64_MIN / (a)) ||			\
+ 			((a) < 0 && (b) > 0 && (a) < INT64_MIN / (b)) ||			\
+ 			((a) < 0 && (b) < 0 && (a) < 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
*** a/src/pl/plpgsql/src/pl_exec.c
--- b/src/pl/plpgsql/src/pl_exec.c
***************
*** 2036,2048 **** exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
  		 */
  		if (stmt->reverse)
  		{
! 			if ((int32) (loop_value - step_value) > loop_value)
  				break;
  			loop_value -= step_value;
  		}
  		else
  		{
! 			if ((int32) (loop_value + step_value) < loop_value)
  				break;
  			loop_value += step_value;
  		}
--- 2036,2048 ----
  		 */
  		if (stmt->reverse)
  		{
! 			if (INT32_SUB_OVERFLOWS(loop_value, step_value))
  				break;
  			loop_value -= step_value;
  		}
  		else
  		{
! 			if (INT32_ADD_OVERFLOWS(loop_value, step_value))
  				break;
  			loop_value += step_value;
  		}
*** a/src/timezone/localtime.c
--- b/src/timezone/localtime.c
***************
*** 1278,1294 **** timesub(const pg_time_t *timep, long offset,
  }
  
  /*
!  * Simplified normalize logic courtesy Paul Eggert.
   */
  
  static int
  increment_overflow(int *number, int delta)
  {
! 	int			number0;
  
- 	number0 = *number;
  	*number += delta;
! 	return (*number < number0) != (delta < 0);
  }
  
  /*
--- 1278,1297 ----
  }
  
  /*
!  * 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)
  {
! 	if ((delta > 0 && *number > INT_MAX - delta) ||
! 		(delta < 0 && *number < INT_MIN - delta))
! 		return 1;
  
  	*number += delta;
! 	return 0;
  }
  
  /*
*** a/src/timezone/zic.c
--- b/src/timezone/zic.c
***************
*** 2651,2683 **** getfields(char *cp)
  static long
  oadd(long t1, long t2)
  {
! 	long		t;
! 
! 	t = t1 + t2;
! 	if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1))
! 	{
  		error(_("time overflow"));
  		exit(EXIT_FAILURE);
  	}
! 	return t;
  }
  
  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))
! 	{
  		error(_("time overflow"));
  		exit(EXIT_FAILURE);
  	}
! 	return t;
  }
  
  /*
--- 2651,2677 ----
  static long
  oadd(long t1, long t2)
  {
! 	if (t1 < 0 ? t2 < LONG_MIN - t1 : LONG_MAX - t1 < t2) {
  		error(_("time overflow"));
  		exit(EXIT_FAILURE);
  	}
! 
! 	return t1 + t2;
  }
  
  static zic_t
  tadd(const zic_t t1, long t2)
  {
  	if (t1 == max_time && t2 > 0)
  		return max_time;
  	if (t1 == min_time && t2 < 0)
  		return min_time;
! 	if (t1 < 0 ? t2 < min_time - t1 : max_time - t1 < t2) {
  		error(_("time overflow"));
  		exit(EXIT_FAILURE);
  	}
! 
! 	return t1 + t2;
  }
  
  /*
#25Tom Lane
tgl@sss.pgh.pa.us
In reply to: Greg Stark (#24)
Re: [RFC] overflow checks optimized away

Greg Stark <stark@mit.edu> writes:

b) I'm concerned these checks depend on INT_MIN/MAX and SHRT_MIN/MAX
which may not be exactly the right length. I'm kind of confused why
c.h assumes long is 32 bits and short is 16 bits though so I don't
think I'm making it any worse.

I think it's something we figured we could make configure deal with
if it ever proved necessary; which it hasn't yet. (In practice, unless
an implementor is going to omit support for these integer widths entirely,
he doesn't have too much choice but to assign them the names "short"
and "int" --- C doesn't provide all that many names he can use.)

It may be better for us to just define
our own limits since we know exactly how large we expect these data
types to be.

Yeah, using INT16_MAX etc would likely be more transparent, if the code
is declaring the variables as int16.

c) I want to add regression tests that will ensure that the overflow
checks are all working. So far I haven't been able to catch any being
optimized away even with -fno-wrapv and -fstrict-overflow.

This does not leave me with a warm feeling about whether this is a useful
exercise. Maybe you need to try a different compiler?

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#26Greg Stark
stark@mit.edu
In reply to: Tom Lane (#25)
Re: [RFC] overflow checks optimized away

On Fri, Nov 29, 2013 at 5:21 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

c) I want to add regression tests that will ensure that the overflow
checks are all working. So far I haven't been able to catch any being
optimized away even with -fno-wrapv and -fstrict-overflow.

This does not leave me with a warm feeling about whether this is a useful
exercise. Maybe you need to try a different compiler?

Just as an update I did get gcc to do the wrong thing on purpose. The
only overflow check that the regression tests find missing is the one
for int8abs() ie:

*** /home/stark/src/postgresql/postgresql/src/test/regress/expected/int8.out
   Wed Jul 17 19:23:02 2013
--- /home/stark/src/postgresql/postgresql/src/test/regress/results/int8.out
   Fri Nov 29 14:22:31 2013
***************
*** 674,680 ****
  select '9223372036854775800'::int8 % '0'::int8;
  ERROR:  division by zero
  select abs('-9223372036854775808'::int8);
! ERROR:  bigint out of range
  select '9223372036854775800'::int8 + '100'::int4;
  ERROR:  bigint out of range
  select '-9223372036854775800'::int8 - '100'::int4;
--- 674,684 ----
  select '9223372036854775800'::int8 % '0'::int8;
  ERROR:  division by zero
  select abs('-9223372036854775808'::int8);
!          abs
! ----------------------
!  -9223372036854775808
! (1 row)
!
  select '9223372036854775800'::int8 + '100'::int4;
  ERROR:  bigint out of range
  select '-9223372036854775800'::int8 - '100'::int4;

======================================================================

--
greg

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#27Greg Stark
stark@mit.edu
In reply to: Greg Stark (#26)
Re: [RFC] overflow checks optimized away

On Fri, Nov 29, 2013 at 7:39 PM, Greg Stark <stark@mit.edu> wrote:

Just as an update I did get gcc to do the wrong thing on purpose. The
only overflow check that the regression tests find missing is the one
for int8abs() ie:

Also, one of the places GCC warns about optimizing away an overflow
check (with -fno-wrapv) is inside the localtime.c file from the tz
library. I fixed it in my patch but in fact I checked and it's already
fixed upstream so I'm wondering whether you expect to merge in an
updated tz library? Is there anything surprising about the process or
do you just copy in the files? Would you be happy for someone else to
do it?

--
greg

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#28Heikki Linnakangas
hlinnakangas@vmware.com
In reply to: Greg Stark (#27)
Re: [RFC] overflow checks optimized away

On 11/29/2013 10:06 PM, Greg Stark wrote:

On Fri, Nov 29, 2013 at 7:39 PM, Greg Stark <stark@mit.edu> wrote:

Just as an update I did get gcc to do the wrong thing on purpose. The
only overflow check that the regression tests find missing is the one
for int8abs() ie:

Also, one of the places GCC warns about optimizing away an overflow
check (with -fno-wrapv) is inside the localtime.c file from the tz
library. I fixed it in my patch but in fact I checked and it's already
fixed upstream so I'm wondering whether you expect to merge in an
updated tz library? Is there anything surprising about the process or
do you just copy in the files? Would you be happy for someone else to
do it?

IIRC some files can be copied directly, but not all. Might be easiest to
generate a diff between the last version in PostgreSQL and the latest
upstream version, and apply that.

- Heikki

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#29Tom Lane
tgl@sss.pgh.pa.us
In reply to: Greg Stark (#27)
Re: [RFC] overflow checks optimized away

Greg Stark <stark@mit.edu> writes:

Also, one of the places GCC warns about optimizing away an overflow
check (with -fno-wrapv) is inside the localtime.c file from the tz
library. I fixed it in my patch but in fact I checked and it's already
fixed upstream so I'm wondering whether you expect to merge in an
updated tz library? Is there anything surprising about the process or
do you just copy in the files? Would you be happy for someone else to
do it?

We've made a number of changes in our copies, unfortunately. What you
have to do is look at the upstream diffs since we last synchronized
with them (which according to src/timezone/README was tzcode 2010c)
and merge those diffs as appropriate. It should be reasonably
mechanical, but don't forget to update the README.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#30Heikki Linnakangas
hlinnakangas@vmware.com
In reply to: Greg Stark (#24)
Re: [RFC] overflow checks optimized away

On 11/29/2013 04:04 AM, Greg Stark wrote:

Attached is what I have so far. I have to say I'm starting to come
around to Tom's point of view. This is a lot of hassle for not much
gain. i've noticed a number of other overflow checks that the llvm
optimizer is not picking up on so even after this patch it's not clear
that all the signed overflow checks that depend on -fwrapv will be
gone.

This patch still isn't quite finished though.

In addition to what you have in the patch, Coverity is complaining about
the overflow checks in int4abs (which is just like int8abs), and in
DetermineTimeZoneOffset.

- Heikki

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#31Bruce Momjian
bruce@momjian.us
In reply to: Greg Stark (#24)
Re: [RFC] overflow checks optimized away

On Fri, Nov 29, 2013 at 02:04:10AM +0000, Greg Stark wrote:

Attached is what I have so far. I have to say I'm starting to come
around to Tom's point of view. This is a lot of hassle for not much
gain. i've noticed a number of other overflow checks that the llvm
optimizer is not picking up on so even after this patch it's not clear
that all the signed overflow checks that depend on -fwrapv will be
gone.

This patch still isn't quite finished though.

a) It triggers a spurious gcc warning about overflows on constant
expressions. These value of these expressions aren't actually being
used as they're used in the other branch of the overflow test. I think
I see how to work around it for gcc using __builtin_choose_expr but it
might be pretty grotty.

b) I'm concerned these checks depend on INT_MIN/MAX and SHRT_MIN/MAX
which may not be exactly the right length. I'm kind of confused why
c.h assumes long is 32 bits and short is 16 bits though so I don't
think I'm making it any worse. It may be better for us to just define
our own limits since we know exactly how large we expect these data
types to be.

c) I want to add regression tests that will ensure that the overflow
checks are all working. So far I haven't been able to catch any being
optimized away even with -fno-wrapv and -fstrict-overflow. I think I
just didn't build with the right options though and it should be
possible.

The goal here imho is to allow building with -fno-wrapv
-fstrict-overflow safely. Whether we actually do or not is another
question but it means we would be able to use new compilers like clang
without worrying about finding the equivalent of -fwrapv for them.

Where are we on this?

--
Bruce Momjian <bruce@momjian.us> http://momjian.us
EnterpriseDB http://enterprisedb.com

+ Everyone has their own god. +

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#32Bruce Momjian
bruce@momjian.us
In reply to: Bruce Momjian (#31)
Re: [RFC] overflow checks optimized away

Any news on this item from 2013, worked on again 2014?

---------------------------------------------------------------------------

On Wed, Aug 6, 2014 at 12:55:59PM -0400, Bruce Momjian wrote:

On Fri, Nov 29, 2013 at 02:04:10AM +0000, Greg Stark wrote:

Attached is what I have so far. I have to say I'm starting to come
around to Tom's point of view. This is a lot of hassle for not much
gain. i've noticed a number of other overflow checks that the llvm
optimizer is not picking up on so even after this patch it's not clear
that all the signed overflow checks that depend on -fwrapv will be
gone.

This patch still isn't quite finished though.

a) It triggers a spurious gcc warning about overflows on constant
expressions. These value of these expressions aren't actually being
used as they're used in the other branch of the overflow test. I think
I see how to work around it for gcc using __builtin_choose_expr but it
might be pretty grotty.

b) I'm concerned these checks depend on INT_MIN/MAX and SHRT_MIN/MAX
which may not be exactly the right length. I'm kind of confused why
c.h assumes long is 32 bits and short is 16 bits though so I don't
think I'm making it any worse. It may be better for us to just define
our own limits since we know exactly how large we expect these data
types to be.

c) I want to add regression tests that will ensure that the overflow
checks are all working. So far I haven't been able to catch any being
optimized away even with -fno-wrapv and -fstrict-overflow. I think I
just didn't build with the right options though and it should be
possible.

The goal here imho is to allow building with -fno-wrapv
-fstrict-overflow safely. Whether we actually do or not is another
question but it means we would be able to use new compilers like clang
without worrying about finding the equivalent of -fwrapv for them.

Where are we on this?

--
Bruce Momjian <bruce@momjian.us> http://momjian.us
EnterpriseDB http://enterprisedb.com

+ Everyone has their own god. +

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

--
Bruce Momjian <bruce@momjian.us> http://momjian.us
EnterpriseDB http://enterprisedb.com

+ As you are, so once was I. As I am, so you will be. +
+ Roman grave inscription                             +

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#33Michael Paquier
michael.paquier@gmail.com
In reply to: Bruce Momjian (#32)
1 attachment(s)
Re: [RFC] overflow checks optimized away

On Fri, Oct 9, 2015 at 10:52 PM, Bruce Momjian <bruce@momjian.us> wrote:

Any news on this item from 2013, worked on again 2014?

---------------------------------------------------------------------------

On Wed, Aug 6, 2014 at 12:55:59PM -0400, Bruce Momjian wrote:

On Fri, Nov 29, 2013 at 02:04:10AM +0000, Greg Stark wrote:

Attached is what I have so far. I have to say I'm starting to come
around to Tom's point of view. This is a lot of hassle for not much
gain. i've noticed a number of other overflow checks that the llvm
optimizer is not picking up on so even after this patch it's not clear
that all the signed overflow checks that depend on -fwrapv will be
gone.

This patch still isn't quite finished though.

a) It triggers a spurious gcc warning about overflows on constant
expressions. These value of these expressions aren't actually being
used as they're used in the other branch of the overflow test. I think
I see how to work around it for gcc using __builtin_choose_expr but it
might be pretty grotty.

b) I'm concerned these checks depend on INT_MIN/MAX and SHRT_MIN/MAX
which may not be exactly the right length. I'm kind of confused why
c.h assumes long is 32 bits and short is 16 bits though so I don't
think I'm making it any worse. It may be better for us to just define
our own limits since we know exactly how large we expect these data
types to be.

c) I want to add regression tests that will ensure that the overflow
checks are all working. So far I haven't been able to catch any being
optimized away even with -fno-wrapv and -fstrict-overflow. I think I
just didn't build with the right options though and it should be
possible.

The goal here imho is to allow building with -fno-wrapv
-fstrict-overflow safely. Whether we actually do or not is another
question but it means we would be able to use new compilers like clang
without worrying about finding the equivalent of -fwrapv for them.

Where are we on this?

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.
Regards,
--
Michael

Attachments:

20151016_overflow_optimizer.patchapplication/x-patch; name=20151016_overflow_optimizer.patchDownload
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..a6b0d1b 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..8790169 100644
--- a/src/backend/utils/adt/int.c
+++ b/src/backend/utils/adt/int.c
@@ -641,12 +641,8 @@ int4pl(PG_FUNCTION_ARGS)
 
 	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")));
@@ -662,12 +658,8 @@ int4mi(PG_FUNCTION_ARGS)
 
 	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")));
@@ -683,22 +675,8 @@ int4mul(PG_FUNCTION_ARGS)
 
 	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")));
@@ -729,12 +707,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 +727,25 @@ 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 == SHRT_MIN)
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("smallint out of range")));
-	PG_RETURN_INT16(result);
+	PG_RETURN_INT16(-arg);
 }
 
 Datum
@@ -1151,12 +1123,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 +1138,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..8a0a05a 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);
 }
 
@@ -537,17 +530,13 @@ int8mi(PG_FUNCTION_ARGS)
 	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))
+	/* Overflow check */
+	if (PG_INT64_SUB_OVERFLOWS(arg1, arg2))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("bigint out of range")));
+
+	result = arg1 - arg2;
 	PG_RETURN_INT64(result);
 }
 
@@ -560,18 +549,8 @@ int8mul(PG_FUNCTION_ARGS)
 
 	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))
+	/* Overflow check */
+	if (PG_INT64_MUL_OVERFLOWS(arg1, arg2))
 	{
 		if (arg2 != 0 &&
 			((arg2 == -1 && arg1 < 0 && result < 0) ||
@@ -607,12 +586,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 +611,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 +666,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 +681,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);
 	}
 }
 
@@ -823,12 +796,8 @@ int84pl(PG_FUNCTION_ARGS)
 
 	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")));
@@ -844,12 +813,8 @@ int84mi(PG_FUNCTION_ARGS)
 
 	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_INT64_SUB_OVERFLOWS(arg1, arg2))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("bigint out of range")));
@@ -865,18 +830,8 @@ int84mul(PG_FUNCTION_ARGS)
 
 	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)
+	/* overflow check */
+	if (PG_INT64_MUL_OVERFLOWS(arg1, arg2))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("bigint out of range")));
@@ -907,13 +862,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 */
@@ -932,12 +885,8 @@ int48pl(PG_FUNCTION_ARGS)
 
 	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")));
@@ -953,12 +902,8 @@ int48mi(PG_FUNCTION_ARGS)
 
 	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_INT64_SUB_OVERFLOWS(arg1, arg2))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("bigint out of range")));
@@ -974,18 +919,8 @@ int48mul(PG_FUNCTION_ARGS)
 
 	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")));
@@ -1018,17 +953,13 @@ int82pl(PG_FUNCTION_ARGS)
 	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))
+	/* 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);
 }
 
@@ -1039,17 +970,13 @@ int82mi(PG_FUNCTION_ARGS)
 	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))
+	/* Overflow check */
+	if (PG_INT64_SUB_OVERFLOWS(arg1, arg2))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("bigint out of range")));
+
+	result = arg1 - arg2;
 	PG_RETURN_INT64(result);
 }
 
@@ -1060,23 +987,13 @@ int82mul(PG_FUNCTION_ARGS)
 	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)
+	/* Overflow check */
+	if (PG_INT64_MUL_OVERFLOWS(arg1, arg2))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("bigint out of range")));
+
+	result = arg1 * arg2;
 	PG_RETURN_INT64(result);
 }
 
@@ -1129,12 +1046,8 @@ int28pl(PG_FUNCTION_ARGS)
 
 	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")));
@@ -1155,7 +1068,7 @@ int28mi(PG_FUNCTION_ARGS)
 	 * 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")));
@@ -1171,18 +1084,8 @@ int28mul(PG_FUNCTION_ARGS)
 
 	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")));
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..bb01121 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -793,6 +793,68 @@ 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_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're always
+ * dividing it by a positive value.
+ */
+
+#define PG_INT32_MUL_OVERFLOWS(a,b) (								\
+		((a) > SHRT_MAX || (a) < SHRT_MIN  ||						\
+		 (b) > SHRT_MAX || (b) < SHRT_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;
 		}
#34Michael Paquier
michael.paquier@gmail.com
In reply to: Michael Paquier (#33)
1 attachment(s)
Re: [RFC] overflow checks optimized away

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

Attachments:

20151020_overflow_checks_v2.patchapplication/x-patch; name=20151020_overflow_checks_v2.patchDownload
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;
 }
 
 /*
#35Michael Paquier
michael.paquier@gmail.com
In reply to: Michael Paquier (#34)
Re: [RFC] overflow checks optimized away

On Tue, Oct 20, 2015 at 4:25 PM, Michael Paquier wrote:

I'll add that to the next CF, perhaps this will interest somebody.

And nobody got interested into that, marking as returned with feedback.
--
Michael

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#36Greg Stark
stark@mit.edu
In reply to: Bruce Momjian (#32)
Re: [RFC] overflow checks optimized away

On Fri, Oct 9, 2015 at 2:52 PM, Bruce Momjian <bruce@momjian.us> wrote:

Any news on this item from 2013, worked on again 2014?

Sorry, I didn't look at it since. At the time I was using Xi Wang's
software to find the overflow checks that need to be redone. He published a
paper on it and it's actually pretty impressive. It constructs a constraint
problem and then throws a kSAT solver at it to find out if there's any code
that a compiler could optimize away regardless of whether any existant
compiler is actually capable of detecting the case and optimizing it away.
https://pdos.csail.mit.edu/papers/stack:sosp13.pdf

Xi Wang actually went on to pursue the same issues in the Linux kernel,
Clang, and elsewhere:

https://css.csail.mit.edu/stack/
http://kqueue.org/blog/2012/03/16/fast-integer-overflow-detection/
http://lists.llvm.org/pipermail/cfe-commits/Week-of-Mon-20130617/082221.html

I'm up for trying again but it's a long slong to replace all the overflow
checks and the patch will be big....

--
greg

#37Greg Stark
stark@mit.edu
In reply to: Greg Stark (#36)
1 attachment(s)
Re: [RFC] overflow checks optimized away

On Tue, Dec 1, 2015 at 5:17 PM, Greg Stark <stark@mit.edu> wrote:

Sorry, I didn't look at it since. At the time I was using Xi Wang's software
to find the overflow checks that need to be redone. He published a paper on
it and it's actually pretty impressive. It constructs a constraint problem
and then throws a kSAT solver at it to find out if there's any code that a
compiler could optimize away regardless of whether any existant compiler is
actually capable of detecting the case and optimizing it away.
https://pdos.csail.mit.edu/papers/stack:sosp13.pdf

I did get this code running again (it was quite a hassle actually).
Attached is the report.

I'm leaning towards using the builtin functions described here

http://clang.llvm.org/docs/LanguageExtensions.html#checked-arithmetic-builtins
https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html

They aren't in older GCC and clang and probably won't be in icc and
the like but we could probably implement replacements. The downside is
that then we wouldn't be able to use the generic one and would have to
use the type-specific ones which would be annoying. The Linux kernel
folk wrote wrappers that don't have that problem but they depend on
type_min() and type_max() which I've never heard of and have no idea
what support they have?

What version of GCC and other compilers did we decide we're targeting now?

--
greg

Attachments:

pstack.txttext/plain; charset=US-ASCII; name=pstack.txtDownload
---
bug: anti-simplify
model: |
  %cmp48 = icmp ne i8* %30, null, !dbg !1018
  -->  true
stack: 
  - /home/stark/src/pg/postgresql-master/src/backend/storage/lmgr/lmgr.c:712:0
ncore: 1
core: 
  - /home/stark/src/pg/postgresql-master/src/backend/storage/lmgr/lmgr.c:713:0
    - null pointer dereference
---
bug: anti-algebra
model: |
  %cmp = icmp ult i8* %add.ptr1, %start_address, !dbg !500
  -->  %16 = icmp slt i64 %15, 0, !dbg !500
  ************************************************************
  (4 + (8 * (sext i32 %7 to i64)) + %start_address) <u %start_address
  -->  (4 + (8 * (sext i32 %7 to i64))) <s 0
stack: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/time/combocid.c:326:0
ncore: 2
core: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/time/combocid.c:324:0
    - pointer overflow
  - /home/stark/src/pg/postgresql-master/src/backend/utils/time/combocid.c:324:0
    - pointer overflow
---
bug: anti-simplify
model: |
  %cmp3 = icmp slt i32 %add, 0, !dbg !595
  -->  false
stack: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/adt/int.c:756:0
ncore: 1
core: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/adt/int.c:754:0
    - signed addition overflow
---
bug: anti-algebra
model: |
  %cmp2 = icmp slt i32 %add1, %s, !dbg !570
  -->  %6 = icmp slt i32 %l, 0, !dbg !570
  ************************************************************
  (%s + %l) <s %s
  -->  %l <s 0
stack: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/adt/varbit.c:1063:0
ncore: 1
core: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/adt/varbit.c:1057:0
    - signed addition overflow
---
bug: anti-simplify
model: |
  %cmp5 = icmp sle i32 %add, %sl, !dbg !568
  -->  false
stack: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/adt/varbit.c:1170:0
ncore: 1
core: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/adt/varbit.c:1169:0
    - signed addition overflow
---
bug: anti-algebra
model: |
  %cmp3 = icmp slt i32 %add, %start, !dbg !878
  -->  %2 = icmp slt i32 %length, 0, !dbg !878
  ************************************************************
  (%start + %length) <s %start
  -->  %length <s 0
stack: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/adt/varlena.c:834:0
ncore: 1
core: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/adt/varlena.c:828:0
    - signed addition overflow
---
bug: anti-algebra
model: |
  %cmp31 = icmp slt i32 %add30, %start, !dbg !907
  -->  %29 = icmp slt i32 %length, 0, !dbg !907
  ************************************************************
  (%start + %length) <s %start
  -->  %length <s 0
stack: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/adt/varlena.c:898:0
ncore: 1
core: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/adt/varlena.c:892:0
    - signed addition overflow
---
bug: anti-simplify
model: |
  %cmp5 = icmp sle i32 %add, %sl, !dbg !876
  -->  false
stack: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/adt/varlena.c:1047:0
ncore: 1
core: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/adt/varlena.c:1046:0
    - signed addition overflow
---
bug: anti-algebra
model: |
  %cmp1 = icmp slt i32 %add, %S, !dbg !875
  -->  %2 = icmp slt i32 %L, 0, !dbg !875
  ************************************************************
  (%S + %L) <s %S
  -->  %L <s 0
stack: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/adt/varlena.c:2594:0
ncore: 1
core: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/adt/varlena.c:2588:0
    - signed addition overflow
---
bug: anti-simplify
model: |
  %cmp5 = icmp sle i32 %add, %sl, !dbg !877
  -->  false
stack: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/adt/varlena.c:2666:0
ncore: 1
core: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/adt/varlena.c:2665:0
    - signed addition overflow
---
bug: anti-simplify
model: |
  %cmp19 = icmp slt i64 %mul, 0, !dbg !583
  -->  false
stack: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/adt/int8.c:576:0
ncore: 1
core: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/adt/int8.c:561:0
    - signed multiplication overflow
---
bug: anti-simplify
model: |
  %cmp2 = icmp sgt i64 %1, 0, !dbg !580
  -->  false
stack: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/adt/int8.c:711:0
ncore: 1
core: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/adt/int8.c:709:0
    - signed addition overflow
---
bug: anti-simplify
model: |
  %cmp2 = icmp slt i64 %1, 0, !dbg !580
  -->  false
stack: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/adt/int8.c:755:0
ncore: 1
core: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/adt/int8.c:753:0
    - signed subtraction overflow
---
bug: anti-dce
model: |
  %cmp36 = icmp eq i64 %val.1, 0, !dbg !964
  -->  true
  ************************************************************
  lor.lhs.false38:
  %cmp39 = icmp slt i64 %val.0, 0, !dbg !964
  br i1 %cmp39, label %if.then41, label %if.end42, !dbg !964
stack: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/adt/numeric.c:5233:0
ncore: 1
core: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/adt/numeric.c:5233:0
    - signed subtraction overflow
---
bug: anti-simplify
model: |
  %cmp61 = icmp sle i32 %add58, %mul57, !dbg !542
  -->  false
stack: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/adt/oracle_compat.c:1056:0
ncore: 1
core: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/adt/oracle_compat.c:1054:0
    - signed addition overflow
---
bug: anti-simplify
model: |
  %cmp6 = icmp slt i32 %add5, %sub, !dbg !539
  -->  false
stack: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/adt/array_userfuncs.c:117:0
ncore: 1
core: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/adt/array_userfuncs.c:114:0
    - signed addition overflow
---
bug: anti-simplify
model: |
  %cmp59 = icmp sgt i64 %sub52, 0, !dbg !878
  -->  false
stack: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/adt/datetime.c:1557:0
ncore: 1
core: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/adt/datetime.c:1556:0
    - signed subtraction overflow
---
bug: anti-simplify
model: |
  %cmp79 = icmp sgt i64 %sub72, 0, !dbg !882
  -->  false
stack: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/adt/datetime.c:1563:0
ncore: 1
core: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/adt/datetime.c:1562:0
    - signed subtraction overflow
---
bug: anti-simplify
model: |
  %cmp105 = icmp slt i32 %add, %conv, !dbg !680
  -->  false
stack: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/adt/float.c:2768:0
ncore: 1
core: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/adt/float.c:2766:0
    - signed addition overflow
---
bug: anti-simplify
model: |
  %cmp136 = icmp slt i32 %add135, %conv, !dbg !700
  -->  false
stack: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/adt/float.c:2784:0
ncore: 1
core: 
  - /home/stark/src/pg/postgresql-master/src/backend/utils/adt/float.c:2782:0
    - signed addition overflow
---
bug: anti-dce
model: |
  entry:
  %call = call i32 @p_isalnum(%struct.TParser* null), !dbg !1025
  %call.i = call i32 @p_isalnum(%struct.TParser* null) #7, !dbg !1026
  %call2 = call i32 @p_isalpha(%struct.TParser* null), !dbg !1028
  %call.i1 = call i32 @p_isalpha(%struct.TParser* null) #7, !dbg !1029
  %call4 = call i32 @p_isdigit(%struct.TParser* null), !dbg !1031
  %call.i5 = call i32 @p_isdigit(%struct.TParser* null) #7, !dbg !1032, !macro !1034
  %call6 = call fastcc i32 @p_islower(%struct.TParser* null), !dbg !1035
  %call.i9 = call fastcc i32 @p_islower(%struct.TParser* null) #7, !dbg !1036, !macro !1034
  %call8 = call fastcc i32 @p_isprint(%struct.TParser* null), !dbg !1038
  %call.i13 = call fastcc i32 @p_isprint(%struct.TParser* null) #7, !dbg !1039, !macro !1034
  %call10 = call fastcc i32 @p_ispunct(%struct.TParser* null), !dbg !1041
  %call.i17 = call fastcc i32 @p_ispunct(%struct.TParser* null) #7, !dbg !1042, !macro !1034
  %call12 = call i32 @p_isspace(%struct.TParser* null), !dbg !1044
  %call.i21 = call i32 @p_isspace(%struct.TParser* null) #7, !dbg !1045, !macro !1034
  %call14 = call fastcc i32 @p_isupper(%struct.TParser* null), !dbg !1047
  %call.i25 = call fastcc i32 @p_isupper(%struct.TParser* null) #7, !dbg !1048, !macro !1034
  %call16 = call i32 @p_isxdigit(%struct.TParser* null), !dbg !1050
  %call.i29 = call i32 @p_isxdigit(%struct.TParser* null) #7, !dbg !1051, !macro !1034
  call void @opt.bugon(i1 true), !dbg !1053, !bug !1057
  call void @opt.bugon(i1 true), !dbg !1053, !bug !1058
  %0 = load %struct.TParserPosition** getelementptr (%struct.TParser* null, i32 0, i32 6), align 8, !dbg !1053, !macro !1059
  %tobool.i33 = icmp ne %struct.TParserPosition* %0, null, !dbg !1053, !macro !1059
  br i1 %tobool.i33, label %if.end.i, label %if.then.i, !dbg !1053, !macro !1059
stack: 
  - /home/stark/src/pg/postgresql-master/src/backend/tsearch/wparser_def.c:639:0
ncore: 1
core: 
  - /home/stark/src/pg/postgresql-master/src/backend/tsearch/wparser_def.c:576:0
    - buffer overflow
---
bug: anti-simplify
model: |
  %cmp33 = icmp sgt i32 %add, 0, !dbg !755
  -->  true
stack: 
  - /home/stark/src/pg/postgresql-master/src/backend/tsearch/spell.c:1634:0
ncore: 2
core: 
  - /home/stark/src/pg/postgresql-master/src/backend/tsearch/spell.c:1624:0
    - signed subtraction overflow
  - /home/stark/src/pg/postgresql-master/src/backend/tsearch/spell.c:1624:0
    - signed addition overflow
---
bug: anti-dce
model: |
  %cmp44 = icmp slt i64 %add, %17, !dbg !1346
  -->  false
  ************************************************************
  if.then46:
  %posOverflow = getelementptr inbounds %struct.PortalData* %portal, i32 0, i32 23, !dbg !1348
  %20 = icmp eq %struct.PortalData* %portal, null
  call void @opt.bugon(i1 %20), !dbg !1348, !bug !1308
  store i8 1, i8* %posOverflow, align 1, !dbg !1348
  br label %if.end47, !dbg !1348
stack: 
  - /home/stark/src/pg/postgresql-master/src/backend/tcop/pquery.c:960:0
ncore: 1
core: 
  - /home/stark/src/pg/postgresql-master/src/backend/tcop/pquery.c:957:0
    - signed addition overflow
---
bug: anti-simplify
model: |
  %cmp114 = icmp sgt i64 %sub, %39, !dbg !1393
  -->  false
stack: 
  - /home/stark/src/pg/postgresql-master/src/backend/tcop/pquery.c:1010:0
ncore: 1
core: 
  - /home/stark/src/pg/postgresql-master/src/backend/tcop/pquery.c:1009:0
    - signed subtraction overflow
---
bug: anti-simplify
model: |
  %cmp72 = icmp sle i32 %add, 0, !dbg !2117
  -->  false
stack: 
  - /home/stark/src/pg/postgresql-master/src/backend/executor/execQual.c:3188:0
ncore: 1
core: 
  - /home/stark/src/pg/postgresql-master/src/backend/executor/execQual.c:3187:0
    - signed addition overflow
---
bug: anti-simplify
model: |
  %cmp12 = icmp sle i32 %add, 0, !dbg !824
  -->  false
stack: 
  - /home/stark/src/pg/postgresql-master/src/backend/regex/./regc_locale.c:438:0
ncore: 2
core: 
  - /home/stark/src/pg/postgresql-master/src/backend/regex/./regc_locale.c:437:0
    - signed subtraction overflow
  - /home/stark/src/pg/postgresql-master/src/backend/regex/./regc_locale.c:437:0
    - signed addition overflow
---
bug: anti-simplify
model: |
  %cmp29 = icmp ne i8* %cond, null, !dbg !1083
  -->  true
stack: 
  - /home/stark/src/pg/postgresql-master/src/backend/access/gist/gist.c:1007:0
ncore: 1
core: 
  - /home/stark/src/pg/postgresql-master/src/backend/access/gist/gist.c:1004:0
    - null pointer dereference
---
bug: anti-simplify
model: |
  %tobool36 = icmp ne %struct.List* %rollup_lists.addr.0, null, !dbg !2266
  -->  true
stack: 
  - /home/stark/src/pg/postgresql-master/src/backend/optimizer/plan/planner.c:2548:0
ncore: 1
core: 
  - /home/stark/src/pg/postgresql-master/src/backend/optimizer/plan/planner.c:2507:20
    - null pointer dereference
---
bug: anti-simplify
model: |
  %cmp129 = icmp sgt i32 %sub, %loop_value.0, !dbg !2917
  -->  false
stack: 
  - /home/stark/src/pg/postgresql-master/src/pl/plpgsql/src/pl_exec.c:2071:0
ncore: 1
core: 
  - /home/stark/src/pg/postgresql-master/src/pl/plpgsql/src/pl_exec.c:2071:0
    - signed subtraction overflow
---
bug: anti-simplify
model: |
  %cmp135 = icmp slt i32 %add, %loop_value.0, !dbg !2924
  -->  false
stack: 
  - /home/stark/src/pg/postgresql-master/src/pl/plpgsql/src/pl_exec.c:2077:0
ncore: 1
core: 
  - /home/stark/src/pg/postgresql-master/src/pl/plpgsql/src/pl_exec.c:2077:0
    - signed addition overflow
---
bug: anti-simplify
model: |
  %tobool97 = icmp ne i32 %conv4.i, 0, !dbg !236
  -->  false
stack: 
  - /home/stark/src/pg/postgresql-master/src/bin/initdb/localtime.c:1202:0
ncore: 1
core: 
  - /home/stark/src/pg/postgresql-master/src/bin/initdb/localtime.c:1290:0
    - signed addition overflow
---
bug: anti-simplify
model: |
  %cmp3 = icmp ne i32 %conv, %conv2, !dbg !197
  -->  false
stack: 
  - /home/stark/src/pg/postgresql-master/src/bin/initdb/localtime.c:1291:0
ncore: 1
core: 
  - /home/stark/src/pg/postgresql-master/src/bin/initdb/localtime.c:1290:0
    - signed addition overflow
---
bug: anti-simplify
model: |
  %cmp556 = icmp slt i64 %sub555, 0, !dbg !825
  -->  false
stack: 
  - /home/stark/src/pg/postgresql-master/src/bin/pgbench/pgbench.c:1533:0
ncore: 1
core: 
  - /home/stark/src/pg/postgresql-master/src/bin/pgbench/pgbench.c:1533:0
    - signed subtraction overflow
---
bug: anti-simplify
model: |
  %cmp561 = icmp slt i64 %add560, 0, !dbg !825
  -->  false
stack: 
  - /home/stark/src/pg/postgresql-master/src/bin/pgbench/pgbench.c:1533:0
ncore: 2
core: 
  - /home/stark/src/pg/postgresql-master/src/bin/pgbench/pgbench.c:1533:0
    - signed subtraction overflow
  - /home/stark/src/pg/postgresql-master/src/bin/pgbench/pgbench.c:1533:0
    - signed addition overflow
---
bug: anti-simplify
model: |
  %cmp9 = icmp sle i64 %add, %t1, !dbg !402
  -->  false
stack: 
  - /home/stark/src/pg/postgresql-master/src/timezone/zic.c:2674:0
ncore: 1
core: 
  - /home/stark/src/pg/postgresql-master/src/timezone/zic.c:2673:0
    - signed addition overflow
---
bug: anti-simplify
model: |
  %cmp12 = icmp sge i64 %add, %t1, !dbg !402
  -->  false
stack: 
  - /home/stark/src/pg/postgresql-master/src/timezone/zic.c:2674:0
ncore: 1
core: 
  - /home/stark/src/pg/postgresql-master/src/timezone/zic.c:2673:0
    - signed addition overflow
---
bug: anti-simplify
model: |
  %cmp1 = icmp sle i64 %add, %t1, !dbg !396
  -->  false
stack: 
  - /home/stark/src/pg/postgresql-master/src/timezone/zic.c:2656:0
ncore: 1
core: 
  - /home/stark/src/pg/postgresql-master/src/timezone/zic.c:2655:0
    - signed addition overflow
---
bug: anti-simplify
model: |
  %cmp4 = icmp sge i64 %add, %t1, !dbg !396
  -->  false
stack: 
  - /home/stark/src/pg/postgresql-master/src/timezone/zic.c:2656:0
ncore: 1
core: 
  - /home/stark/src/pg/postgresql-master/src/timezone/zic.c:2655:0
    - signed addition overflow
---
bug: anti-simplify
model: |
  %tobool97 = icmp ne i32 %conv4.i, 0, !dbg !236
  -->  false
stack: 
  - /home/stark/src/pg/postgresql-master/src/timezone/localtime.c:1202:0
ncore: 1
core: 
  - /home/stark/src/pg/postgresql-master/src/timezone/localtime.c:1290:0
    - signed addition overflow
---
bug: anti-simplify
model: |
  %cmp3 = icmp ne i32 %conv, %conv2, !dbg !197
  -->  false
stack: 
  - /home/stark/src/pg/postgresql-master/src/timezone/localtime.c:1291:0
ncore: 1
core: 
  - /home/stark/src/pg/postgresql-master/src/timezone/localtime.c:1290:0
    - signed addition overflow
#38Tom Lane
tgl@sss.pgh.pa.us
In reply to: Greg Stark (#37)
Re: [RFC] overflow checks optimized away

Greg Stark <stark@mit.edu> writes:

What version of GCC and other compilers did we decide we're targeting now?

I can't see us moving the compiler goalposts one inch for this.
"I'm going to break building on your compiler in order to work around
bugs in somebody else's compiler" isn't gonna fly.

The original post pointed out that we haven't introduced the appropriate
equivalents of -fwrapv for non-gcc compilers, which is a good point that
we should fix. Beyond that, I'm not convinced.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#39Greg Stark
stark@mit.edu
In reply to: Tom Lane (#38)
Re: [RFC] overflow checks optimized away

On Thu, Dec 3, 2015 at 2:51 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Greg Stark <stark@mit.edu> writes:

What version of GCC and other compilers did we decide we're targeting now?

I can't see us moving the compiler goalposts one inch for this.

That's not the question I asked :/

--
greg

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#40Andres Freund
andres@anarazel.de
In reply to: Greg Stark (#37)
Re: [RFC] overflow checks optimized away

On 2015-12-03 12:10:27 +0000, Greg Stark wrote:

I'm leaning towards using the builtin functions described here

For performance reasons? Michael's version of the patch had the
necessary 'raw' macros, and they don't look *that* bad. Using the
__builtin variants when available, would be nice - and not hard. On
e.g. x86 the overflow checks can be done much more efficiently than both
the current and patched checks.

I wonder though if we can replace

#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_INT32_ADD_OVERFLOWS(a, b) ( \
((a) > 0 && (b) > 0 && (a) > PG_INT32_MAX - (b)) || \
((a) < 0 && (b) < 0 && (a) < PG_INT32_MIN - (b)))

...

with something like
#define PG_ADD_OVERFLOWS(a, b, MINVAL, MAXVAL) ( \
((a) > 0 && (b) > 0 && (a) > MAXVAL - (b)) || \
((a) < 0 && (b) < 0 && (a) < MINVAL - (b)))
#define PG_INT16_ADD_OVERFLOWS(a, b) \
PG_ADD_OVERFLOWS(a, b, PG_INT16_MIN, PG_INT16_MAX)

especially for the MUL variants that'll save a bunch of long repetitions.

The downside is that then we wouldn't be able to use the generic one
and would have to use the type-specific ones which would be annoying.

Doesn't seem to be all that bad to me. If we do the fallback like in the
above it should be fairly ok repetition wise.

Greetings,

Andres Freund

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#41Greg Stark
stark@mit.edu
In reply to: Tom Lane (#38)
Re: [RFC] overflow checks optimized away

On Thu, Dec 3, 2015 at 2:51 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

I can't see us moving the compiler goalposts one inch for this.
"I'm going to break building on your compiler in order to work around
bugs in somebody else's compiler" isn't gonna fly.

Fwiw the builtins offer a carrot as well. They promise to use
architecture features like arithmetic status flags which can be faster
than explicit comparisons and also avoid extra branches that can mess
up cache and branch prediction.

I was proposing to implement wrappers around them that do the checks
manually if they're not present.

--
greg

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#42Tom Lane
tgl@sss.pgh.pa.us
In reply to: Greg Stark (#41)
Re: [RFC] overflow checks optimized away

Greg Stark <stark@mit.edu> writes:

On Thu, Dec 3, 2015 at 2:51 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

I can't see us moving the compiler goalposts one inch for this.
"I'm going to break building on your compiler in order to work around
bugs in somebody else's compiler" isn't gonna fly.

I was proposing to implement wrappers around them that do the checks
manually if they're not present.

As long as there's a fallback for compilers without the builtins, fine.
I read your question as suggesting that you were thinking about not
providing a fallback ...

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#43Michael Paquier
michael.paquier@gmail.com
In reply to: Andres Freund (#40)
Re: [RFC] overflow checks optimized away

On Fri, Dec 4, 2015 at 1:27 AM, Andres Freund <andres@anarazel.de> wrote:

On 2015-12-03 12:10:27 +0000, Greg Stark wrote:

I'm leaning towards using the builtin functions described here

For performance reasons? Michael's version of the patch had the
necessary 'raw' macros, and they don't look *that* bad. Using the
__builtin variants when available, would be nice - and not hard. On
e.g. x86 the overflow checks can be done much more efficiently than both
the current and patched checks.

Using the _builtin functions when available would be indeed a nice
optimization that the previous patch missed.

I wonder though if we can replace

#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_INT32_ADD_OVERFLOWS(a, b) ( \
((a) > 0 && (b) > 0 && (a) > PG_INT32_MAX - (b)) || \
((a) < 0 && (b) < 0 && (a) < PG_INT32_MIN - (b)))

...

with something like
#define PG_ADD_OVERFLOWS(a, b, MINVAL, MAXVAL) ( \
((a) > 0 && (b) > 0 && (a) > MAXVAL - (b)) || \
((a) < 0 && (b) < 0 && (a) < MINVAL - (b)))
#define PG_INT16_ADD_OVERFLOWS(a, b) \
PG_ADD_OVERFLOWS(a, b, PG_INT16_MIN, PG_INT16_MAX)

especially for the MUL variants that'll save a bunch of long repetitions.

Yeah, we should. Those would save quite a couple of lines in c.h.
--
Michael

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers