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
16951704tfrac = time /USECS_PER_HOUR ;
16961705time -= 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" )));
16981711tfrac = time /USECS_PER_MINUTE ;
16991712time -= tfrac * USECS_PER_MINUTE ;
17001713tm -> 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 ;
17291746span -> day = tm -> tm_mday ;
17301747#ifdef HAVE_INT64_TIMESTAMP
17311748span -> time = (((((tm -> tm_hour * INT64CONST (60 ))+
@@ -2826,8 +2843,21 @@ interval_um(PG_FUNCTION_ARGS)
28262843result = (Interval * )palloc (sizeof (Interval ));
28272844
28282845result -> 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" )));
28292851result -> 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" )));
28302856result -> 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
28322862PG_RETURN_INTERVAL_P (result );
28332863}
@@ -2872,8 +2902,26 @@ interval_pl(PG_FUNCTION_ARGS)
28722902result = (Interval * )palloc (sizeof (Interval ));
28732903
28742904result -> 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+
28752912result -> 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+
28762919result -> 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
28782926PG_RETURN_INTERVAL_P (result );
28792927}
@@ -2888,8 +2936,27 @@ interval_mi(PG_FUNCTION_ARGS)
28882936result = (Interval * )palloc (sizeof (Interval ));
28892937
28902938result -> 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+
28912946result -> 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+
28922953result -> 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
28942961PG_RETURN_INTERVAL_P (result );
28952962}
@@ -2906,15 +2973,27 @@ interval_mul(PG_FUNCTION_ARGS)
29062973Interval * span = PG_GETARG_INTERVAL_P (0 );
29072974float8 factor = PG_GETARG_FLOAT8 (1 );
29082975double month_remainder_days ,
2909- sec_remainder ;
2976+ sec_remainder ,
2977+ result_double ;
29102978int32 orig_month = span -> month ,
29112979orig_day = span -> day ;
29122980Interval * result ;
29132981
29142982result = (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 */
29553034result -> 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
29593043result -> time = span -> time * factor + sec_remainder ;
29603044#endif