postgres.git / summary / log / commit / refs

commit    cb0ccefa03d351d9c643362ac77fca7dadd9fc42
Author:   Tom Lane <tgl@sss.pgh.pa.us>
Date:     Sun Apr 28 17:42:13 2024 +0000
First released in: 17.0, 12.19, 13.15, 14.12, 15.7, 16.3

    Detect more overflows in timestamp[tz]_pl_interval.
    
    In commit 25cd2d640 I (tgl) opined that "The additions of the months
    and microseconds fields could also overflow, of course.  However,
    I believe we need no additional checks there; the existing range
    checks should catch such cases".  This is demonstrably wrong however
    for the microseconds field, and given that discovery it seems prudent
    to be paranoid about the months addition as well.
    
    Report and patch by Joseph Koshakow.  As before, back-patch to all
    supported branches.  (However, the test case doesn't work before
    v15 because we didn't allow wider-than-int32 numbers in interval
    literals.  A variant test could probably be built that fits within
    that restriction, but it didn't seem worth the trouble.)
    
    Discussion: https://postgr.es/m/CAAvxfHf77sRHKoEzUw9_cMYSpbpNS2C+J_+8Dq4+0oi8iKopeA@mail.gmail.com


src/backend/utils/adt/timestamp.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c index b41a08878a0..d3f0398e18e 100644 --- a/src/backend/utils/adt/timestamp.c +++ b/src/backend/utils/adt/timestamp.c @@ -2859,7 +2859,10 @@ timestamp_pl_interval(PG_FUNCTION_ARGS) (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); - tm->tm_mon += span->month; + if (pg_add_s32_overflow(tm->tm_mon, span->month, &tm->tm_mon)) + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("timestamp out of range"))); if (tm->tm_mon > MONTHS_PER_YEAR) { tm->tm_year += (tm->tm_mon - 1) / MONTHS_PER_YEAR; @@ -2911,7 +2914,10 @@ timestamp_pl_interval(PG_FUNCTION_ARGS) errmsg("timestamp out of range"))); } - timestamp += span->time; + if (pg_add_s64_overflow(timestamp, span->time, &timestamp)) + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("timestamp out of range"))); if (!IS_VALID_TIMESTAMP(timestamp)) ereport(ERROR, @@ -2973,7 +2979,10 @@ timestamptz_pl_interval(PG_FUNCTION_ARGS) (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); - tm->tm_mon += span->month; + if (pg_add_s32_overflow(tm->tm_mon, span->month, &tm->tm_mon)) + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("timestamp out of range"))); if (tm->tm_mon > MONTHS_PER_YEAR) { tm->tm_year += (tm->tm_mon - 1) / MONTHS_PER_YEAR; @@ -3032,7 +3041,10 @@ timestamptz_pl_interval(PG_FUNCTION_ARGS) errmsg("timestamp out of range"))); } - timestamp += span->time; + if (pg_add_s64_overflow(timestamp, span->time, &timestamp)) + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("timestamp out of range"))); if (!IS_VALID_TIMESTAMP(timestamp)) ereport(ERROR, [parent: 6d4a17010740]