Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commite39f990

Browse files
committed
Fix overflow hazards in interval input and output conversions.
DecodeInterval (interval input) was careless about integer-overflowhazards, allowing bogus results to be obtained for sufficientlylarge input values. Also, since it initially converted the inputto a "struct tm", it was impossible to produce the full range ofrepresentable interval values.Meanwhile, EncodeInterval (interval output) and a few otherfunctions could suffer failures if asked to process sufficientlylarge interval values, because they also relied on being able torepresent an interval in "struct tm" which is not designed tohandle that.Fix all this stuff by introducing new struct types that are morefit for purpose.While this is clearly a bug fix, it's also an API break for anycode that's calling these functions directly. So back-patchingdoesn't seem wise, especially in view of the lack of fieldcomplaints.Joe Koshakow, editorialized a bit by meDiscussion:https://postgr.es/m/CAAvxfHff0JLYHwyBrtMx_=6wr=k2Xp+D+-X3vEhHjJYMj+mQcg@mail.gmail.com
1 parentf7e4d5c commite39f990

File tree

9 files changed

+1473
-372
lines changed

9 files changed

+1473
-372
lines changed

‎src/backend/utils/adt/datetime.c

Lines changed: 474 additions & 260 deletions
Large diffs are not rendered by default.

‎src/backend/utils/adt/formatting.c

Lines changed: 65 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -491,11 +491,28 @@ typedef struct
491491

492492
/* ----------
493493
* Datetime to char conversion
494+
*
495+
* To support intervals as well as timestamps, we use a custom "tm" struct
496+
* that is almost like struct pg_tm, but has a 64-bit tm_hour field.
497+
* We omit the tm_isdst and tm_zone fields, which are not used here.
494498
* ----------
495499
*/
500+
structfmt_tm
501+
{
502+
inttm_sec;
503+
inttm_min;
504+
int64tm_hour;
505+
inttm_mday;
506+
inttm_mon;
507+
inttm_year;
508+
inttm_wday;
509+
inttm_yday;
510+
longinttm_gmtoff;
511+
};
512+
496513
typedefstructTmToChar
497514
{
498-
structpg_tmtm;/* classic 'tm' struct */
515+
structfmt_tmtm;/* almost the classic 'tm' struct */
499516
fsec_tfsec;/* fractional seconds */
500517
constchar*tzn;/* timezone */
501518
}TmToChar;
@@ -504,12 +521,25 @@ typedef struct TmToChar
504521
#definetmtcTzn(_X) ((_X)->tzn)
505522
#definetmtcFsec(_X)((_X)->fsec)
506523

524+
/* Note: this is used to copy pg_tm to fmt_tm, so not quite a bitwise copy */
525+
#defineCOPY_tm(_DST,_SRC) \
526+
do {\
527+
(_DST)->tm_sec = (_SRC)->tm_sec; \
528+
(_DST)->tm_min = (_SRC)->tm_min; \
529+
(_DST)->tm_hour = (_SRC)->tm_hour; \
530+
(_DST)->tm_mday = (_SRC)->tm_mday; \
531+
(_DST)->tm_mon = (_SRC)->tm_mon; \
532+
(_DST)->tm_year = (_SRC)->tm_year; \
533+
(_DST)->tm_wday = (_SRC)->tm_wday; \
534+
(_DST)->tm_yday = (_SRC)->tm_yday; \
535+
(_DST)->tm_gmtoff = (_SRC)->tm_gmtoff; \
536+
} while(0)
537+
538+
/* Caution: this is used to zero both pg_tm and fmt_tm structs */
507539
#defineZERO_tm(_X) \
508540
do {\
509-
(_X)->tm_sec = (_X)->tm_year = (_X)->tm_min = (_X)->tm_wday = \
510-
(_X)->tm_hour = (_X)->tm_yday = (_X)->tm_isdst = 0; \
511-
(_X)->tm_mday = (_X)->tm_mon = 1; \
512-
(_X)->tm_zone = NULL; \
541+
memset(_X, 0, sizeof(*(_X))); \
542+
(_X)->tm_mday = (_X)->tm_mon = 1; \
513543
} while(0)
514544

515545
#defineZERO_tmtc(_X) \
@@ -2649,7 +2679,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
26492679
{
26502680
FormatNode*n;
26512681
char*s;
2652-
structpg_tm*tm=&in->tm;
2682+
structfmt_tm*tm=&in->tm;
26532683
inti;
26542684

26552685
/* cache localized days and months */
@@ -2698,16 +2728,17 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
26982728
* display time as shown on a 12-hour clock, even for
26992729
* intervals
27002730
*/
2701-
sprintf(s,"%0*d",S_FM(n->suffix) ?0 : (tm->tm_hour >=0) ?2 :3,
2702-
tm->tm_hour % (HOURS_PER_DAY /2)==0 ?HOURS_PER_DAY /2 :
2703-
tm->tm_hour % (HOURS_PER_DAY /2));
2731+
sprintf(s,"%0*lld",S_FM(n->suffix) ?0 : (tm->tm_hour >=0) ?2 :3,
2732+
tm->tm_hour % (HOURS_PER_DAY /2)==0 ?
2733+
(long long) (HOURS_PER_DAY /2) :
2734+
(long long) (tm->tm_hour % (HOURS_PER_DAY /2)));
27042735
if (S_THth(n->suffix))
27052736
str_numth(s,s,S_TH_TYPE(n->suffix));
27062737
s+=strlen(s);
27072738
break;
27082739
caseDCH_HH24:
2709-
sprintf(s,"%0*d",S_FM(n->suffix) ?0 : (tm->tm_hour >=0) ?2 :3,
2710-
tm->tm_hour);
2740+
sprintf(s,"%0*lld",S_FM(n->suffix) ?0 : (tm->tm_hour >=0) ?2 :3,
2741+
(long long)tm->tm_hour);
27112742
if (S_THth(n->suffix))
27122743
str_numth(s,s,S_TH_TYPE(n->suffix));
27132744
s+=strlen(s);
@@ -2755,9 +2786,10 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
27552786
break;
27562787
#undef DCH_to_char_fsec
27572788
caseDCH_SSSS:
2758-
sprintf(s,"%d",tm->tm_hour*SECS_PER_HOUR+
2759-
tm->tm_min*SECS_PER_MINUTE+
2760-
tm->tm_sec);
2789+
sprintf(s,"%lld",
2790+
(long long) (tm->tm_hour*SECS_PER_HOUR+
2791+
tm->tm_min*SECS_PER_MINUTE+
2792+
tm->tm_sec));
27612793
if (S_THth(n->suffix))
27622794
str_numth(s,s,S_TH_TYPE(n->suffix));
27632795
s+=strlen(s);
@@ -4088,7 +4120,8 @@ timestamp_to_char(PG_FUNCTION_ARGS)
40884120
text*fmt=PG_GETARG_TEXT_PP(1),
40894121
*res;
40904122
TmToChartmtc;
4091-
structpg_tm*tm;
4123+
structpg_tmtt;
4124+
structfmt_tm*tm;
40924125
intthisdate;
40934126

40944127
if (VARSIZE_ANY_EXHDR(fmt) <=0||TIMESTAMP_NOT_FINITE(dt))
@@ -4097,10 +4130,11 @@ timestamp_to_char(PG_FUNCTION_ARGS)
40974130
ZERO_tmtc(&tmtc);
40984131
tm=tmtcTm(&tmtc);
40994132

4100-
if (timestamp2tm(dt,NULL,tm,&tmtcFsec(&tmtc),NULL,NULL)!=0)
4133+
if (timestamp2tm(dt,NULL,&tt,&tmtcFsec(&tmtc),NULL,NULL)!=0)
41014134
ereport(ERROR,
41024135
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
41034136
errmsg("timestamp out of range")));
4137+
COPY_tm(tm,&tt);
41044138

41054139
thisdate=date2j(tm->tm_year,tm->tm_mon,tm->tm_mday);
41064140
tm->tm_wday= (thisdate+1) %7;
@@ -4120,7 +4154,8 @@ timestamptz_to_char(PG_FUNCTION_ARGS)
41204154
*res;
41214155
TmToChartmtc;
41224156
inttz;
4123-
structpg_tm*tm;
4157+
structpg_tmtt;
4158+
structfmt_tm*tm;
41244159
intthisdate;
41254160

41264161
if (VARSIZE_ANY_EXHDR(fmt) <=0||TIMESTAMP_NOT_FINITE(dt))
@@ -4129,10 +4164,11 @@ timestamptz_to_char(PG_FUNCTION_ARGS)
41294164
ZERO_tmtc(&tmtc);
41304165
tm=tmtcTm(&tmtc);
41314166

4132-
if (timestamp2tm(dt,&tz,tm,&tmtcFsec(&tmtc),&tmtcTzn(&tmtc),NULL)!=0)
4167+
if (timestamp2tm(dt,&tz,&tt,&tmtcFsec(&tmtc),&tmtcTzn(&tmtc),NULL)!=0)
41334168
ereport(ERROR,
41344169
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
41354170
errmsg("timestamp out of range")));
4171+
COPY_tm(tm,&tt);
41364172

41374173
thisdate=date2j(tm->tm_year,tm->tm_mon,tm->tm_mday);
41384174
tm->tm_wday= (thisdate+1) %7;
@@ -4156,16 +4192,24 @@ interval_to_char(PG_FUNCTION_ARGS)
41564192
text*fmt=PG_GETARG_TEXT_PP(1),
41574193
*res;
41584194
TmToChartmtc;
4159-
structpg_tm*tm;
4195+
structfmt_tm*tm;
4196+
structpg_itmtt,
4197+
*itm=&tt;
41604198

41614199
if (VARSIZE_ANY_EXHDR(fmt) <=0)
41624200
PG_RETURN_NULL();
41634201

41644202
ZERO_tmtc(&tmtc);
41654203
tm=tmtcTm(&tmtc);
41664204

4167-
if (interval2tm(*it,tm,&tmtcFsec(&tmtc))!=0)
4168-
PG_RETURN_NULL();
4205+
interval2itm(*it,itm);
4206+
tmtc.fsec=itm->tm_usec;
4207+
tm->tm_sec=itm->tm_sec;
4208+
tm->tm_min=itm->tm_min;
4209+
tm->tm_hour=itm->tm_hour;
4210+
tm->tm_mday=itm->tm_mday;
4211+
tm->tm_mon=itm->tm_mon;
4212+
tm->tm_year=itm->tm_year;
41694213

41704214
/* wday is meaningless, yday approximates the total span in days */
41714215
tm->tm_yday= (tm->tm_year*MONTHS_PER_YEAR+tm->tm_mon)*DAYS_PER_MONTH+tm->tm_mday;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp