diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2022-04-02 16:12:26 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2022-04-02 16:12:29 -0400 |
commit | e39f9904671082c5ad3a2c5acbdbd028fa93bf35 (patch) | |
tree | 6ab9ab1ed3b78bab977b0949e3cfcdb6af9f9cde /src/include/datatype/timestamp.h | |
parent | f7e4d5c64fb3977e3a773e7213472be1b59dab2f (diff) | |
download | postgresql-e39f9904671082c5ad3a2c5acbdbd028fa93bf35.tar.gz postgresql-e39f9904671082c5ad3a2c5acbdbd028fa93bf35.zip |
Fix overflow hazards in interval input and output conversions.
DecodeInterval (interval input) was careless about integer-overflow
hazards, allowing bogus results to be obtained for sufficiently
large input values. Also, since it initially converted the input
to a "struct tm", it was impossible to produce the full range of
representable interval values.
Meanwhile, EncodeInterval (interval output) and a few other
functions could suffer failures if asked to process sufficiently
large interval values, because they also relied on being able to
represent an interval in "struct tm" which is not designed to
handle that.
Fix all this stuff by introducing new struct types that are more
fit for purpose.
While this is clearly a bug fix, it's also an API break for any
code that's calling these functions directly. So back-patching
doesn't seem wise, especially in view of the lack of field
complaints.
Joe Koshakow, editorialized a bit by me
Discussion: https://postgr.es/m/CAAvxfHff0JLYHwyBrtMx_=6wr=k2Xp+D+-X3vEhHjJYMj+mQcg@mail.gmail.com
Diffstat (limited to 'src/include/datatype/timestamp.h')
-rw-r--r-- | src/include/datatype/timestamp.h | 39 |
1 files changed, 39 insertions, 0 deletions
diff --git a/src/include/datatype/timestamp.h b/src/include/datatype/timestamp.h index 5fa38d20d84..d155f1b03b0 100644 --- a/src/include/datatype/timestamp.h +++ b/src/include/datatype/timestamp.h @@ -40,6 +40,10 @@ typedef int64 TimestampTz; typedef int64 TimeOffset; typedef int32 fsec_t; /* fractional seconds (in microseconds) */ + +/* + * Storage format for type interval. + */ typedef struct { TimeOffset time; /* all time units other than days, months and @@ -48,6 +52,41 @@ typedef struct int32 month; /* months and years, after time for alignment */ } Interval; +/* + * Data structure representing a broken-down interval. + * + * For historical reasons, this is modeled on struct pg_tm for timestamps. + * Unlike the situation for timestamps, there's no magic interpretation + * needed for months or years: they're just zero or not. Note that fields + * can be negative; however, because of the divisions done while converting + * from struct Interval, only tm_mday could be INT_MIN. This is important + * because we may need to negate the values in some code paths. + */ +struct pg_itm +{ + int tm_usec; + int tm_sec; + int tm_min; + int64 tm_hour; /* needs to be wide */ + int tm_mday; + int tm_mon; + int tm_year; +}; + +/* + * Data structure for decoding intervals. We could just use struct pg_itm, + * but then the requirement for tm_usec to be 64 bits would propagate to + * places where it's not really needed. Also, omitting the fields that + * aren't used during decoding seems like a good error-prevention measure. + */ +struct pg_itm_in +{ + int64 tm_usec; /* needs to be wide */ + int tm_mday; + int tm_mon; + int tm_year; +}; + /* Limits on the "precision" option (typmod) for these data types */ #define MAX_TIMESTAMP_PRECISION 6 |