diff --git a/contrib/btree_gist/btree_cash.c b/contrib/btree_gist/btree_cash.c index 81131af4dc..18f45f2750 100644 --- a/contrib/btree_gist/btree_cash.c +++ b/contrib/btree_gist/btree_cash.c @@ -5,6 +5,7 @@ #include "btree_gist.h" #include "btree_utils_num.h" +#include "common/int.h" #include "utils/cash.h" typedef struct @@ -99,15 +100,14 @@ cash_dist(PG_FUNCTION_ARGS) Cash r; Cash ra; - r = a - b; - ra = Abs(r); - - /* Overflow check. */ - if (ra < 0 || (!SAMESIGN(a, b) && !SAMESIGN(r, a))) + if (pg_sub_s64_overflow(a, b, &r) || + r == INT64_MIN) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("money out of range"))); + ra = Abs(r); + PG_RETURN_CASH(ra); } diff --git a/contrib/btree_gist/btree_int2.c b/contrib/btree_gist/btree_int2.c index f343b8615f..c2af4cd566 100644 --- a/contrib/btree_gist/btree_int2.c +++ b/contrib/btree_gist/btree_int2.c @@ -5,6 +5,7 @@ #include "btree_gist.h" #include "btree_utils_num.h" +#include "common/int.h" typedef struct int16key { @@ -98,15 +99,14 @@ int2_dist(PG_FUNCTION_ARGS) int16 r; int16 ra; - r = a - b; - ra = Abs(r); - - /* Overflow check. */ - if (ra < 0 || (!SAMESIGN(a, b) && !SAMESIGN(r, a))) + if (pg_sub_s16_overflow(a, b, &r) || + r == INT16_MIN) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("smallint out of range"))); + ra = Abs(r); + PG_RETURN_INT16(ra); } diff --git a/contrib/btree_gist/btree_int4.c b/contrib/btree_gist/btree_int4.c index 35bb442437..f2b6dec660 100644 --- a/contrib/btree_gist/btree_int4.c +++ b/contrib/btree_gist/btree_int4.c @@ -5,6 +5,7 @@ #include "btree_gist.h" #include "btree_utils_num.h" +#include "common/int.h" typedef struct int32key { @@ -99,15 +100,14 @@ int4_dist(PG_FUNCTION_ARGS) int32 r; int32 ra; - r = a - b; - ra = Abs(r); - - /* Overflow check. */ - if (ra < 0 || (!SAMESIGN(a, b) && !SAMESIGN(r, a))) + if (pg_sub_s32_overflow(a, b, &r) || + r == INT32_MIN) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); + ra = Abs(r); + PG_RETURN_INT32(ra); } diff --git a/contrib/btree_gist/btree_int8.c b/contrib/btree_gist/btree_int8.c index 91f2d032d1..16db0028b7 100644 --- a/contrib/btree_gist/btree_int8.c +++ b/contrib/btree_gist/btree_int8.c @@ -5,6 +5,7 @@ #include "btree_gist.h" #include "btree_utils_num.h" +#include "common/int.h" typedef struct int64key { @@ -99,15 +100,14 @@ int8_dist(PG_FUNCTION_ARGS) int64 r; int64 ra; - r = a - b; - ra = Abs(r); - - /* Overflow check. */ - if (ra < 0 || (!SAMESIGN(a, b) && !SAMESIGN(r, a))) + if (pg_sub_s64_overflow(a, b, &r) || + r == INT64_MIN) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("bigint out of range"))); + ra = Abs(r); + PG_RETURN_INT64(ra); } diff --git a/contrib/btree_gist/btree_utils_num.h b/contrib/btree_gist/btree_utils_num.h index 17561fa9e4..d7945f856c 100644 --- a/contrib/btree_gist/btree_utils_num.h +++ b/contrib/btree_gist/btree_utils_num.h @@ -89,8 +89,6 @@ typedef struct #define GET_FLOAT_DISTANCE(t, arg1, arg2) Abs( ((float8) *((const t *) (arg1))) - ((float8) *((const t *) (arg2))) ) -#define SAMESIGN(a,b) (((a) < 0) == ((b) < 0)) - /* * check to see if a float4/8 val has underflowed or overflowed * borrowed from src/backend/utils/adt/float.c diff --git a/src/backend/utils/adt/array_userfuncs.c b/src/backend/utils/adt/array_userfuncs.c index 87d79f3f98..bb70cba171 100644 --- a/src/backend/utils/adt/array_userfuncs.c +++ b/src/backend/utils/adt/array_userfuncs.c @@ -13,6 +13,7 @@ #include "postgres.h" #include "catalog/pg_type.h" +#include "common/int.h" #include "utils/array.h" #include "utils/builtins.h" #include "utils/lsyscache.h" @@ -118,15 +119,11 @@ array_append(PG_FUNCTION_ARGS) if (eah->ndims == 1) { /* append newelem */ - int ub; - lb = eah->lbound; dimv = eah->dims; - ub = dimv[0] + lb[0] - 1; - indx = ub + 1; - /* overflow? */ - if (indx < ub) + /* index of added elem is at lb[0] + (dimv[0] - 1) + 1 */ + if (pg_add_s32_overflow(lb[0], dimv[0], &indx)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); @@ -176,11 +173,9 @@ array_prepend(PG_FUNCTION_ARGS) { /* prepend newelem */ lb = eah->lbound; - indx = lb[0] - 1; lb0 = lb[0]; - /* overflow? */ - if (indx > lb[0]) + if (pg_sub_s32_overflow(lb0, 1, &indx)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); diff --git a/src/backend/utils/adt/cash.c b/src/backend/utils/adt/cash.c index 7bbc634bd2..c787dd3419 100644 --- a/src/backend/utils/adt/cash.c +++ b/src/backend/utils/adt/cash.c @@ -22,6 +22,7 @@ #include #include +#include "common/int.h" #include "libpq/pqformat.h" #include "utils/builtins.h" #include "utils/cash.h" @@ -199,20 +200,21 @@ cash_in(PG_FUNCTION_ARGS) for (; *s; s++) { - /* we look for digits as long as we have found less */ - /* than the required number of decimal places */ + /* + * We look for digits as long as we have found less than the required + * number of decimal places. + */ if (isdigit((unsigned char) *s) && (!seen_dot || dec < fpoint)) { - Cash newvalue = (value * 10) - (*s - '0'); + int8 digit = *s - '0'; - if (newvalue / 10 != value) + if (pg_mul_s64_overflow(value, 10, &value) || + pg_sub_s64_overflow(value, digit, &value)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("value \"%s\" is out of range for type %s", str, "money"))); - value = newvalue; - if (seen_dot) dec++; } @@ -230,26 +232,23 @@ cash_in(PG_FUNCTION_ARGS) /* round off if there's another digit */ if (isdigit((unsigned char) *s) && *s >= '5') - value--; /* remember we build the value in the negative */ - - if (value > 0) - ereport(ERROR, - (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("value \"%s\" is out of range for type %s", - str, "money"))); - - /* adjust for less than required decimal places */ - for (; dec < fpoint; dec++) { - Cash newvalue = value * 10; - - if (newvalue / 10 != value) + /* remember we build the value in the negative */ + if (pg_sub_s64_overflow(value, 1, &value)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("value \"%s\" is out of range for type %s", str, "money"))); + } - value = newvalue; + /* adjust for less than required decimal places */ + for (; dec < fpoint; dec++) + { + if (pg_mul_s64_overflow(value, 10, &value)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("value \"%s\" is out of range for type %s", + str, "money"))); } /* @@ -285,12 +284,12 @@ cash_in(PG_FUNCTION_ARGS) */ if (sgn > 0) { - result = -value; - if (result < 0) + if (value == PG_INT64_MIN) ereport(ERROR, (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/float.c b/src/backend/utils/adt/float.c index 18b3b949ac..be65aab1c9 100644 --- a/src/backend/utils/adt/float.c +++ b/src/backend/utils/adt/float.c @@ -20,6 +20,7 @@ #include #include "catalog/pg_type.h" +#include "common/int.h" #include "libpq/pqformat.h" #include "utils/array.h" #include "utils/builtins.h" @@ -3548,9 +3549,7 @@ width_bucket_float8(PG_FUNCTION_ARGS) result = 0; else if (operand >= bound2) { - result = count + 1; - /* check for overflow */ - if (result < count) + if (pg_add_s32_overflow(count, 1, &result)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); @@ -3564,9 +3563,7 @@ width_bucket_float8(PG_FUNCTION_ARGS) result = 0; else if (operand <= bound2) { - result = count + 1; - /* check for overflow */ - if (result < count) + if (pg_add_s32_overflow(count, 1, &result)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); diff --git a/src/backend/utils/adt/int.c b/src/backend/utils/adt/int.c index 4cd8960b3f..36ba86ca73 100644 --- a/src/backend/utils/adt/int.c +++ b/src/backend/utils/adt/int.c @@ -32,14 +32,12 @@ #include #include "catalog/pg_type.h" +#include "common/int.h" #include "funcapi.h" #include "libpq/pqformat.h" #include "utils/array.h" #include "utils/builtins.h" - -#define SAMESIGN(a,b) (((a) < 0) == ((b) < 0)) - #define Int2VectorSize(n) (offsetof(int2vector, values) + (n) * sizeof(int16)) typedef struct @@ -328,7 +326,7 @@ i4toi2(PG_FUNCTION_ARGS) { int32 arg1 = PG_GETARG_INT32(0); - if (arg1 < SHRT_MIN || arg1 > SHRT_MAX) + if (unlikely(arg1 < SHRT_MIN) || unlikely(arg1 > SHRT_MAX)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("smallint out of range"))); @@ -598,15 +596,12 @@ 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 (unlikely(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 @@ -624,14 +619,7 @@ int4pl(PG_FUNCTION_ARGS) 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 (unlikely(pg_add_s32_overflow(arg1, arg2, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); @@ -645,14 +633,7 @@ int4mi(PG_FUNCTION_ARGS) 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 (unlikely(pg_sub_s32_overflow(arg1, arg2, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); @@ -666,24 +647,7 @@ int4mul(PG_FUNCTION_ARGS) 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)) + if (unlikely(pg_mul_s32_overflow(arg1, arg2, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); @@ -714,12 +678,11 @@ int4div(PG_FUNCTION_ARGS) */ if (arg2 == -1) { - result = -arg1; - /* overflow check (needed for INT_MIN) */ - if (arg1 != 0 && SAMESIGN(result, arg1)) + if (unlikely(arg1 == PG_INT32_MIN)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); + result = -arg1; PG_RETURN_INT32(result); } @@ -736,9 +699,7 @@ int4inc(PG_FUNCTION_ARGS) int32 arg = PG_GETARG_INT32(0); int32 result; - result = arg + 1; - /* Overflow check */ - if (arg > 0 && result < 0) + if (unlikely(pg_add_s32_overflow(arg, 1, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); @@ -750,15 +711,12 @@ 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 (unlikely(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 @@ -776,14 +734,7 @@ int2pl(PG_FUNCTION_ARGS) 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 (unlikely(pg_add_s16_overflow(arg1, arg2, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("smallint out of range"))); @@ -797,14 +748,7 @@ int2mi(PG_FUNCTION_ARGS) 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 (unlikely(pg_sub_s16_overflow(arg1, arg2, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("smallint out of range"))); @@ -816,20 +760,14 @@ int2mul(PG_FUNCTION_ARGS) { int16 arg1 = PG_GETARG_INT16(0); int16 arg2 = PG_GETARG_INT16(1); - int32 result32; + int16 result; - /* - * 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 (unlikely(pg_mul_s16_overflow(arg1, arg2, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("smallint out of range"))); - PG_RETURN_INT16((int16) result32); + PG_RETURN_INT16(result); } Datum @@ -856,12 +794,11 @@ int2div(PG_FUNCTION_ARGS) */ if (arg2 == -1) { - result = -arg1; - /* overflow check (needed for SHRT_MIN) */ - if (arg1 != 0 && SAMESIGN(result, arg1)) + if (unlikely(arg1 == INT16_MIN)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("smallint out of range"))); + result = -arg1; PG_RETURN_INT16(result); } @@ -879,14 +816,7 @@ int24pl(PG_FUNCTION_ARGS) 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 (unlikely(pg_add_s32_overflow((int32) arg1, arg2, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); @@ -900,14 +830,7 @@ int24mi(PG_FUNCTION_ARGS) 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 (unlikely(pg_sub_s32_overflow((int32) arg1, arg2, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); @@ -921,20 +844,7 @@ int24mul(PG_FUNCTION_ARGS) 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 (unlikely(pg_mul_s32_overflow((int32) arg1, arg2, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); @@ -947,7 +857,7 @@ int24div(PG_FUNCTION_ARGS) int16 arg1 = PG_GETARG_INT16(0); int32 arg2 = PG_GETARG_INT32(1); - if (arg2 == 0) + if (unlikely(arg2 == 0)) { ereport(ERROR, (errcode(ERRCODE_DIVISION_BY_ZERO), @@ -967,14 +877,7 @@ int42pl(PG_FUNCTION_ARGS) 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 (unlikely(pg_add_s32_overflow(arg1, (int32) arg2, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); @@ -988,14 +891,7 @@ int42mi(PG_FUNCTION_ARGS) 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 (unlikely(pg_sub_s32_overflow(arg1, (int32) arg2, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); @@ -1009,20 +905,7 @@ int42mul(PG_FUNCTION_ARGS) 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 (unlikely(pg_mul_s32_overflow(arg1, (int32) arg2, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); @@ -1036,7 +919,7 @@ int42div(PG_FUNCTION_ARGS) int16 arg2 = PG_GETARG_INT16(1); int32 result; - if (arg2 == 0) + if (unlikely(arg2 == 0)) { ereport(ERROR, (errcode(ERRCODE_DIVISION_BY_ZERO), @@ -1053,12 +936,11 @@ int42div(PG_FUNCTION_ARGS) */ if (arg2 == -1) { - result = -arg1; - /* overflow check (needed for INT_MIN) */ - if (arg1 != 0 && SAMESIGN(result, arg1)) + if (unlikely(arg1 == PG_INT32_MIN)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); + result = -arg1; PG_RETURN_INT32(result); } @@ -1075,7 +957,7 @@ int4mod(PG_FUNCTION_ARGS) int32 arg1 = PG_GETARG_INT32(0); int32 arg2 = PG_GETARG_INT32(1); - if (arg2 == 0) + if (unlikely(arg2 == 0)) { ereport(ERROR, (errcode(ERRCODE_DIVISION_BY_ZERO), @@ -1103,7 +985,7 @@ int2mod(PG_FUNCTION_ARGS) int16 arg1 = PG_GETARG_INT16(0); int16 arg2 = PG_GETARG_INT16(1); - if (arg2 == 0) + if (unlikely(arg2 == 0)) { ereport(ERROR, (errcode(ERRCODE_DIVISION_BY_ZERO), @@ -1136,12 +1018,11 @@ 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 (unlikely(arg1 == 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); } @@ -1151,12 +1032,11 @@ 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 (unlikely(arg1 == 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); } @@ -1381,11 +1261,11 @@ generate_series_step_int4(PG_FUNCTION_ARGS) if ((fctx->step > 0 && fctx->current <= fctx->finish) || (fctx->step < 0 && fctx->current >= fctx->finish)) { - /* increment current in preparation for next iteration */ - fctx->current += fctx->step; - - /* if next-value computation overflows, this is the final result */ - if (SAMESIGN(result, fctx->step) && !SAMESIGN(result, fctx->current)) + /* + * Increment current in preparation for next iteration. If next-value + * computation overflows, this is the final result. + */ + if (pg_add_s32_overflow(fctx->current, fctx->step, &fctx->current)) fctx->step = 0; /* do when there is more left to send */ diff --git a/src/backend/utils/adt/int8.c b/src/backend/utils/adt/int8.c index afa434cfee..bc8dad5c5d 100644 --- a/src/backend/utils/adt/int8.c +++ b/src/backend/utils/adt/int8.c @@ -17,6 +17,7 @@ #include #include +#include "common/int.h" #include "funcapi.h" #include "libpq/pqformat.h" #include "utils/int8.h" @@ -25,8 +26,6 @@ #define MAXINT8LEN 25 -#define SAMESIGN(a,b) (((a) < 0) == ((b) < 0)) - typedef struct { int64 current; @@ -56,11 +55,14 @@ scanint8(const char *str, bool errorOK, int64 *result) { const char *ptr = str; int64 tmp = 0; - int sign = 1; + bool neg = false; /* * Do our own scan, rather than relying on sscanf which might be broken * for long long. + * + * As INT64_MIN can't be stored as a positive 64 bit integer, accumulate + * value as a negative number. */ /* skip leading spaces */ @@ -71,72 +73,60 @@ scanint8(const char *str, bool errorOK, int64 *result) if (*ptr == '-') { ptr++; - - /* - * Do an explicit check for INT64_MIN. Ugly though this is, it's - * cleaner than trying to get the loop below to handle it portably. - */ - if (strncmp(ptr, "9223372036854775808", 19) == 0) - { - tmp = PG_INT64_MIN; - ptr += 19; - goto gotdigits; - } - sign = -1; + neg = true; } else if (*ptr == '+') ptr++; /* require at least one digit */ - if (!isdigit((unsigned char) *ptr)) + if (unlikely(!isdigit((unsigned char) *ptr))) { - if (errorOK) - return false; - else - ereport(ERROR, - (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for integer: \"%s\"", - str))); + goto invalid_syntax; } /* process digits */ while (*ptr && isdigit((unsigned char) *ptr)) { - int64 newtmp = tmp * 10 + (*ptr++ - '0'); + int8 digit = (*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 %s", - str, "bigint"))); - } - tmp = newtmp; + if (unlikely(pg_mul_s64_overflow(tmp, 10, &tmp)) || + unlikely(pg_sub_s64_overflow(tmp, digit, &tmp))) + goto out_of_range; } -gotdigits: - /* allow trailing whitespace, but not other trailing chars */ while (*ptr != '\0' && isspace((unsigned char) *ptr)) ptr++; - if (*ptr != '\0') - { - if (errorOK) - return false; - else - ereport(ERROR, - (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for integer: \"%s\"", - str))); - } + if (unlikely(*ptr != '\0')) + goto invalid_syntax; - *result = (sign < 0) ? -tmp : tmp; + if (!neg) + { + if (unlikely(tmp == INT64_MIN)) + goto out_of_range; + tmp = -tmp; + } + *result = tmp; return true; + +out_of_range: + if (errorOK) + return false; + else + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("value \"%s\" is out of range for type %s", + str, "bigint"))); +invalid_syntax: + if (errorOK) + return false; + else + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for integer: \"%s\"", + str))); } /* int8in() @@ -492,12 +482,11 @@ 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 (unlikely(arg == PG_INT64_MIN)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("bigint out of range"))); + result = -arg; PG_RETURN_INT64(result); } @@ -516,14 +505,7 @@ 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)) + if (unlikely(pg_add_s64_overflow(arg1, arg2, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("bigint out of range"))); @@ -537,14 +519,7 @@ 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)) + if (unlikely(pg_sub_s64_overflow(arg1, arg2, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("bigint out of range"))); @@ -558,28 +533,10 @@ 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"))); - } + if (unlikely(pg_mul_s64_overflow(arg1, arg2, &result))) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("bigint out of range"))); PG_RETURN_INT64(result); } @@ -607,12 +564,11 @@ int8div(PG_FUNCTION_ARGS) */ if (arg2 == -1) { - result = -arg1; - /* overflow check (needed for INT64_MIN) */ - if (arg1 != 0 && SAMESIGN(result, arg1)) + if (unlikely(arg1 == INT64_MIN)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("bigint out of range"))); + result = -arg1; PG_RETURN_INT64(result); } @@ -632,12 +588,11 @@ 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 (unlikely(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); } @@ -650,7 +605,7 @@ int8mod(PG_FUNCTION_ARGS) int64 arg1 = PG_GETARG_INT64(0); int64 arg2 = PG_GETARG_INT64(1); - if (arg2 == 0) + if (unlikely(arg2 == 0)) { ereport(ERROR, (errcode(ERRCODE_DIVISION_BY_ZERO), @@ -687,16 +642,12 @@ 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) + if (unlikely(pg_add_s64_overflow(*arg, 1, arg))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("bigint out of range"))); - *arg = result; PG_RETURN_POINTER(arg); } else @@ -706,9 +657,7 @@ int8inc(PG_FUNCTION_ARGS) int64 arg = PG_GETARG_INT64(0); int64 result; - result = arg + 1; - /* Overflow check */ - if (result < 0 && arg > 0) + if (unlikely(pg_add_s64_overflow(arg, 1, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("bigint out of range"))); @@ -731,16 +680,11 @@ int8dec(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) + if (unlikely(pg_sub_s64_overflow(*arg, 1, arg))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("bigint out of range"))); - - *arg = result; PG_RETURN_POINTER(arg); } else @@ -750,9 +694,7 @@ int8dec(PG_FUNCTION_ARGS) int64 arg = PG_GETARG_INT64(0); int64 result; - result = arg - 1; - /* Overflow check */ - if (result > 0 && arg < 0) + if (unlikely(pg_sub_s64_overflow(arg, 1, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("bigint out of range"))); @@ -821,14 +763,7 @@ int84pl(PG_FUNCTION_ARGS) 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 (unlikely(pg_add_s64_overflow(arg1, (int64) arg2, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("bigint out of range"))); @@ -842,14 +777,7 @@ int84mi(PG_FUNCTION_ARGS) 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 (unlikely(pg_sub_s64_overflow(arg1, (int64) arg2, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("bigint out of range"))); @@ -863,20 +791,7 @@ int84mul(PG_FUNCTION_ARGS) 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 (unlikely(pg_mul_s64_overflow(arg1, (int64) arg2, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("bigint out of range"))); @@ -907,12 +822,11 @@ int84div(PG_FUNCTION_ARGS) */ if (arg2 == -1) { - result = -arg1; - /* overflow check (needed for INT64_MIN) */ - if (arg1 != 0 && SAMESIGN(result, arg1)) + if (unlikely(arg1 == INT64_MIN)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("bigint out of range"))); + result = -arg1; PG_RETURN_INT64(result); } @@ -930,14 +844,7 @@ int48pl(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)) + if (unlikely(pg_add_s64_overflow((int64) arg1, arg2, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("bigint out of range"))); @@ -951,14 +858,7 @@ int48mi(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)) + if (unlikely(pg_sub_s64_overflow((int64) arg1, arg2, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("bigint out of range"))); @@ -972,20 +872,7 @@ int48mul(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 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 (unlikely(pg_mul_s64_overflow((int64) arg1, arg2, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("bigint out of range"))); @@ -998,7 +885,7 @@ int48div(PG_FUNCTION_ARGS) int32 arg1 = PG_GETARG_INT32(0); int64 arg2 = PG_GETARG_INT64(1); - if (arg2 == 0) + if (unlikely(arg2 == 0)) { ereport(ERROR, (errcode(ERRCODE_DIVISION_BY_ZERO), @@ -1018,14 +905,7 @@ 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)) + if (unlikely(pg_add_s64_overflow(arg1, (int64) arg2, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("bigint out of range"))); @@ -1039,14 +919,7 @@ 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)) + if (unlikely(pg_sub_s64_overflow(arg1, (int64) arg2, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("bigint out of range"))); @@ -1060,20 +933,7 @@ 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) + if (unlikely(pg_mul_s64_overflow(arg1, (int64) arg2, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("bigint out of range"))); @@ -1087,7 +947,7 @@ int82div(PG_FUNCTION_ARGS) int16 arg2 = PG_GETARG_INT16(1); int64 result; - if (arg2 == 0) + if (unlikely(arg2 == 0)) { ereport(ERROR, (errcode(ERRCODE_DIVISION_BY_ZERO), @@ -1104,12 +964,11 @@ int82div(PG_FUNCTION_ARGS) */ if (arg2 == -1) { - result = -arg1; - /* overflow check (needed for INT64_MIN) */ - if (arg1 != 0 && SAMESIGN(result, arg1)) + if (unlikely(arg1 == INT64_MIN)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("bigint out of range"))); + result = -arg1; PG_RETURN_INT64(result); } @@ -1127,14 +986,7 @@ int28pl(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)) + if (unlikely(pg_add_s64_overflow((int64) arg1, arg2, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("bigint out of range"))); @@ -1148,14 +1000,7 @@ int28mi(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)) + if (unlikely(pg_sub_s64_overflow((int64) arg1, arg2, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("bigint out of range"))); @@ -1169,20 +1014,7 @@ int28mul(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 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 (unlikely(pg_mul_s64_overflow((int64) arg1, arg2, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("bigint out of range"))); @@ -1195,7 +1027,7 @@ int28div(PG_FUNCTION_ARGS) int16 arg1 = PG_GETARG_INT16(0); int64 arg2 = PG_GETARG_INT64(1); - if (arg2 == 0) + if (unlikely(arg2 == 0)) { ereport(ERROR, (errcode(ERRCODE_DIVISION_BY_ZERO), @@ -1287,17 +1119,13 @@ Datum int84(PG_FUNCTION_ARGS) { int64 arg = PG_GETARG_INT64(0); - int32 result; - result = (int32) arg; - - /* Test for overflow by reverse-conversion. */ - if ((int64) result != arg) + if (unlikely(arg < PG_INT32_MIN) || unlikely(arg > PG_INT32_MAX)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); - PG_RETURN_INT32(result); + PG_RETURN_INT32((int32) arg); } Datum @@ -1312,17 +1140,13 @@ Datum int82(PG_FUNCTION_ARGS) { int64 arg = PG_GETARG_INT64(0); - int16 result; - result = (int16) arg; - - /* Test for overflow by reverse-conversion. */ - if ((int64) result != arg) + if (unlikely(arg < PG_INT16_MIN) || unlikely(arg > PG_INT16_MAX)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("smallint out of range"))); - PG_RETURN_INT16(result); + PG_RETURN_INT16((int16) arg); } Datum @@ -1348,18 +1172,15 @@ dtoi8(PG_FUNCTION_ARGS) /* Round arg to nearest integer (but it's still in float form) */ arg = rint(arg); - /* - * Does it fit in an int64? Avoid assuming that we have handy constants - * defined for the range boundaries, instead test for overflow by - * reverse-conversion. - */ - result = (int64) arg; - - if ((float8) result != arg) + if (unlikely(arg < (double) PG_INT64_MIN) || + unlikely(arg > (double) PG_INT64_MAX) || + unlikely(isnan(arg))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("bigint out of range"))); + result = (int64) arg; + PG_RETURN_INT64(result); } @@ -1381,42 +1202,32 @@ Datum ftoi8(PG_FUNCTION_ARGS) { float4 arg = PG_GETARG_FLOAT4(0); - int64 result; float8 darg; /* Round arg to nearest integer (but it's still in float form) */ darg = rint(arg); - /* - * Does it fit in an int64? Avoid assuming that we have handy constants - * defined for the range boundaries, instead test for overflow by - * reverse-conversion. - */ - result = (int64) darg; - - if ((float8) result != darg) + if (unlikely(arg < (float4) PG_INT64_MIN) || + unlikely(arg > (float4) PG_INT64_MAX) || + unlikely(isnan(arg))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("bigint out of range"))); - PG_RETURN_INT64(result); + PG_RETURN_INT64((int64) darg); } Datum i8tooid(PG_FUNCTION_ARGS) { int64 arg = PG_GETARG_INT64(0); - Oid result; - result = (Oid) arg; - - /* Test for overflow by reverse-conversion. */ - if ((int64) result != arg) + if (unlikely(arg < 0) || unlikely(arg > PG_UINT32_MAX)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("OID out of range"))); - PG_RETURN_OID(result); + PG_RETURN_OID((Oid) arg); } Datum @@ -1494,11 +1305,11 @@ generate_series_step_int8(PG_FUNCTION_ARGS) if ((fctx->step > 0 && fctx->current <= fctx->finish) || (fctx->step < 0 && fctx->current >= fctx->finish)) { - /* increment current in preparation for next iteration */ - fctx->current += fctx->step; - - /* if next-value computation overflows, this is the final result */ - if (SAMESIGN(result, fctx->step) && !SAMESIGN(result, fctx->current)) + /* + * Increment current in preparation for next iteration. If next-value + * computation overflows, this is the final result. + */ + if (pg_add_s64_overflow(fctx->current, fctx->step, &fctx->current)) fctx->step = 0; /* do when there is more left to send */ diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c index 82e6f4483b..e9a6ca3535 100644 --- a/src/backend/utils/adt/numeric.c +++ b/src/backend/utils/adt/numeric.c @@ -28,6 +28,7 @@ #include "access/hash.h" #include "catalog/pg_type.h" +#include "common/int.h" #include "funcapi.h" #include "lib/hyperloglog.h" #include "libpq/pqformat.h" @@ -6169,8 +6170,7 @@ numericvar_to_int64(const NumericVar *var, int64 *result) int ndigits; int weight; int i; - int64 val, - oldval; + int64 val; bool neg; NumericVar rounded; @@ -6196,27 +6196,25 @@ numericvar_to_int64(const NumericVar *var, int64 *result) weight = rounded.weight; Assert(weight >= 0 && ndigits <= weight + 1); - /* Construct the result */ + /* + * Construct the result. To avoid issues with converting a value + * corresponding to INT64_MIN (which can't be represented as a positive 64 + * bit two's complement integer), accumulate value as a negative number. + */ 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 (unlikely(pg_mul_s64_overflow(val, NBASE, &val))) { - if (!neg || (-val) != val || val == 0 || oldval < 0) + free_var(&rounded); + return false; + } + + if (i < ndigits) + { + if (unlikely(pg_sub_s64_overflow(val, digits[i], &val))) { free_var(&rounded); return false; @@ -6226,7 +6224,14 @@ numericvar_to_int64(const NumericVar *var, int64 *result) free_var(&rounded); - *result = neg ? -val : val; + if (!neg) + { + if (unlikely(val == INT64_MIN)) + return false; + val = -val; + } + *result = val; + return true; } diff --git a/src/backend/utils/adt/oracle_compat.c b/src/backend/utils/adt/oracle_compat.c index b82016500b..a5aa6a95aa 100644 --- a/src/backend/utils/adt/oracle_compat.c +++ b/src/backend/utils/adt/oracle_compat.c @@ -15,6 +15,7 @@ */ #include "postgres.h" +#include "common/int.h" #include "utils/builtins.h" #include "utils/formatting.h" #include "mb/pg_wchar.h" @@ -1045,19 +1046,12 @@ 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 (unlikely(pg_mul_s32_overflow(count, slen, &tlen)) || + unlikely(pg_add_s32_overflow(tlen, VARHDRSZ, &tlen))) + ereport(ERROR, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("requested length too large"))); result = (text *) palloc(tlen); diff --git a/src/backend/utils/adt/varbit.c b/src/backend/utils/adt/varbit.c index 478fab9bfc..6caa7e9b5e 100644 --- a/src/backend/utils/adt/varbit.c +++ b/src/backend/utils/adt/varbit.c @@ -17,6 +17,7 @@ #include "postgres.h" #include "access/htup_details.h" +#include "common/int.h" #include "libpq/pqformat.h" #include "nodes/nodeFuncs.h" #include "utils/array.h" @@ -1166,8 +1167,7 @@ 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_add_s32_overflow(sp, sl, &sp_pl_sl)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c index 39b68dbc65..a84e845ad2 100644 --- a/src/backend/utils/adt/varlena.c +++ b/src/backend/utils/adt/varlena.c @@ -21,6 +21,7 @@ #include "access/tuptoaster.h" #include "catalog/pg_collation.h" #include "catalog/pg_type.h" +#include "common/int.h" #include "common/md5.h" #include "lib/hyperloglog.h" #include "libpq/pqformat.h" @@ -1047,8 +1048,7 @@ 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_add_s32_overflow(sp, sl, &sp_pl_sl)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); @@ -2950,8 +2950,7 @@ 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_add_s32_overflow(sp, sl, &sp_pl_sl)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); @@ -5279,13 +5278,13 @@ text_format_parse_digits(const char **ptr, const char *end_ptr, int *value) while (*cp >= '0' && *cp <= '9') { - int newval = val * 10 + (*cp - '0'); + int8 digit = (*cp - '0'); - if (newval / 10 != val) /* overflow? */ + if (unlikely(pg_mul_s32_overflow(val, 10, &val)) || + unlikely(pg_add_s32_overflow(val, digit, &val))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("number is out of range"))); - val = newval; ADVANCE_PARSE_POINTER(cp, end_ptr); found = true; }