From 2952414253f3a76d7b2983b9eaf57de0c5237c0e Mon Sep 17 00:00:00 2001 From: Joseph Koshakow Date: Sat, 18 Mar 2023 12:38:58 -0400 Subject: [PATCH 2/3] Check for overflow in make_interval --- src/backend/utils/adt/timestamp.c | 24 +++++++++++++++++++----- src/include/common/int.h | 13 +++++++++++++ src/test/regress/expected/interval.out | 5 +++++ src/test/regress/sql/interval.sql | 4 ++++ 4 files changed, 41 insertions(+), 5 deletions(-) diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c index c266d0d02e..de80a7e5b5 100644 --- a/src/backend/utils/adt/timestamp.c +++ b/src/backend/utils/adt/timestamp.c @@ -1501,13 +1501,27 @@ make_interval(PG_FUNCTION_ARGS) errmsg("interval out of range"))); result = (Interval *) palloc(sizeof(Interval)); - result->month = years * MONTHS_PER_YEAR + months; - result->day = weeks * 7 + days; + result->month = months; + if (pg_mul_add_s32_overflow(years, MONTHS_PER_YEAR, &result->month)) + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("interval out of range"))); + result->day = days; + if (pg_mul_add_s32_overflow(weeks, 7, &result->day)) + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("interval out of range"))); secs = rint(secs * USECS_PER_SEC); - result->time = hours * ((int64) SECS_PER_HOUR * USECS_PER_SEC) + - mins * ((int64) SECS_PER_MINUTE * USECS_PER_SEC) + - (int64) secs; + result->time = secs; + if (pg_mul_add_s64_overflow(mins, ((int64) SECS_PER_MINUTE * USECS_PER_SEC), &result->time)) + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("interval out of range"))); + if (pg_mul_add_s64_overflow(hours, ((int64) SECS_PER_HOUR * USECS_PER_SEC), &result->time)) + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("interval out of range"))); PG_RETURN_INTERVAL_P(result); } diff --git a/src/include/common/int.h b/src/include/common/int.h index 81726c65f7..48ef495551 100644 --- a/src/include/common/int.h +++ b/src/include/common/int.h @@ -154,6 +154,19 @@ pg_mul_s32_overflow(int32 a, int32 b, int32 *result) #endif } +/* + * Add val * multiplier to *sum. + * Returns false if successful, true on overflow. + */ +static inline bool +pg_mul_add_s32_overflow(int32 val, int32 multiplier, int32 *sum) +{ + int32 product; + + return pg_mul_s32_overflow(val, multiplier, &product) || + pg_add_s32_overflow(*sum, product, sum); +} + /* * INT64 */ diff --git a/src/test/regress/expected/interval.out b/src/test/regress/expected/interval.out index 28b71d9681..27bfb8ba9b 100644 --- a/src/test/regress/expected/interval.out +++ b/src/test/regress/expected/interval.out @@ -1587,6 +1587,11 @@ select interval '-2147483648 months -2147483648 days -9223372036854775808 micros ERROR: interval field value out of range: "-2147483648 months -2147483648 days -9223372036854775808 microseconds ago" LINE 1: select interval '-2147483648 months -2147483648 days -922337... ^ +-- overflowing using make_interval +select make_interval(1, 2147483647, 2147483647, 1, 1, 1, 9223372036854.7759); +ERROR: interval out of range +select make_interval(-1, -2147483648, -2147483648, -1, -1, -1, -9223372036854.7759); +ERROR: interval out of range -- test that INT_MIN number is formatted properly SET IntervalStyle to postgres; select interval '-2147483648 months -2147483648 days -9223372036854775808 us'; diff --git a/src/test/regress/sql/interval.sql b/src/test/regress/sql/interval.sql index 56feda1a3d..f1abf08501 100644 --- a/src/test/regress/sql/interval.sql +++ b/src/test/regress/sql/interval.sql @@ -511,6 +511,10 @@ select interval '-2147483648 days ago'; select interval '-9223372036854775808 microseconds ago'; select interval '-2147483648 months -2147483648 days -9223372036854775808 microseconds ago'; +-- overflowing using make_interval +select make_interval(1, 2147483647, 2147483647, 1, 1, 1, 9223372036854.7759); +select make_interval(-1, -2147483648, -2147483648, -1, -1, -1, -9223372036854.7759); + -- test that INT_MIN number is formatted properly SET IntervalStyle to postgres; select interval '-2147483648 months -2147483648 days -9223372036854775808 us'; -- 2.34.1