From 56410d265d439ed479b210e57242476e15bb6edb Mon Sep 17 00:00:00 2001 From: Ewan Young Date: Thu, 27 Aug 2026 18:06:09 +0800 Subject: [PATCH] Use pg_neg_s{16,32,64}_overflow() for open-coded negation overflow checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Several integer, bigint and money functions guard the negation of the most negative value by open-coding an explicit "x == PG_INTnn_MIN" test before computing -x. int.h already provides pg_neg_s16_overflow(), pg_neg_s32_overflow() and pg_neg_s64_overflow() for exactly this, which use __builtin_sub_overflow() where available and fall back to the same open-coded test otherwise. Convert the remaining hand-rolled checks to use these helpers, as suggested by Dagfinn Ilmari Mannsåker. This is a cleanup with no behavioral change: every converted site keeps its existing error (or soft-error) path, and on platforms without __builtin_sub_overflow() the inlined fallback is identical to the code being replaced. --- src/backend/utils/adt/cash.c | 9 +++++---- src/backend/utils/adt/int.c | 33 ++++++++++++++------------------- src/backend/utils/adt/int8.c | 22 +++++++--------------- src/backend/utils/adt/numeric.c | 3 +-- 4 files changed, 27 insertions(+), 40 deletions(-) diff --git a/src/backend/utils/adt/cash.c b/src/backend/utils/adt/cash.c index 310b3bb3fca..5fa5288629f 100644 --- a/src/backend/utils/adt/cash.c +++ b/src/backend/utils/adt/cash.c @@ -169,11 +169,13 @@ cash_div_int64(Cash c, int64 i) */ if (i == -1) { - if (unlikely(c == PG_INT64_MIN)) + Cash result; + + if (unlikely(pg_neg_s64_overflow(c, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("money out of range"))); - return -c; + return result; } /* No overflow is possible */ @@ -379,12 +381,11 @@ cash_in(PG_FUNCTION_ARGS) */ if (sgn > 0) { - if (value == PG_INT64_MIN) + if (pg_neg_s64_overflow(value, &result)) ereturn(escontext, (Datum) 0, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("value \"%s\" is out of range for type %s", str, "money"))); - result = -value; } else result = value; diff --git a/src/backend/utils/adt/int.c b/src/backend/utils/adt/int.c index 01608d8ca42..d4aedb2ffbc 100644 --- a/src/backend/utils/adt/int.c +++ b/src/backend/utils/adt/int.c @@ -800,12 +800,13 @@ Datum int4um(PG_FUNCTION_ARGS) { int32 arg = PG_GETARG_INT32(0); + int32 result; - if (unlikely(arg == PG_INT32_MIN)) + if (unlikely(pg_neg_s32_overflow(arg, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); - PG_RETURN_INT32(-arg); + PG_RETURN_INT32(result); } Datum @@ -882,11 +883,10 @@ int4div(PG_FUNCTION_ARGS) */ if (arg2 == -1) { - if (unlikely(arg1 == PG_INT32_MIN)) + if (unlikely(pg_neg_s32_overflow(arg1, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); - result = -arg1; PG_RETURN_INT32(result); } @@ -915,12 +915,13 @@ Datum int2um(PG_FUNCTION_ARGS) { int16 arg = PG_GETARG_INT16(0); + int16 result; - if (unlikely(arg == PG_INT16_MIN)) + if (unlikely(pg_neg_s16_overflow(arg, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("smallint out of range"))); - PG_RETURN_INT16(-arg); + PG_RETURN_INT16(result); } Datum @@ -998,11 +999,10 @@ int2div(PG_FUNCTION_ARGS) */ if (arg2 == -1) { - if (unlikely(arg1 == PG_INT16_MIN)) + if (unlikely(pg_neg_s16_overflow(arg1, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("smallint out of range"))); - result = -arg1; PG_RETURN_INT16(result); } @@ -1140,11 +1140,10 @@ int42div(PG_FUNCTION_ARGS) */ if (arg2 == -1) { - if (unlikely(arg1 == PG_INT32_MIN)) + if (unlikely(pg_neg_s32_overflow(arg1, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); - result = -arg1; PG_RETURN_INT32(result); } @@ -1223,11 +1222,11 @@ int4abs(PG_FUNCTION_ARGS) int32 arg1 = PG_GETARG_INT32(0); int32 result; - if (unlikely(arg1 == PG_INT32_MIN)) + result = arg1; + if (arg1 < 0 && unlikely(pg_neg_s32_overflow(arg1, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); - result = (arg1 < 0) ? -arg1 : arg1; PG_RETURN_INT32(result); } @@ -1237,11 +1236,11 @@ int2abs(PG_FUNCTION_ARGS) int16 arg1 = PG_GETARG_INT16(0); int16 result; - if (unlikely(arg1 == PG_INT16_MIN)) + result = arg1; + if (arg1 < 0 && unlikely(pg_neg_s16_overflow(arg1, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("smallint out of range"))); - result = (arg1 < 0) ? -arg1 : arg1; PG_RETURN_INT16(result); } @@ -1360,15 +1359,11 @@ int4lcm(PG_FUNCTION_ARGS) (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); - /* If the result is INT_MIN, it cannot be represented. */ - if (unlikely(result == PG_INT32_MIN)) + if (result < 0 && unlikely(pg_neg_s32_overflow(result, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); - if (result < 0) - result = -result; - PG_RETURN_INT32(result); } diff --git a/src/backend/utils/adt/int8.c b/src/backend/utils/adt/int8.c index 1f59d831600..72390e985c3 100644 --- a/src/backend/utils/adt/int8.c +++ b/src/backend/utils/adt/int8.c @@ -449,11 +449,10 @@ int8um(PG_FUNCTION_ARGS) int64 arg = PG_GETARG_INT64(0); int64 result; - if (unlikely(arg == PG_INT64_MIN)) + if (unlikely(pg_neg_s64_overflow(arg, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("bigint out of range"))); - result = -arg; PG_RETURN_INT64(result); } @@ -531,11 +530,10 @@ int8div(PG_FUNCTION_ARGS) */ if (arg2 == -1) { - if (unlikely(arg1 == PG_INT64_MIN)) + if (unlikely(pg_neg_s64_overflow(arg1, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("bigint out of range"))); - result = -arg1; PG_RETURN_INT64(result); } @@ -556,11 +554,11 @@ int8abs(PG_FUNCTION_ARGS) int64 arg1 = PG_GETARG_INT64(0); int64 result; - if (unlikely(arg1 == PG_INT64_MIN)) + result = arg1; + if (arg1 < 0 && unlikely(pg_neg_s64_overflow(arg1, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("bigint out of range"))); - result = (arg1 < 0) ? -arg1 : arg1; PG_RETURN_INT64(result); } @@ -712,15 +710,11 @@ int8lcm(PG_FUNCTION_ARGS) (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("bigint out of range"))); - /* If the result is INT64_MIN, it cannot be represented. */ - if (unlikely(result == PG_INT64_MIN)) + if (result < 0 && unlikely(pg_neg_s64_overflow(result, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("bigint out of range"))); - if (result < 0) - result = -result; - PG_RETURN_INT64(result); } @@ -991,11 +985,10 @@ int84div(PG_FUNCTION_ARGS) */ if (arg2 == -1) { - if (unlikely(arg1 == PG_INT64_MIN)) + if (unlikely(pg_neg_s64_overflow(arg1, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("bigint out of range"))); - result = -arg1; PG_RETURN_INT64(result); } @@ -1133,11 +1126,10 @@ int82div(PG_FUNCTION_ARGS) */ if (arg2 == -1) { - if (unlikely(arg1 == PG_INT64_MIN)) + if (unlikely(pg_neg_s64_overflow(arg1, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("bigint out of range"))); - result = -arg1; PG_RETURN_INT64(result); } diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c index 523cd3cd608..37f24e33857 100644 --- a/src/backend/utils/adt/numeric.c +++ b/src/backend/utils/adt/numeric.c @@ -7870,9 +7870,8 @@ numericvar_to_int64(const NumericVar *var, int64 *result) if (!neg) { - if (unlikely(val == PG_INT64_MIN)) + if (unlikely(pg_neg_s64_overflow(val, &val))) return false; - val = -val; } *result = val; -- 2.47.3