1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-13 07:41:39 +03:00

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
This commit is contained in:
Tom Lane
2022-02-28 15:36:54 -05:00
parent a59c79564b
commit 54bd1e43ca
3 changed files with 79 additions and 4 deletions

View File

@ -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)
{