From 308a69a9878212bc2f96279023ce16070dac9214 Mon Sep 17 00:00:00 2001 From: Dean Rasheed Date: Thu, 9 Nov 2023 09:54:22 +0000 Subject: [PATCH] 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 --- src/include/common/int.h | 6 +++++- src/test/regress/expected/int8.out | 2 ++ src/test/regress/sql/int8.sql | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/include/common/int.h b/src/include/common/int.h index 12a269d952..e2617fbc5d 100644 --- a/src/include/common/int.h +++ b/src/include/common/int.h @@ -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; diff --git a/src/test/regress/expected/int8.out b/src/test/regress/expected/int8.out index 1ae23cf3f9..329f3911dd 100644 --- a/src/test/regress/expected/int8.out +++ b/src/test/regress/expected/int8.out @@ -654,6 +654,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; diff --git a/src/test/regress/sql/int8.sql b/src/test/regress/sql/int8.sql index 38b771964d..8a3d5371d6 100644 --- a/src/test/regress/sql/int8.sql +++ b/src/test/regress/sql/int8.sql @@ -126,6 +126,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;