Fix corner-case 64-bit integer subtraction bug on some platforms.

When computing "0 - INT64_MIN", most platforms would report an
overflow error, which is correct. However, platforms without integer
overflow builtins or 128-bit integers would fail to spot the overflow,
and incorrectly return INT64_MIN.

Back-patch to all supported branches.

Patch be me. Thanks to Jian He for initial investigation, and Laurenz
Albe and Tom Lane for review.

Discussion: https://postgr.es/m/CAEZATCUNK-AZSD0jVdgkk0N%3DNcAXBWeAEX-QU9AnJPensikmdQ%40mail.gmail.com
This commit is contained in:
Dean Rasheed 2023-11-09 09:50:23 +00:00
parent a7db71ed27
commit 0e3e8fbd3a
3 changed files with 8 additions and 1 deletions

View File

@ -200,8 +200,12 @@ pg_sub_s64_overflow(int64 a, int64 b, int64 *result)
*result = (int64) res;
return false;
#else
/*
* Note: overflow is also possible when a == 0 and b < 0 (specifically,
* when b == PG_INT64_MIN).
*/
if ((a < 0 && b > 0 && a < PG_INT64_MIN + b) ||
(a > 0 && b < 0 && a > PG_INT64_MAX + b))
(a >= 0 && b < 0 && a > PG_INT64_MAX + b))
{
*result = 0x5EED; /* to avoid spurious warnings */
return true;

View File

@ -679,6 +679,8 @@ select -('-9223372036854775807'::int8);
select -('-9223372036854775808'::int8);
ERROR: bigint out of range
select 0::int8 - '-9223372036854775808'::int8;
ERROR: bigint out of range
select '9223372036854775800'::int8 + '9223372036854775800'::int8;
ERROR: bigint out of range
select '-9223372036854775800'::int8 + '-9223372036854775800'::int8;

View File

@ -132,6 +132,7 @@ select '9223372036854775808'::int8;
select -('-9223372036854775807'::int8);
select -('-9223372036854775808'::int8);
select 0::int8 - '-9223372036854775808'::int8;
select '9223372036854775800'::int8 + '9223372036854775800'::int8;
select '-9223372036854775800'::int8 + '-9223372036854775800'::int8;