Commit 5109d540 authored by Luis Soares's avatar Luis Soares

BUG#38718: slave sql thread crashes when reading relay log

      
Suprisingly, a Slave_log_event would show up in the binary
log. This event is never used and should not appear in the
logs. As such, when the slave (or the mysqlbinlog tool) reads the
event, it will hit an invalid pointer (reference to the
descriptor event when deserializing the Slave_log_event was
purposodely set to NULL).
      
The presence of the Slave_log_event denotes a corrupted log, but
we cannot tell how the log got corrupted in the first
place. However, we can make the server cope with such events when
it reads them - in case of log corruption - and fail gracefully.
     
This patch makes the server/mysqlbinlog to report that it has
found an invalid log event when Slave_log_event is read.
parent 58995280
...@@ -1225,7 +1225,7 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len, ...@@ -1225,7 +1225,7 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len,
break; break;
#ifdef HAVE_REPLICATION #ifdef HAVE_REPLICATION
case SLAVE_EVENT: /* can never happen (unused event) */ case SLAVE_EVENT: /* can never happen (unused event) */
ev = new Slave_log_event(buf, event_len); ev = new Slave_log_event(buf, event_len, description_event);
break; break;
#endif /* HAVE_REPLICATION */ #endif /* HAVE_REPLICATION */
case CREATE_FILE_EVENT: case CREATE_FILE_EVENT:
...@@ -1313,8 +1313,10 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len, ...@@ -1313,8 +1313,10 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len,
(because constructor is "void") ; so instead we leave the pointer we (because constructor is "void") ; so instead we leave the pointer we
wanted to allocate (e.g. 'query') to 0 and we test it in is_valid(). wanted to allocate (e.g. 'query') to 0 and we test it in is_valid().
Same for Format_description_log_event, member 'post_header_len'. Same for Format_description_log_event, member 'post_header_len'.
SLAVE_EVENT is never used, so it should not be read ever.
*/ */
if (!ev || !ev->is_valid()) if (!ev || !ev->is_valid() || (event_type == SLAVE_EVENT))
{ {
DBUG_PRINT("error",("Found invalid event in binary log")); DBUG_PRINT("error",("Found invalid event in binary log"));
...@@ -5978,8 +5980,12 @@ void Slave_log_event::init_from_mem_pool(int data_size) ...@@ -5978,8 +5980,12 @@ void Slave_log_event::init_from_mem_pool(int data_size)
/** This code is not used, so has not been updated to be format-tolerant. */ /** This code is not used, so has not been updated to be format-tolerant. */
Slave_log_event::Slave_log_event(const char* buf, uint event_len) /* We are using description_event so that slave does not crash on Log_event
:Log_event(buf,0) /*unused event*/ ,mem_pool(0),master_host(0) constructor */
Slave_log_event::Slave_log_event(const char* buf,
uint event_len,
const Format_description_log_event* description_event)
:Log_event(buf,description_event),mem_pool(0),master_host(0)
{ {
if (event_len < LOG_EVENT_HEADER_LEN) if (event_len < LOG_EVENT_HEADER_LEN)
return; return;
......
...@@ -1782,7 +1782,9 @@ class Slave_log_event: public Log_event ...@@ -1782,7 +1782,9 @@ class Slave_log_event: public Log_event
void print(FILE* file, PRINT_EVENT_INFO* print_event_info); void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
#endif #endif
Slave_log_event(const char* buf, uint event_len); Slave_log_event(const char* buf,
uint event_len,
const Format_description_log_event *description_event);
~Slave_log_event(); ~Slave_log_event();
int get_data_size(); int get_data_size();
bool is_valid() const { return master_host != 0; } bool is_valid() const { return master_host != 0; }
......
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