Merge pull request #3913 from yandex/fix-buffer-overflow-in-add-days

Fix buffer overflow in functions addDays, subtractDays
This commit is contained in:
alexey-milovidov 2018-12-24 15:47:46 +03:00 committed by GitHub
commit 1923ee9423
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 45 additions and 39 deletions

View File

@ -7,7 +7,6 @@ s a b
02/01/17 010203 MSK 2017-01-01 22:02:03 2017-01-01 22:02:03 02/01/17 010203 MSK 2017-01-01 22:02:03 2017-01-01 22:02:03
02/01/17 010203 MSK+0100 2017-01-01 21:02:03 2017-01-01 21:02:03 02/01/17 010203 MSK+0100 2017-01-01 21:02:03 2017-01-01 21:02:03
02/01/17 010203 UTC+0300 2017-01-01 22:02:03 2017-01-01 22:02:03 02/01/17 010203 UTC+0300 2017-01-01 22:02:03 2017-01-01 22:02:03
020117 010203 UTC+0300 1970-01-01 04:30:19 1970-01-01 04:30:19
02/01/17 010203Z 2017-01-02 01:02:03 2017-01-02 01:02:03 02/01/17 010203Z 2017-01-02 01:02:03 2017-01-02 01:02:03
02/01/1970 010203Z 1970-01-02 01:02:03 1970-01-02 01:02:03 02/01/1970 010203Z 1970-01-02 01:02:03 1970-01-02 01:02:03
02/01/70 010203Z 1970-01-02 01:02:03 1970-01-02 01:02:03 02/01/70 010203Z 1970-01-02 01:02:03 1970-01-02 01:02:03

View File

@ -12,7 +12,6 @@ FROM
'02/01/17 010203 MSK', '02/01/17 010203 MSK',
'02/01/17 010203 MSK+0100', '02/01/17 010203 MSK+0100',
'02/01/17 010203 UTC+0300', '02/01/17 010203 UTC+0300',
'020117 010203 UTC+0300',
'02/01/17 010203Z', '02/01/17 010203Z',
'02/01/1970 010203Z', '02/01/1970 010203Z',
'02/01/70 010203Z', '02/01/70 010203Z',

View File

@ -0,0 +1,6 @@
0
0
0
0
0
0

View File

@ -0,0 +1,12 @@
SELECT ignore(addDays(toDateTime(0), -1));
SELECT ignore(subtractDays(toDateTime(0), 1));
SELECT ignore(addDays(toDate(0), -1));
SELECT ignore(subtractDays(toDate(0), 1));
SET send_logs_level = 'none';
SELECT ignore(addDays((CAST((96.338) AS DateTime)), -3));
SELECT ignore(subtractDays((CAST((-5263074.47) AS DateTime)), -737895));
SELECT quantileDeterministic([], findClusterIndex(( SELECT subtractDays((CAST((566450.398706) AS DateTime)), 54) ) )), '\0', []; -- { serverError 42 }
SELECT sequenceCount((CAST((( SELECT NULL ) AS rg, ( SELECT ( SELECT [], '<e', caseWithExpr([NULL], -588755.149, []), retention(addWeeks((CAST((-7644612.39732) AS DateTime)), -23578040.02833), (CAST(([]) AS DateTime)), (CAST(([010977.08]) AS String))), emptyArrayToSingle('') ) , '\0', toUInt64([], 't3hw@'), '\0', toStartOfQuarter(-4230.1872, []) ) ) AS Date))); -- { serverError 43 }

View File

@ -1,6 +1,2 @@
SELECT sequenceCount((CAST((( SELECT NULL ) AS rg, ( SELECT ( SELECT [], '<e', caseWithExpr([NULL], -588755.149, []), retention(addWeeks((CAST((-7644612.39732) AS DateTime)), -23578040.02833), (CAST(([]) AS DateTime)), (CAST(([010977.08]) AS String))), emptyArrayToSingle('') ) , '\0', toUInt64([], 't3hw@'), '\0', toStartOfQuarter(-4230.1872, []) ) ) AS Date)));
SELECT ( SELECT toDecimal128([], rowNumberInBlock()) ) , lcm('', [[(CAST(('>A') AS String))]]); SELECT ( SELECT toDecimal128([], rowNumberInBlock()) ) , lcm('', [[(CAST(('>A') AS String))]]);
SELECT truncate(895, -16); SELECT truncate(895, -16);
SELECT subtractDays((CAST((-5263074.47) AS DateTime)), -737895);
SELECT quantileDeterministic([], findClusterIndex(( SELECT subtractDays((CAST((566450.398706) AS DateTime)), 54) ) )), '\0', [];
SELECT addDays((CAST((96.338) AS DateTime)), -3);

View File

@ -71,26 +71,22 @@ private:
/// We can correctly process only timestamps that less DATE_LUT_MAX (i.e. up to 2105 year inclusively) /// We can correctly process only timestamps that less DATE_LUT_MAX (i.e. up to 2105 year inclusively)
inline size_t findIndex(time_t t) const /// We don't care about overflow.
inline DayNum findIndex(time_t t) const
{ {
/// First guess. /// First guess.
size_t guess = t / 86400; DayNum guess(t / 86400);
if (guess >= DATE_LUT_MAX_DAY_NUM)
return 0; /// UTC offset is from -12 to +14 in all known time zones. This requires checking only three indices.
if (t >= lut[guess].date && t < lut[guess + 1].date)
if ((guess == 0 || t >= lut[guess].date) && t < lut[DayNum(guess + 1)].date)
return guess; return guess;
for (size_t i = 1;; ++i) /// Time zones that have offset 0 from UTC do daylight saving time change (if any) towards increasing UTC offset (example: British Standard Time).
{ if (offset_at_start_of_epoch >= 0)
if (guess + i >= DATE_LUT_MAX_DAY_NUM) return DayNum(guess + 1);
return 0;
if (t >= lut[guess + i].date && t < lut[guess + i + 1].date) return DayNum(guess - 1);
return guess + i;
if (guess < i)
return 0;
if (t >= lut[guess - i].date && t < lut[guess - i + 1].date)
return guess - i;
}
} }
inline const Values & find(time_t t) const inline const Values & find(time_t t) const
@ -113,8 +109,8 @@ public:
/// Round down to start of monday. /// Round down to start of monday.
inline time_t toFirstDayOfWeek(time_t t) const inline time_t toFirstDayOfWeek(time_t t) const
{ {
size_t index = findIndex(t); DayNum index = findIndex(t);
return lut[index - (lut[index].day_of_week - 1)].date; return lut[DayNum(index - (lut[index].day_of_week - 1))].date;
} }
inline DayNum toFirstDayNumOfWeek(DayNum d) const inline DayNum toFirstDayNumOfWeek(DayNum d) const
@ -130,7 +126,7 @@ public:
/// Round down to start of month. /// Round down to start of month.
inline time_t toFirstDayOfMonth(time_t t) const inline time_t toFirstDayOfMonth(time_t t) const
{ {
size_t index = findIndex(t); DayNum index = findIndex(t);
return lut[index - (lut[index].day_of_month - 1)].date; return lut[index - (lut[index].day_of_month - 1)].date;
} }
@ -147,13 +143,13 @@ public:
/// Round down to start of quarter. /// Round down to start of quarter.
inline DayNum toFirstDayNumOfQuarter(DayNum d) const inline DayNum toFirstDayNumOfQuarter(DayNum d) const
{ {
size_t index = d; DayNum index = d;
size_t month_inside_quarter = (lut[index].month - 1) % 3; size_t month_inside_quarter = (lut[index].month - 1) % 3;
index = index - lut[index].day_of_month; index -= lut[index].day_of_month;
while (month_inside_quarter) while (month_inside_quarter)
{ {
index = index - lut[index].day_of_month; index -= lut[index].day_of_month;
--month_inside_quarter; --month_inside_quarter;
} }
@ -188,14 +184,14 @@ public:
inline time_t toFirstDayOfNextMonth(time_t t) const inline time_t toFirstDayOfNextMonth(time_t t) const
{ {
size_t index = findIndex(t); DayNum index = findIndex(t);
index += 32 - lut[index].day_of_month; index += 32 - lut[index].day_of_month;
return lut[index - (lut[index].day_of_month - 1)].date; return lut[index - (lut[index].day_of_month - 1)].date;
} }
inline time_t toFirstDayOfPrevMonth(time_t t) const inline time_t toFirstDayOfPrevMonth(time_t t) const
{ {
size_t index = findIndex(t); DayNum index = findIndex(t);
index -= lut[index].day_of_month; index -= lut[index].day_of_month;
return lut[index - (lut[index].day_of_month - 1)].date; return lut[index - (lut[index].day_of_month - 1)].date;
} }
@ -213,7 +209,7 @@ public:
inline UInt8 daysInMonth(UInt16 year, UInt8 month) const inline UInt8 daysInMonth(UInt16 year, UInt8 month) const
{ {
/// 32 makes arithmetic more simple. /// 32 makes arithmetic more simple.
auto any_day_of_month = years_lut[year - DATE_LUT_MIN_YEAR] + 32 * (month - 1); DayNum any_day_of_month = DayNum(years_lut[year - DATE_LUT_MIN_YEAR] + 32 * (month - 1));
return lut[any_day_of_month].days_in_month; return lut[any_day_of_month].days_in_month;
} }
@ -221,12 +217,12 @@ public:
*/ */
inline time_t toDateAndShift(time_t t, Int32 days) const inline time_t toDateAndShift(time_t t, Int32 days) const
{ {
return lut[findIndex(t) + days].date; return lut[DayNum(findIndex(t) + days)].date;
} }
inline time_t toTime(time_t t) const inline time_t toTime(time_t t) const
{ {
size_t index = findIndex(t); DayNum index = findIndex(t);
if (unlikely(index == 0)) if (unlikely(index == 0))
return t + offset_at_start_of_epoch; return t + offset_at_start_of_epoch;
@ -241,7 +237,7 @@ public:
inline unsigned toHour(time_t t) const inline unsigned toHour(time_t t) const
{ {
size_t index = findIndex(t); DayNum index = findIndex(t);
/// If it is not 1970 year (findIndex found nothing appropriate), /// If it is not 1970 year (findIndex found nothing appropriate),
/// than limit number of hours to avoid insane results like 1970-01-01 89:28:15 /// than limit number of hours to avoid insane results like 1970-01-01 89:28:15
@ -301,7 +297,7 @@ public:
* because the same calendar day starts/ends at different timestamps in different time zones) * because the same calendar day starts/ends at different timestamps in different time zones)
*/ */
inline DayNum toDayNum(time_t t) const { return static_cast<DayNum>(findIndex(t)); } inline DayNum toDayNum(time_t t) const { return findIndex(t); }
inline time_t fromDayNum(DayNum d) const { return lut[d].date; } inline time_t fromDayNum(DayNum d) const { return lut[d].date; }
inline time_t toDate(DayNum d) const { return lut[d].date; } inline time_t toDate(DayNum d) const { return lut[d].date; }
@ -517,7 +513,7 @@ public:
inline time_t addDays(time_t t, Int64 delta) const inline time_t addDays(time_t t, Int64 delta) const
{ {
size_t index = findIndex(t); DayNum index = findIndex(t);
time_t time_offset = toHour(t) * 3600 + toMinute(t) * 60 + toSecond(t); time_t time_offset = toHour(t) * 3600 + toMinute(t) * 60 + toSecond(t);
index += delta; index += delta;
@ -687,6 +683,4 @@ public:
return s; return s;
} }
inline bool isOffsetWholeNumberOfHoursEveryTime() const { return offset_is_whole_number_of_hours_everytime; }
}; };

View File

@ -129,7 +129,7 @@ DateLUTImpl::DateLUTImpl(const std::string & time_zone_)
/// Fill excessive part of lookup table. This is needed only to simplify handling of overflow cases. /// Fill excessive part of lookup table. This is needed only to simplify handling of overflow cases.
while (i < DATE_LUT_SIZE) while (i < DATE_LUT_SIZE)
{ {
lut[i] = lut[0]; lut[i] = lut[DATE_LUT_MAX_DAY_NUM];
++i; ++i;
} }