Commit 35ce2b91 authored by unknown's avatar unknown

Bug#28641 CREATE EVENT with '2038.01.18 03:00:00' let server crash.

Creating an EVENT to be executed at a time close to the end of the allowed
range (2038.01.19 03:14:07 UTC) would cause the server to crash. The
expected behavior is to accept all calendar times within the interval and
reject all other values without crashing.

This patch replaces the function 'sec_to_epoch_TIME' with a Time_zone API call.
This function was broken because it invoked the internal function 'sec_to_epoch'
without respecting the restrictions on the function parameters (and this caused
assertion failure). It also was used as a reverse function to
Time_zone_utc::gmt_sec_to_TIME which it isn't.


mysql-test/r/events_bugs.result:
  Added test case
mysql-test/t/events_bugs.test:
  Added test case
sql/event_data_objects.cc:
  Replaced function 'sec_since_epoch_TIME' since it was implemented as
  a wrapper around 'sec_since_epoch' without taking parameter restrictions
  into account. The function was used to load information about event
  execution time from mysql.events table. Further more, the function wasn't
  the inverse function of Time_zone_utc::gmt_sec_to_TIME() which was used
  by events code to store information about event execution time.
sql/event_db_repository.cc:
  Replaced my_tz_UTC object with my_tz_OFFSET0 object because the first one
  doesn't supply us with a bijective MYSQL_TIME<->my_time_t translation. Instead
  the function sec_since_epoch_TIME was used as a reverse function to the method
  my_tz_UTC::gmt_sec_to_TIME.
sql/event_queue.cc:
  Replaced my_tz_UTC object with my_tz_OFFSET0 object because the first one
  doesn't supply us with a bijective MYSQL_TIME<->my_time_t translation. Instead
  the function sec_since_epoch_TIME was used as a reverse function to the method
  my_tz_UTC::gmt_sec_to_TIME.
sql/tztime.cc:
  * Remove function 'sec_since_epoch_TIME' since it was implemented as
  a wrapper around 'sec_since_epoch' without taking parameter restrictions
  into account. The function was used to load information about event
  execution time from mysql.events table. Further more, the function wasn't
  the inverse function of Time_zone_utc::gmt_sec_to_TIME() which was used
  by events code to store information about event execution time.
  
  * Added static Time_zone object for UTC+0 time zone.
sql/tztime.h:
  Include extern pointer to static Time_zone object.
parent 0b03233e
...@@ -611,3 +611,10 @@ id ev_nm ev_cnt ...@@ -611,3 +611,10 @@ id ev_nm ev_cnt
DROP TABLE event_log; DROP TABLE event_log;
SET GLOBAL event_scheduler = OFF; SET GLOBAL event_scheduler = OFF;
DROP DATABASE events_test; DROP DATABASE events_test;
SET GLOBAL event_scheduler= ON;
CREATE EVENT bug28641 ON SCHEDULE AT '2038.01.18 03:00:00'
DO BEGIN
SELECT 1;
END;|
SET GLOBAL event_scheduler= OFF;
DROP EVENT bug28641;
...@@ -722,3 +722,18 @@ let $wait_condition= ...@@ -722,3 +722,18 @@ let $wait_condition=
--source include/wait_condition.inc --source include/wait_condition.inc
DROP DATABASE events_test; DROP DATABASE events_test;
#
# Bug#28641 CREATE EVENT with '2038.01.18 03:00:00' let server crash.
#
SET GLOBAL event_scheduler= ON;
DELIMITER |;
CREATE EVENT bug28641 ON SCHEDULE AT '2038.01.18 03:00:00'
DO BEGIN
SELECT 1;
END;|
DELIMITER ;|
SET GLOBAL event_scheduler= OFF;
DROP EVENT bug28641;
...@@ -979,17 +979,18 @@ Event_queue_element::load_from_row(THD *thd, TABLE *table) ...@@ -979,17 +979,18 @@ Event_queue_element::load_from_row(THD *thd, TABLE *table)
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
starts_null= table->field[ET_FIELD_STARTS]->is_null(); starts_null= table->field[ET_FIELD_STARTS]->is_null();
my_bool not_used= FALSE;
if (!starts_null) if (!starts_null)
{ {
table->field[ET_FIELD_STARTS]->get_date(&time, TIME_NO_ZERO_DATE); table->field[ET_FIELD_STARTS]->get_date(&time, TIME_NO_ZERO_DATE);
starts= sec_since_epoch_TIME(&time); starts= my_tz_OFFSET0->TIME_to_gmt_sec(&time,&not_used);
} }
ends_null= table->field[ET_FIELD_ENDS]->is_null(); ends_null= table->field[ET_FIELD_ENDS]->is_null();
if (!ends_null) if (!ends_null)
{ {
table->field[ET_FIELD_ENDS]->get_date(&time, TIME_NO_ZERO_DATE); table->field[ET_FIELD_ENDS]->get_date(&time, TIME_NO_ZERO_DATE);
ends= sec_since_epoch_TIME(&time); ends= my_tz_OFFSET0->TIME_to_gmt_sec(&time,&not_used);
} }
if (!table->field[ET_FIELD_INTERVAL_EXPR]->is_null()) if (!table->field[ET_FIELD_INTERVAL_EXPR]->is_null())
...@@ -1007,7 +1008,7 @@ Event_queue_element::load_from_row(THD *thd, TABLE *table) ...@@ -1007,7 +1008,7 @@ Event_queue_element::load_from_row(THD *thd, TABLE *table)
if (table->field[ET_FIELD_EXECUTE_AT]->get_date(&time, if (table->field[ET_FIELD_EXECUTE_AT]->get_date(&time,
TIME_NO_ZERO_DATE)) TIME_NO_ZERO_DATE))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
execute_at= sec_since_epoch_TIME(&time); execute_at= my_tz_OFFSET0->TIME_to_gmt_sec(&time,&not_used);
} }
/* /*
...@@ -1039,7 +1040,7 @@ Event_queue_element::load_from_row(THD *thd, TABLE *table) ...@@ -1039,7 +1040,7 @@ Event_queue_element::load_from_row(THD *thd, TABLE *table)
{ {
table->field[ET_FIELD_LAST_EXECUTED]->get_date(&time, table->field[ET_FIELD_LAST_EXECUTED]->get_date(&time,
TIME_NO_ZERO_DATE); TIME_NO_ZERO_DATE);
last_executed= sec_since_epoch_TIME(&time); last_executed= my_tz_OFFSET0->TIME_to_gmt_sec(&time,&not_used);
} }
last_executed_changed= FALSE; last_executed_changed= FALSE;
......
...@@ -250,7 +250,7 @@ mysql_event_fill_row(THD *thd, ...@@ -250,7 +250,7 @@ mysql_event_fill_row(THD *thd,
if (!et->starts_null) if (!et->starts_null)
{ {
MYSQL_TIME time; MYSQL_TIME time;
my_tz_UTC->gmt_sec_to_TIME(&time, et->starts); my_tz_OFFSET0->gmt_sec_to_TIME(&time, et->starts);
fields[ET_FIELD_STARTS]->set_notnull(); fields[ET_FIELD_STARTS]->set_notnull();
fields[ET_FIELD_STARTS]->store_time(&time, MYSQL_TIMESTAMP_DATETIME); fields[ET_FIELD_STARTS]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
...@@ -259,7 +259,7 @@ mysql_event_fill_row(THD *thd, ...@@ -259,7 +259,7 @@ mysql_event_fill_row(THD *thd,
if (!et->ends_null) if (!et->ends_null)
{ {
MYSQL_TIME time; MYSQL_TIME time;
my_tz_UTC->gmt_sec_to_TIME(&time, et->ends); my_tz_OFFSET0->gmt_sec_to_TIME(&time, et->ends);
fields[ET_FIELD_ENDS]->set_notnull(); fields[ET_FIELD_ENDS]->set_notnull();
fields[ET_FIELD_ENDS]->store_time(&time, MYSQL_TIMESTAMP_DATETIME); fields[ET_FIELD_ENDS]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
...@@ -278,7 +278,7 @@ mysql_event_fill_row(THD *thd, ...@@ -278,7 +278,7 @@ mysql_event_fill_row(THD *thd,
fields[ET_FIELD_ENDS]->set_null(); fields[ET_FIELD_ENDS]->set_null();
MYSQL_TIME time; MYSQL_TIME time;
my_tz_UTC->gmt_sec_to_TIME(&time, et->execute_at); my_tz_OFFSET0->gmt_sec_to_TIME(&time, et->execute_at);
fields[ET_FIELD_EXECUTE_AT]->set_notnull(); fields[ET_FIELD_EXECUTE_AT]->set_notnull();
fields[ET_FIELD_EXECUTE_AT]-> fields[ET_FIELD_EXECUTE_AT]->
...@@ -1004,7 +1004,7 @@ update_timing_fields_for_event(THD *thd, ...@@ -1004,7 +1004,7 @@ update_timing_fields_for_event(THD *thd,
if (update_last_executed) if (update_last_executed)
{ {
MYSQL_TIME time; MYSQL_TIME time;
my_tz_UTC->gmt_sec_to_TIME(&time, last_executed); my_tz_OFFSET0->gmt_sec_to_TIME(&time, last_executed);
fields[ET_FIELD_LAST_EXECUTED]->set_notnull(); fields[ET_FIELD_LAST_EXECUTED]->set_notnull();
fields[ET_FIELD_LAST_EXECUTED]->store_time(&time, fields[ET_FIELD_LAST_EXECUTED]->store_time(&time,
......
...@@ -740,7 +740,7 @@ Event_queue::dump_internal_status() ...@@ -740,7 +740,7 @@ Event_queue::dump_internal_status()
printf("WOC : %s\n", waiting_on_cond? "YES":"NO"); printf("WOC : %s\n", waiting_on_cond? "YES":"NO");
MYSQL_TIME time; MYSQL_TIME time;
my_tz_UTC->gmt_sec_to_TIME(&time, next_activation_at); my_tz_OFFSET0->gmt_sec_to_TIME(&time, next_activation_at);
if (time.year != 1970) if (time.year != 1970)
printf("Next activation : %04d-%02d-%02d %02d:%02d:%02d\n", printf("Next activation : %04d-%02d-%02d %02d:%02d:%02d\n",
time.year, time.month, time.day, time.hour, time.minute, time.second); time.year, time.month, time.day, time.hour, time.minute, time.second);
......
...@@ -807,19 +807,6 @@ sec_since_epoch(int year, int mon, int mday, int hour, int min ,int sec) ...@@ -807,19 +807,6 @@ sec_since_epoch(int year, int mon, int mday, int hour, int min ,int sec)
SECS_PER_MIN + sec; SECS_PER_MIN + sec;
} }
/*
Works like sec_since_epoch but expects MYSQL_TIME structure as parameter.
*/
my_time_t
sec_since_epoch_TIME(MYSQL_TIME *t)
{
return sec_since_epoch(t->year, t->month, t->day,
t->hour, t->minute, t->second);
}
/* /*
Converts local time in broken down MYSQL_TIME representation to my_time_t Converts local time in broken down MYSQL_TIME representation to my_time_t
representation. representation.
...@@ -1425,7 +1412,9 @@ Time_zone_offset::get_name() const ...@@ -1425,7 +1412,9 @@ Time_zone_offset::get_name() const
static Time_zone_utc tz_UTC; static Time_zone_utc tz_UTC;
static Time_zone_system tz_SYSTEM; static Time_zone_system tz_SYSTEM;
static Time_zone_offset tz_OFFSET0(0);
Time_zone *my_tz_OFFSET0= &tz_OFFSET0;
Time_zone *my_tz_UTC= &tz_UTC; Time_zone *my_tz_UTC= &tz_UTC;
Time_zone *my_tz_SYSTEM= &tz_SYSTEM; Time_zone *my_tz_SYSTEM= &tz_SYSTEM;
......
...@@ -59,6 +59,7 @@ class Time_zone: public Sql_alloc ...@@ -59,6 +59,7 @@ class Time_zone: public Sql_alloc
extern Time_zone * my_tz_UTC; extern Time_zone * my_tz_UTC;
extern Time_zone * my_tz_SYSTEM; extern Time_zone * my_tz_SYSTEM;
extern Time_zone * my_tz_OFFSET0;
extern Time_zone * my_tz_find(THD *thd, const String *name); extern Time_zone * my_tz_find(THD *thd, const String *name);
extern my_bool my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap); extern my_bool my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap);
extern void my_tz_free(); extern void my_tz_free();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment