41
41
#error -ffast-math is known to break this code
42
42
#endif
43
43
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
44
53
45
54
/* Set at postmaster start */
46
55
TimestampTz PgStartTime ;
@@ -1694,7 +1703,11 @@ interval2tm(Interval span, struct pg_tm * tm, fsec_t *fsec)
1694
1703
#ifdef HAVE_INT64_TIMESTAMP
1695
1704
tfrac = time / USECS_PER_HOUR ;
1696
1705
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" )));
1698
1711
tfrac = time / USECS_PER_MINUTE ;
1699
1712
time -= tfrac * USECS_PER_MINUTE ;
1700
1713
tm -> tm_min = tfrac ;
@@ -1725,7 +1738,11 @@ interval2tm(Interval span, struct pg_tm * tm, fsec_t *fsec)
1725
1738
int
1726
1739
tm2interval (struct pg_tm * tm , fsec_t fsec , Interval * span )
1727
1740
{
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 ;
1729
1746
span -> day = tm -> tm_mday ;
1730
1747
#ifdef HAVE_INT64_TIMESTAMP
1731
1748
span -> time = (((((tm -> tm_hour * INT64CONST (60 )) +
@@ -2826,8 +2843,21 @@ interval_um(PG_FUNCTION_ARGS)
2826
2843
result = (Interval * ) palloc (sizeof (Interval ));
2827
2844
2828
2845
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" )));
2829
2851
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" )));
2830
2856
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" )));
2831
2861
2832
2862
PG_RETURN_INTERVAL_P (result );
2833
2863
}
@@ -2872,8 +2902,26 @@ interval_pl(PG_FUNCTION_ARGS)
2872
2902
result = (Interval * ) palloc (sizeof (Interval ));
2873
2903
2874
2904
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
+
2875
2912
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
+
2876
2919
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" )));
2877
2925
2878
2926
PG_RETURN_INTERVAL_P (result );
2879
2927
}
@@ -2888,8 +2936,27 @@ interval_mi(PG_FUNCTION_ARGS)
2888
2936
result = (Interval * ) palloc (sizeof (Interval ));
2889
2937
2890
2938
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
+
2891
2946
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
+
2892
2953
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
+
2893
2960
2894
2961
PG_RETURN_INTERVAL_P (result );
2895
2962
}
@@ -2906,15 +2973,27 @@ interval_mul(PG_FUNCTION_ARGS)
2906
2973
Interval * span = PG_GETARG_INTERVAL_P (0 );
2907
2974
float8 factor = PG_GETARG_FLOAT8 (1 );
2908
2975
double month_remainder_days ,
2909
- sec_remainder ;
2976
+ sec_remainder ,
2977
+ result_double ;
2910
2978
int32 orig_month = span -> month ,
2911
2979
orig_day = span -> day ;
2912
2980
Interval * result ;
2913
2981
2914
2982
result = (Interval * ) palloc (sizeof (Interval ));
2915
2983
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 ;
2918
2997
2919
2998
/*
2920
2999
* The above correctly handles the whole-number part of the month and day
@@ -2954,7 +3033,12 @@ interval_mul(PG_FUNCTION_ARGS)
2954
3033
/* cascade units down */
2955
3034
result -> day += (int32 ) month_remainder_days ;
2956
3035
#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 ;
2958
3042
#else
2959
3043
result -> time = span -> time * factor + sec_remainder ;
2960
3044
#endif
0 commit comments