4141#error -ffast-math is known to break this code
4242#endif
4343
44+ #define SAMESIGN (a ,b ) (((a) < 0) == ((b) < 0))
45+
46+ #ifndef INT64_MAX
47+ #define INT64_MAX INT64CONST(0x7FFFFFFFFFFFFFFF)
48+ #endif
49+
50+ #ifndef INT64_MIN
51+ #define INT64_MIN (-INT64CONST(0x7FFFFFFFFFFFFFFF) - 1)
52+ #endif
4453
4554/* Set at postmaster start */
4655TimestampTz PgStartTime ;
@@ -1694,7 +1703,11 @@ interval2tm(Interval span, struct pg_tm * tm, fsec_t *fsec)
16941703#ifdef HAVE_INT64_TIMESTAMP
16951704 tfrac = time / USECS_PER_HOUR ;
16961705 time -= tfrac * USECS_PER_HOUR ;
1697- tm -> tm_hour = tfrac ; /* could overflow ... */
1706+ tm -> tm_hour = tfrac ;
1707+ if (!SAMESIGN (tm -> tm_hour , tfrac ))
1708+ ereport (ERROR ,
1709+ (errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
1710+ errmsg ("interval out of range" )));
16981711 tfrac = time / USECS_PER_MINUTE ;
16991712 time -= tfrac * USECS_PER_MINUTE ;
17001713 tm -> tm_min = tfrac ;
@@ -1725,7 +1738,11 @@ interval2tm(Interval span, struct pg_tm * tm, fsec_t *fsec)
17251738int
17261739tm2interval (struct pg_tm * tm , fsec_t fsec , Interval * span )
17271740{
1728- span -> month = tm -> tm_year * MONTHS_PER_YEAR + tm -> tm_mon ;
1741+ double total_months = (double )tm -> tm_year * MONTHS_PER_YEAR + tm -> tm_mon ;
1742+
1743+ if (total_months > INT_MAX || total_months < INT_MIN )
1744+ return -1 ;
1745+ span -> month = total_months ;
17291746 span -> day = tm -> tm_mday ;
17301747#ifdef HAVE_INT64_TIMESTAMP
17311748 span -> time = (((((tm -> tm_hour * INT64CONST (60 )) +
@@ -2826,8 +2843,21 @@ interval_um(PG_FUNCTION_ARGS)
28262843 result = (Interval * ) palloc (sizeof (Interval ));
28272844
28282845 result -> time = - interval -> time ;
2846+ /* overflow check copied from int4um */
2847+ if (interval -> time != 0 && SAMESIGN (result -> time , interval -> time ))
2848+ ereport (ERROR ,
2849+ (errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
2850+ errmsg ("interval out of range" )));
28292851 result -> day = - interval -> day ;
2852+ if (interval -> day != 0 && SAMESIGN (result -> day , interval -> day ))
2853+ ereport (ERROR ,
2854+ (errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
2855+ errmsg ("interval out of range" )));
28302856 result -> month = - interval -> month ;
2857+ if (interval -> month != 0 && SAMESIGN (result -> month , interval -> month ))
2858+ ereport (ERROR ,
2859+ (errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
2860+ errmsg ("interval out of range" )));
28312861
28322862 PG_RETURN_INTERVAL_P (result );
28332863}
@@ -2872,8 +2902,26 @@ interval_pl(PG_FUNCTION_ARGS)
28722902 result = (Interval * ) palloc (sizeof (Interval ));
28732903
28742904 result -> month = span1 -> month + span2 -> month ;
2905+ /* overflow check copied from int4pl */
2906+ if (SAMESIGN (span1 -> month , span2 -> month ) &&
2907+ !SAMESIGN (result -> month , span1 -> month ))
2908+ ereport (ERROR ,
2909+ (errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
2910+ errmsg ("interval out of range" )));
2911+
28752912 result -> day = span1 -> day + span2 -> day ;
2913+ if (SAMESIGN (span1 -> day , span2 -> day ) &&
2914+ !SAMESIGN (result -> day , span1 -> day ))
2915+ ereport (ERROR ,
2916+ (errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
2917+ errmsg ("interval out of range" )));
2918+
28762919 result -> time = span1 -> time + span2 -> time ;
2920+ if (SAMESIGN (span1 -> time , span2 -> time ) &&
2921+ !SAMESIGN (result -> time , span1 -> time ))
2922+ ereport (ERROR ,
2923+ (errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
2924+ errmsg ("interval out of range" )));
28772925
28782926 PG_RETURN_INTERVAL_P (result );
28792927}
@@ -2888,8 +2936,27 @@ interval_mi(PG_FUNCTION_ARGS)
28882936 result = (Interval * ) palloc (sizeof (Interval ));
28892937
28902938 result -> month = span1 -> month - span2 -> month ;
2939+ /* overflow check copied from int4mi */
2940+ if (!SAMESIGN (span1 -> month , span2 -> month ) &&
2941+ !SAMESIGN (result -> month , span1 -> month ))
2942+ ereport (ERROR ,
2943+ (errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
2944+ errmsg ("interval out of range" )));
2945+
28912946 result -> day = span1 -> day - span2 -> day ;
2947+ if (!SAMESIGN (span1 -> day , span2 -> day ) &&
2948+ !SAMESIGN (result -> day , span1 -> day ))
2949+ ereport (ERROR ,
2950+ (errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
2951+ errmsg ("interval out of range" )));
2952+
28922953 result -> time = span1 -> time - span2 -> time ;
2954+ if (!SAMESIGN (span1 -> time , span2 -> time ) &&
2955+ !SAMESIGN (result -> time , span1 -> time ))
2956+ ereport (ERROR ,
2957+ (errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
2958+ errmsg ("interval out of range" )));
2959+
28932960
28942961 PG_RETURN_INTERVAL_P (result );
28952962}
@@ -2906,15 +2973,27 @@ interval_mul(PG_FUNCTION_ARGS)
29062973 Interval * span = PG_GETARG_INTERVAL_P (0 );
29072974 float8 factor = PG_GETARG_FLOAT8 (1 );
29082975 double month_remainder_days ,
2909- sec_remainder ;
2976+ sec_remainder ,
2977+ result_double ;
29102978 int32 orig_month = span -> month ,
29112979 orig_day = span -> day ;
29122980 Interval * result ;
29132981
29142982 result = (Interval * ) palloc (sizeof (Interval ));
29152983
2916- result -> month = (int32 ) (span -> month * factor );
2917- result -> day = (int32 ) (span -> day * factor );
2984+ result_double = span -> month * factor ;
2985+ if (result_double > INT_MAX || result_double < INT_MIN )
2986+ ereport (ERROR ,
2987+ (errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
2988+ errmsg ("interval out of range" )));
2989+ result -> month = (int32 ) result_double ;
2990+
2991+ result_double = span -> day * factor ;
2992+ if (result_double > INT_MAX || result_double < INT_MIN )
2993+ ereport (ERROR ,
2994+ (errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
2995+ errmsg ("interval out of range" )));
2996+ result -> day = (int32 ) result_double ;
29182997
29192998 /*
29202999 * The above correctly handles the whole-number part of the month and day
@@ -2954,7 +3033,12 @@ interval_mul(PG_FUNCTION_ARGS)
29543033 /* cascade units down */
29553034 result -> day += (int32 ) month_remainder_days ;
29563035#ifdef HAVE_INT64_TIMESTAMP
2957- result -> time = rint (span -> time * factor + sec_remainder * USECS_PER_SEC );
3036+ result_double = rint (span -> time * factor + sec_remainder * USECS_PER_SEC );
3037+ if (result_double > INT64_MAX || result_double < INT64_MIN )
3038+ ereport (ERROR ,
3039+ (errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
3040+ errmsg ("interval out of range" )));
3041+ result -> time = (int64 ) result_double ;
29583042#else
29593043 result -> time = span -> time * factor + sec_remainder ;
29603044#endif
0 commit comments