aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/timestamp.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2024-02-13 15:58:40 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2024-02-13 15:58:40 -0500
commit5ebc9c90173f32cffe373a80835f157b9ebfa3bd (patch)
tree508bf57543052db2b4d8e5ce09678f070f4ed691 /src/backend/utils/adt/timestamp.c
parentfbf9a7ac4d300bbadbffe11c58cb54fcbe15601f (diff)
downloadpostgresql-5ebc9c90173f32cffe373a80835f157b9ebfa3bd.tar.gz
postgresql-5ebc9c90173f32cffe373a80835f157b9ebfa3bd.zip
Catch overflow when rounding intervals in AdjustIntervalForTypmod.
Previously, an interval microseconds field close to INT64_MAX or INT64_MIN could overflow, producing a result with not even the correct sign, while being rounded to match a precision specification. This seems worth fixing, but not worth back-patching, in part because the ereturn() notation doesn't exist very far back. Report and patch by Joseph Koshakow (some cosmetic mods by me) Discussion: https://postgr.es/m/CAAvxfHfpuLgqJYzkUcher466Z1LpmE+5Sm+zc8L6zKCOQ+6TDQ@mail.gmail.com
Diffstat (limited to 'src/backend/utils/adt/timestamp.c')
-rw-r--r--src/backend/utils/adt/timestamp.c22
1 files changed, 14 insertions, 8 deletions
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index c38f88dba78..ed03c50a6de 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -1509,17 +1509,23 @@ AdjustIntervalForTypmod(Interval *interval, int32 typmod,
if (interval->time >= INT64CONST(0))
{
- interval->time = ((interval->time +
- IntervalOffsets[precision]) /
- IntervalScales[precision]) *
- IntervalScales[precision];
+ if (pg_add_s64_overflow(interval->time,
+ IntervalOffsets[precision],
+ &interval->time))
+ ereturn(escontext, false,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("interval out of range")));
+ interval->time -= interval->time % IntervalScales[precision];
}
else
{
- interval->time = -(((-interval->time +
- IntervalOffsets[precision]) /
- IntervalScales[precision]) *
- IntervalScales[precision]);
+ if (pg_sub_s64_overflow(interval->time,
+ IntervalOffsets[precision],
+ &interval->time))
+ ereturn(escontext, false,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("interval out of range")));
+ interval->time -= interval->time % IntervalScales[precision];
}
}
}