diff options
-rw-r--r-- | sql/field.h | 14 | ||||
-rw-r--r-- | sql/log_event.cc | 9 | ||||
-rw-r--r-- | sql/log_event.h | 8 | ||||
-rw-r--r-- | sql/log_event_old.h | 6 | ||||
-rw-r--r-- | sql/rpl_record.cc | 27 | ||||
-rw-r--r-- | sql/rpl_record.h | 5 | ||||
-rw-r--r-- | sql/rpl_utility.cc | 17 |
7 files changed, 41 insertions, 45 deletions
diff --git a/sql/field.h b/sql/field.h index d9f0b892adb..6a181b7ae91 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1,7 +1,7 @@ #ifndef FIELD_INCLUDED #define FIELD_INCLUDED -/* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1802,18 +1802,6 @@ public: { store_length(ptr, packlength, number); } - - /** - Return the packed length plus the length of the data. - - This is used to determine the size of the data plus the - packed length portion in the row data. - - @returns The length in the row plus the size of the data. - */ - uint32 get_packed_size(const uchar *ptr_arg, bool low_byte_first) - {return packlength + get_length(ptr_arg, packlength, low_byte_first);} - inline uint32 get_length(uint row_offset= 0) { return get_length(ptr+row_offset, this->packlength, table->s->db_low_byte_first); } uint32 get_length(const uchar *ptr, uint packlength, bool low_byte_first); diff --git a/sql/log_event.cc b/sql/log_event.cc index 7d18b447084..122953b48ec 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -18,6 +18,7 @@ #ifdef MYSQL_CLIENT #include "sql_priv.h" +#include "mysqld_error.h" #else @@ -1945,6 +1946,14 @@ Rows_log_event::print_verbose_one_row(IO_CACHE *file, table_def *td, else { my_b_printf(file, "### @%d=", i + 1); + size_t fsize= td->calc_field_size((uint)i, (uchar*) value); + if (value + fsize > m_rows_end) + { + my_b_printf(file, "***Corrupted replication event was detected." + " Not printing the value***\n"); + value+= fsize; + return 0; + } size_t size= log_event_print_value(file, value, td->type(i), td->field_metadata(i), typestr, sizeof(typestr)); diff --git a/sql/log_event.h b/sql/log_event.h index fa17b32bef2..460d7244d07 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -3732,12 +3732,8 @@ protected: DBUG_ASSERT(m_table); ASSERT_OR_RETURN_ERROR(m_curr_row < m_rows_end, HA_ERR_CORRUPT_EVENT); - int const result= ::unpack_row(rli, m_table, m_width, m_curr_row, &m_cols, - &m_curr_row_end, &m_master_reclength); - if (m_curr_row_end > m_rows_end) - my_error(ER_SLAVE_CORRUPT_EVENT, MYF(0)); - ASSERT_OR_RETURN_ERROR(m_curr_row_end <= m_rows_end, HA_ERR_CORRUPT_EVENT); - return result; + return ::unpack_row(rli, m_table, m_width, m_curr_row, &m_cols, + &m_curr_row_end, &m_master_reclength, m_rows_end); } #endif diff --git a/sql/log_event_old.h b/sql/log_event_old.h index ab8196c0979..04678ffff84 100644 --- a/sql/log_event_old.h +++ b/sql/log_event_old.h @@ -203,10 +203,8 @@ protected: { DBUG_ASSERT(m_table); ASSERT_OR_RETURN_ERROR(m_curr_row < m_rows_end, HA_ERR_CORRUPT_EVENT); - int const result= ::unpack_row(rli, m_table, m_width, m_curr_row, &m_cols, - &m_curr_row_end, &m_master_reclength); - ASSERT_OR_RETURN_ERROR(m_curr_row_end <= m_rows_end, HA_ERR_CORRUPT_EVENT); - return result; + return ::unpack_row(rli, m_table, m_width, m_curr_row, &m_cols, + &m_curr_row_end, &m_master_reclength, m_rows_end); } #endif diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc index fc123acb104..347915405d9 100644 --- a/sql/rpl_record.cc +++ b/sql/rpl_record.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -169,11 +169,15 @@ pack_row(TABLE *table, MY_BITMAP const* cols, @param row_data Packed row data @param cols Pointer to bitset describing columns to fill in - @param row_end Pointer to variable that will hold the value of the - one-after-end position for the row + @param curr_row_end + Pointer to variable that will hold the value of the + one-after-end position for the current row @param master_reclength Pointer to variable that will be set to the length of the record on the master side + @param row_end + Pointer to variable that will hold the value of the + end position for the data in the row event @retval 0 No error @@ -185,7 +189,8 @@ int unpack_row(Relay_log_info const *rli, TABLE *table, uint const colcnt, uchar const *const row_data, MY_BITMAP const *cols, - uchar const **const row_end, ulong *const master_reclength) + uchar const **const current_row_end, ulong *const master_reclength, + uchar const *const row_end) { DBUG_ENTER("unpack_row"); DBUG_ASSERT(row_data); @@ -303,6 +308,13 @@ unpack_row(Relay_log_info const *rli, #ifndef DBUG_OFF uchar const *const old_pack_ptr= pack_ptr; #endif + uint32 len= tabledef->calc_field_size(i, (uchar *) pack_ptr); + if ( pack_ptr + len > row_end ) + { + pack_ptr+= len; + my_error(ER_SLAVE_CORRUPT_EVENT, MYF(0)); + DBUG_RETURN(ER_SLAVE_CORRUPT_EVENT); + } pack_ptr= f->unpack(f->ptr, pack_ptr, metadata, TRUE); DBUG_PRINT("debug", ("field: %s; metadata: 0x%x;" " pack_ptr: 0x%lx; pack_ptr': 0x%lx; bytes: %d", @@ -369,6 +381,11 @@ unpack_row(Relay_log_info const *rli, uint32 len= tabledef->calc_field_size(i, (uchar *) pack_ptr); DBUG_DUMP("field_data", pack_ptr, len); pack_ptr+= len; + if ( pack_ptr > row_end ) + { + my_error(ER_SLAVE_CORRUPT_EVENT, MYF(0)); + DBUG_RETURN(ER_SLAVE_CORRUPT_EVENT); + } } null_mask <<= 1; } @@ -382,7 +399,7 @@ unpack_row(Relay_log_info const *rli, DBUG_DUMP("row_data", row_data, pack_ptr - row_data); - *row_end = pack_ptr; + *current_row_end = pack_ptr; if (master_reclength) { if (*field_ptr) diff --git a/sql/rpl_record.h b/sql/rpl_record.h index e7d80960fe4..df3e6873af2 100644 --- a/sql/rpl_record.h +++ b/sql/rpl_record.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -32,7 +32,8 @@ size_t pack_row(TABLE* table, MY_BITMAP const* cols, int unpack_row(Relay_log_info const *rli, TABLE *table, uint const colcnt, uchar const *const row_data, MY_BITMAP const *cols, - uchar const **const row_end, ulong *const master_reclength); + uchar const **const curr_row_end, ulong *const master_reclength, + uchar const *const row_end); // Fill table's record[0] with default values. int prepare_record(TABLE *const table, const uint skip, const bool check); diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc index 1527676ee58..16db07af4c2 100644 --- a/sql/rpl_utility.cc +++ b/sql/rpl_utility.cc @@ -186,7 +186,7 @@ int compare_lengths(Field *field, enum_field_types source_type, uint16 metadata) DBUG_PRINT("result", ("%d", result)); DBUG_RETURN(result); } - +#endif //MYSQL_CLIENT /********************************************************************* * table_def member definitions * *********************************************************************/ @@ -285,7 +285,6 @@ uint32 table_def::calc_field_size(uint col, uchar *master_data) const case MYSQL_TYPE_VARCHAR: { length= m_field_metadata[col] > 255 ? 2 : 1; // c&p of Field_varstring::data_length() - DBUG_ASSERT(uint2korr(master_data) > 0); length+= length == 1 ? (uint32) *master_data : uint2korr(master_data); break; } @@ -295,17 +294,6 @@ uint32 table_def::calc_field_size(uint col, uchar *master_data) const case MYSQL_TYPE_BLOB: case MYSQL_TYPE_GEOMETRY: { -#if 1 - /* - BUG#29549: - This is currently broken for NDB, which is using big-endian - order when packing length of BLOB. Once they have decided how to - fix the issue, we can enable the code below to make sure to - always read the length in little-endian order. - */ - Field_blob fb(m_field_metadata[col]); - length= fb.get_packed_size(master_data, TRUE); -#else /* Compute the length of the data. We cannot use get_length() here since it is dependent on the specific table (and also checks the @@ -331,7 +319,6 @@ uint32 table_def::calc_field_size(uint col, uchar *master_data) const } length+= m_field_metadata[col]; -#endif break; } default: @@ -340,7 +327,7 @@ uint32 table_def::calc_field_size(uint col, uchar *master_data) const return length; } - +#ifndef MYSQL_CLIENT /** */ void show_sql_type(enum_field_types type, uint16 metadata, String *str, CHARSET_INFO *field_cs) |