aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/timestamp.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2022-02-28 15:36:54 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2022-02-28 15:36:54 -0500
commit54bd1e43ca56e323aef309dc2dc0e1391825ce68 (patch)
tree95a9580dc560d5487f10f32a9633f230566243d2 /src/backend/utils/adt/timestamp.c
parenta59c79564bdc209a5bc7b02d706f0d7352eb82fa (diff)
downloadpostgresql-54bd1e43ca56e323aef309dc2dc0e1391825ce68.tar.gz
postgresql-54bd1e43ca56e323aef309dc2dc0e1391825ce68.zip
Handle integer overflow in interval justification functions.
justify_interval, justify_hours, and justify_days didn't check for overflow when promoting hours to days or days to months; but that's possible when the upper field's value is already large. Detect and report any such overflow. Also, we can avoid unnecessary overflow in some cases in justify_interval by pre-justifying the days field. (Thanks to Nathan Bossart for this idea.) Joe Koshakow Discussion: https://postgr.es/m/CAAvxfHeNqsJ2xYFbPUf_8nNQUiJqkag04NW6aBQQ0dbZsxfWHA@mail.gmail.com
Diffstat (limited to 'src/backend/utils/adt/timestamp.c')
-rw-r--r--src/backend/utils/adt/timestamp.c35
1 files changed, 31 insertions, 4 deletions
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index 36f8a84bcc5..ae36ff33285 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -2717,12 +2717,33 @@ interval_justify_interval(PG_FUNCTION_ARGS)
result->day = span->day;
result->time = span->time;
+ /* pre-justify days if it might prevent overflow */
+ if ((result->day > 0 && result->time > 0) ||
+ (result->day < 0 && result->time < 0))
+ {
+ wholemonth = result->day / DAYS_PER_MONTH;
+ result->day -= wholemonth * DAYS_PER_MONTH;
+ if (pg_add_s32_overflow(result->month, wholemonth, &result->month))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("interval out of range")));
+ }
+
+ /*
+ * Since TimeOffset is int64, abs(wholeday) can't exceed about 1.07e8. If
+ * we pre-justified then abs(result->day) is less than DAYS_PER_MONTH, so
+ * this addition can't overflow. If we didn't pre-justify, then day and
+ * time are of different signs, so it still can't overflow.
+ */
TMODULO(result->time, wholeday, USECS_PER_DAY);
- result->day += wholeday; /* could overflow... */
+ result->day += wholeday;
wholemonth = result->day / DAYS_PER_MONTH;
result->day -= wholemonth * DAYS_PER_MONTH;
- result->month += wholemonth;
+ if (pg_add_s32_overflow(result->month, wholemonth, &result->month))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("interval out of range")));
if (result->month > 0 &&
(result->day < 0 || (result->day == 0 && result->time < 0)))
@@ -2772,7 +2793,10 @@ interval_justify_hours(PG_FUNCTION_ARGS)
result->time = span->time;
TMODULO(result->time, wholeday, USECS_PER_DAY);
- result->day += wholeday; /* could overflow... */
+ if (pg_add_s32_overflow(result->day, wholeday, &result->day))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("interval out of range")));
if (result->day > 0 && result->time < 0)
{
@@ -2808,7 +2832,10 @@ interval_justify_days(PG_FUNCTION_ARGS)
wholemonth = result->day / DAYS_PER_MONTH;
result->day -= wholemonth * DAYS_PER_MONTH;
- result->month += wholemonth;
+ if (pg_add_s32_overflow(result->month, wholemonth, &result->month))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("interval out of range")));
if (result->month > 0 && result->day < 0)
{