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+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
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/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

View File

@ -12,7 +12,6 @@ FROM
'02/01/17 010203 MSK',
'02/01/17 010203 MSK+0100',
'02/01/17 010203 UTC+0300',
'020117 010203 UTC+0300',
'02/01/17 010203Z',
'02/01/1970 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 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)
inline size_t findIndex(time_t t) const
/// We don't care about overflow.
inline DayNum findIndex(time_t t) const
{
/// First guess.
size_t guess = t / 86400;
if (guess >= DATE_LUT_MAX_DAY_NUM)
return 0;
if (t >= lut[guess].date && t < lut[guess + 1].date)
DayNum guess(t / 86400);
/// UTC offset is from -12 to +14 in all known time zones. This requires checking only three indices.
if ((guess == 0 || t >= lut[guess].date) && t < lut[DayNum(guess + 1)].date)
return guess;
for (size_t i = 1;; ++i)
{
if (guess + i >= DATE_LUT_MAX_DAY_NUM)
return 0;
if (t >= lut[guess + i].date && t < lut[guess + i + 1].date)
return guess + i;
if (guess < i)
return 0;
if (t >= lut[guess - i].date && t < lut[guess - i + 1].date)
return guess - 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)
return DayNum(guess + 1);
return DayNum(guess - 1);
}
inline const Values & find(time_t t) const
@ -113,8 +109,8 @@ public:
/// Round down to start of monday.
inline time_t toFirstDayOfWeek(time_t t) const
{
size_t index = findIndex(t);
return lut[index - (lut[index].day_of_week - 1)].date;
DayNum index = findIndex(t);
return lut[DayNum(index - (lut[index].day_of_week - 1))].date;
}
inline DayNum toFirstDayNumOfWeek(DayNum d) const
@ -130,7 +126,7 @@ public:
/// Round down to start of month.
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;
}
@ -147,13 +143,13 @@ public:
/// Round down to start of quarter.
inline DayNum toFirstDayNumOfQuarter(DayNum d) const
{
size_t index = d;
DayNum index = d;
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)
{
index = index - lut[index].day_of_month;
index -= lut[index].day_of_month;
--month_inside_quarter;
}
@ -188,14 +184,14 @@ public:
inline time_t toFirstDayOfNextMonth(time_t t) const
{
size_t index = findIndex(t);
DayNum index = findIndex(t);
index += 32 - lut[index].day_of_month;
return lut[index - (lut[index].day_of_month - 1)].date;
}
inline time_t toFirstDayOfPrevMonth(time_t t) const
{
size_t index = findIndex(t);
DayNum index = findIndex(t);
index -= lut[index].day_of_month;
return lut[index - (lut[index].day_of_month - 1)].date;
}
@ -213,7 +209,7 @@ public:
inline UInt8 daysInMonth(UInt16 year, UInt8 month) const
{
/// 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;
}
@ -221,12 +217,12 @@ public:
*/
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
{
size_t index = findIndex(t);
DayNum index = findIndex(t);
if (unlikely(index == 0))
return t + offset_at_start_of_epoch;
@ -241,7 +237,7 @@ public:
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),
/// 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)
*/
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 toDate(DayNum d) const { return lut[d].date; }
@ -517,7 +513,7 @@ public:
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);
index += delta;
@ -687,6 +683,4 @@ public:
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.
while (i < DATE_LUT_SIZE)
{
lut[i] = lut[0];
lut[i] = lut[DATE_LUT_MAX_DAY_NUM];
++i;
}