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:
@ -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)
|
||||
{
|
||||
|
Reference in New Issue
Block a user