diff --git a/mysql-test/r/archive.result b/mysql-test/r/archive.result index 0ec84efa842..f2cdf2adfca 100644 --- a/mysql-test/r/archive.result +++ b/mysql-test/r/archive.result @@ -12801,3 +12801,14 @@ OPTIMIZE TABLE t1; Table Op Msg_type Msg_text test.t1 optimize status OK DROP TABLE t1; +# +# BUG#917689 Using wrong archive table causes crash +# +create table t1 (a int, b char(50)) engine=archive; +select * from t1; +ERROR HY000: Table 't1' is marked as crashed and should be repaired +show warnings; +Level Code Message +Error 127 Got error 127 when reading table `test`.`t1` +Error 1194 Table 't1' is marked as crashed and should be repaired +drop table t1; diff --git a/mysql-test/std_data/t917689.ARZ b/mysql-test/std_data/t917689.ARZ new file mode 100644 index 00000000000..4770ca0c257 Binary files /dev/null and b/mysql-test/std_data/t917689.ARZ differ diff --git a/mysql-test/t/archive.test b/mysql-test/t/archive.test index 6f788fc3cc6..0f274b6225d 100644 --- a/mysql-test/t/archive.test +++ b/mysql-test/t/archive.test @@ -1727,3 +1727,14 @@ CHECKSUM TABLE t1 EXTENDED; FLUSH TABLE t1; OPTIMIZE TABLE t1; DROP TABLE t1; + +--echo # +--echo # BUG#917689 Using wrong archive table causes crash +--echo # +create table t1 (a int, b char(50)) engine=archive; +--remove_file $MYSQLD_DATADIR/test/t1.ARZ +copy_file std_data/t917689.ARZ $MYSQLD_DATADIR/test/t1.ARZ; +--error 1194 +select * from t1; +show warnings; +drop table t1; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index fa1572e561f..c7bfa42da95 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -194,12 +194,15 @@ begin insert into test.t1 values (x, z); end| +let $start_value= `SELECT @@max_join_size`| call mixset("mixset", 19)| show variables like 'max_join_size'| select id,data,@z from t1| delete from t1| drop procedure mixset| - +--disable_query_log +eval SET @@max_join_size= $start_value| +--enable_query_log # Multiple CALL statements, one with OUT parameter. --disable_warnings diff --git a/sql/field.cc b/sql/field.cc index 934816ba381..aeaf1a7a21e 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1472,11 +1472,13 @@ Field::pack(uchar *to, const uchar *from, uint max_length) data @return New pointer into memory based on from + length of the data + @return 0 if wrong data */ const uchar * -Field::unpack(uchar* to, const uchar *from, uint param_data) +Field::unpack(uchar* to, const uchar *from, const uchar *from_end, + uint param_data) { - uint length=pack_length(); + uint length=pack_length(), len; int from_type= 0; /* If from length is > 255, it has encoded data in the upper bits. Need @@ -1492,14 +1494,19 @@ Field::unpack(uchar* to, const uchar *from, uint param_data) (length == param_data) || (from_type != real_type())) { + if (from + length > from_end) + return 0; // Error in data + memcpy(to, from, length); return from+length; } - uint len= (param_data && (param_data < length)) ? - param_data : length; + len= (param_data && (param_data < length)) ? param_data : length; - memcpy(to, from, param_data > length ? length : len); + if (from + len > from_end) + return 0; // Error in data + + memcpy(to, from, len); return from+len; } @@ -2916,10 +2923,11 @@ uint Field_new_decimal::is_equal(Create_field *new_field) @return New pointer into memory based on from + length of the data */ const uchar * -Field_new_decimal::unpack(uchar* to, const uchar *from, uint param_data) +Field_new_decimal::unpack(uchar* to, const uchar *from, const uchar *from_end, + uint param_data) { if (param_data == 0) - return Field::unpack(to, from, param_data); + return Field::unpack(to, from, from_end, param_data); uint from_precision= (param_data & 0xff00) >> 8U; uint from_decimal= param_data & 0x00ff; @@ -2949,7 +2957,11 @@ Field_new_decimal::unpack(uchar* to, const uchar *from, uint param_data) decimal2bin(&dec_val, to, precision, decimals()); } else + { + if (from + len > from_end) + return 0; // Wrong data memcpy(to, from, len); // Sizes are the same, just copy the data. + } return from+len; } @@ -6542,7 +6554,8 @@ uchar *Field_string::pack(uchar *to, const uchar *from, uint max_length) @return New pointer into memory based on from + length of the data */ const uchar * -Field_string::unpack(uchar *to, const uchar *from, uint param_data) +Field_string::unpack(uchar *to, const uchar *from, const uchar *from_end, + uint param_data) { uint from_length, length; @@ -6564,11 +6577,19 @@ Field_string::unpack(uchar *to, const uchar *from, uint param_data) */ if (from_length > 255) { + if (from + 2 > from_end) + return 0; length= uint2korr(from); from+= 2; } else + { + if (from + 1 > from_end) + return 0; length= (uint) *from++; + } + if (from + length > from_end || length > field_length) + return 0; memcpy(to, from, length); // Pad the string with the pad character of the fields charset @@ -7060,6 +7081,7 @@ Field_varstring::pack_key(uchar *to, const uchar *key, uint max_length) Pointer to end of 'key' (To the next key part if multi-segment key) */ +#ifdef NOT_USED const uchar * Field_varstring::unpack_key(uchar *to, const uchar *key, uint max_length) { @@ -7076,6 +7098,7 @@ Field_varstring::unpack_key(uchar *to, const uchar *key, uint max_length) memcpy(ptr + length_bytes, key, length); return key + length; } +#endif /** Create a packed key that will be used for storage in the index tree. @@ -7120,11 +7143,16 @@ uchar * Field_varstring::pack_key_from_key_image(uchar *to, const uchar *from, @return New pointer into memory based on from + length of the data */ const uchar * -Field_varstring::unpack(uchar *to, const uchar *from, uint param_data) +Field_varstring::unpack(uchar *to, const uchar *from, const uchar *from_end, + uint param_data) { uint length; uint l_bytes= (param_data && (param_data < field_length)) ? (param_data <= 255) ? 1 : 2 : length_bytes; + + if (from + l_bytes > from_end) + return 0; // Error in data + if (l_bytes == 1) { to[0]= *from++; @@ -7139,7 +7167,11 @@ Field_varstring::unpack(uchar *to, const uchar *from, uint param_data) to[1]= *from++; } if (length) + { + if (from + length > from_end || length > field_length) + return 0; // Error in data memcpy(to+ length_bytes, from, length); + } return from+length; } @@ -7771,16 +7803,21 @@ uchar *Field_blob::pack(uchar *to, const uchar *from, uint max_length) @return New pointer into memory based on from + length of the data */ -const uchar *Field_blob::unpack(uchar *to, const uchar *from, uint param_data) +const uchar *Field_blob::unpack(uchar *to, const uchar *from, + const uchar *from_end, uint param_data) { DBUG_ENTER("Field_blob::unpack"); DBUG_PRINT("enter", ("to: 0x%lx; from: 0x%lx; param_data: %u", (ulong) to, (ulong) from, param_data)); uint const master_packlength= param_data > 0 ? param_data & 0xFF : packlength; + if (from + master_packlength > from_end) + DBUG_RETURN(0); // Error in data uint32 const length= get_length(from, master_packlength); DBUG_DUMP("packed", from, length + master_packlength); bitmap_set_bit(table->write_set, field_index); + if (from + master_packlength + length > from_end) + DBUG_RETURN(0); store(reinterpret_cast(from) + master_packlength, length, field_charset); DBUG_DUMP("record", to, table->s->reclength); @@ -7878,6 +7915,7 @@ Field_blob::pack_key(uchar *to, const uchar *from, uint max_length) Pointer into 'from' past the last byte copied from packed key. */ +#ifdef NOT_USED const uchar * Field_blob::unpack_key(uchar *to, const uchar *from, uint max_length) { @@ -7898,7 +7936,7 @@ Field_blob::unpack_key(uchar *to, const uchar *from, uint max_length) /* point to first byte of next field in 'from' */ return from + length; } - +#endif /** Create a packed key that will be used for storage from a MySQL key. */ @@ -8940,7 +8978,8 @@ Field_bit::pack(uchar *to, const uchar *from, uint max_length) @return New pointer into memory based on from + length of the data */ const uchar * -Field_bit::unpack(uchar *to, const uchar *from, uint param_data) +Field_bit::unpack(uchar *to, const uchar *from, const uchar *from_end, + uint param_data) { uint const from_len= (param_data >> 8U) & 0x00ff; uint const from_bit_len= param_data & 0x00ff; @@ -8951,6 +8990,9 @@ Field_bit::unpack(uchar *to, const uchar *from, uint param_data) if (param_data == 0 || ((from_bit_len == bit_len) && (from_len == bytes_in_rec))) { + if (from + bytes_in_rec + test(bit_len) > from_end) + return 0; // Error in data + if (bit_len > 0) { /* @@ -8975,10 +9017,16 @@ Field_bit::unpack(uchar *to, const uchar *from, uint param_data) Lastly the odd bits need to be masked out if the bytes_in_rec > 0. Otherwise stray bits can cause spurious values. */ + + uint len= from_len + ((from_bit_len > 0) ? 1 : 0); uint new_len= (field_length + 7) / 8; + + if (from + len > from_end || new_len < len) + return 0; // Error in data + char *value= (char *)my_alloca(new_len); bzero(value, new_len); - uint len= from_len + ((from_bit_len > 0) ? 1 : 0); + memcpy(value + (new_len - len), from, len); /* Mask out the unused bits in the partial byte. diff --git a/sql/field.h b/sql/field.h index 933bbe2c018..d83980c2a29 100644 --- a/sql/field.h +++ b/sql/field.h @@ -483,17 +483,8 @@ public: DBUG_RETURN(result); } - virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data); - /** - @overload Field::unpack(uchar*, const uchar*, uint, bool) - */ - const uchar *unpack(uchar* to, const uchar *from) - { - DBUG_ENTER("Field::unpack"); - const uchar *result= unpack(to, from, 0); - DBUG_RETURN(result); - } - + virtual const uchar *unpack(uchar* to, const uchar *from, + const uchar *from_end, uint param_data=0); virtual uchar *pack_key(uchar* to, const uchar *from, uint max_length) { return pack(to, from, max_length); @@ -502,10 +493,12 @@ public: { return pack(to, from, max_length); } +#ifdef NOT_USED virtual const uchar *unpack_key(uchar* to, const uchar *from, uint max_length) { - return unpack(to, from, max_length); + return unpack(to, from, from + max_length+2, max_length); } +#endif virtual uint packed_col_length(const uchar *to, uint length) { return length;} virtual uint max_packed_col_length(uint max_length) @@ -786,10 +779,6 @@ public: void overflow(bool negative); bool zero_pack() const { return 0; } void sql_type(String &str) const; - virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data) - { - return Field::unpack(to, from, param_data); - } virtual uchar *pack(uchar* to, const uchar *from, uint max_length) { return Field::pack(to, from, max_length); @@ -845,7 +834,7 @@ public: int compatible_field_size(uint field_metadata, const Relay_log_info *rli, uint16 mflags); uint is_equal(Create_field *new_field); - virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data); + virtual const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, uint param_data); static Field *create_from_item (Item *); }; @@ -883,8 +872,11 @@ public: return to + 1; } - virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data) + virtual const uchar *unpack(uchar* to, const uchar *from, + const uchar *from_end, uint param_data) { + if (from == from_end) + return 0; *to= *from; return from + 1; } @@ -928,15 +920,19 @@ public: int16 val; val = sint2korr(from); int2store(to, val); - return to + sizeof(val); + return to + 2; } - virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data) + virtual const uchar *unpack(uchar* to, const uchar *from, + const uchar *from_end, uint param_data) { int16 val; + if (from +2 > from_end) + return 0; + val = sint2korr(from); int2store(to, val); - return from + sizeof(val); + return from + 2; } }; @@ -971,11 +967,6 @@ public: { return Field::pack(to, from, max_length); } - - virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data) - { - return Field::unpack(to, from, param_data); - } }; @@ -1016,8 +1007,11 @@ public: return pack_int32(to, from); } virtual const uchar *unpack(uchar* to, const uchar *from, + const uchar *from_end, uint param_data __attribute__((unused))) { + if (from + 4 > from_end) + return 0; return unpack_int32(to, from); } }; @@ -1064,9 +1058,11 @@ public: { return pack_int64(to, from); } - virtual const uchar *unpack(uchar* to, const uchar *from, - uint param_data __attribute__((unused))) + const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, + uint param_data __attribute__((unused))) { + if (from + 8 > from_end) + return 0; return unpack_int64(to, from); } }; @@ -1230,9 +1226,11 @@ public: { return pack_int32(to, from); } - const uchar *unpack(uchar* to, const uchar *from, + const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, uint param_data __attribute__((unused))) { + if (from + 4 > from_end) + return 0; return unpack_int32(to, from); } }; @@ -1269,8 +1267,9 @@ public: uint32 pack_length() const; uchar *pack(uchar *to, const uchar *from, uint max_length) { return Field::pack(to, from, max_length); } - const uchar *unpack(uchar* to, const uchar *from, uint param_data) - { return Field::unpack(to, from, param_data); } + const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, + uint param_data) + { return Field::unpack(to, from, from_end, param_data); } uint size_of() const { return sizeof(*this); } bool eq_def(Field *field) { return Field_str::eq_def(field) && dec == field->decimals(); } @@ -1353,9 +1352,11 @@ public: { return pack_int32(to, from); } - const uchar *unpack(uchar* to, const uchar *from, + const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, uint param_data __attribute__((unused))) { + if (from + 4 > from_end) + return 0; return unpack_int32(to, from); } }; @@ -1482,9 +1483,11 @@ public: { return pack_int64(to, from); } - const uchar *unpack(uchar* to, const uchar *from, + const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, uint param_data __attribute__((unused))) { + if (from + 8 > from_end) + return 0; return unpack_int64(to, from); } }; @@ -1520,8 +1523,9 @@ public: bool get_date(MYSQL_TIME *ltime,uint fuzzydate); uchar *pack(uchar *to, const uchar *from, uint max_length) { return Field::pack(to, from, max_length); } - const uchar *unpack(uchar* to, const uchar *from, uint param_data) - { return Field::unpack(to, from, param_data); } + const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, + uint param_data) + { return Field::unpack(to, from, from_end, param_data); } uint size_of() const { return sizeof(*this); } }; @@ -1612,7 +1616,8 @@ public: void sql_type(String &str) const; virtual uchar *pack(uchar *to, const uchar *from, uint max_length); - virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data); + virtual const uchar *unpack(uchar* to, const uchar *from, + const uchar *from_end,uint param_data); uint pack_length_from_metadata(uint field_metadata) { DBUG_PRINT("debug", ("field_metadata: 0x%04x", field_metadata)); @@ -1700,8 +1705,11 @@ public: virtual uchar *pack(uchar *to, const uchar *from, uint max_length); uchar *pack_key(uchar *to, const uchar *from, uint max_length); uchar *pack_key_from_key_image(uchar* to, const uchar *from, uint max_length); - virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data); + virtual const uchar *unpack(uchar* to, const uchar *from, + const uchar *from_end, uint param_data); +#ifdef NOT_USED const uchar *unpack_key(uchar* to, const uchar *from, uint max_length); +#endif int pack_cmp(const uchar *a, const uchar *b, uint key_length, bool insert_or_update); int pack_cmp(const uchar *b, uint key_length,bool insert_or_update); @@ -1873,8 +1881,11 @@ public: virtual uchar *pack(uchar *to, const uchar *from, uint max_length); uchar *pack_key(uchar *to, const uchar *from, uint max_length); uchar *pack_key_from_key_image(uchar* to, const uchar *from, uint max_length); - virtual const uchar *unpack(uchar *to, const uchar *from, uint param_data); + virtual const uchar *unpack(uchar *to, const uchar *from, + const uchar *from_end, uint param_data); +#ifdef NOT_USED const uchar *unpack_key(uchar* to, const uchar *from, uint max_length); +#endif int pack_cmp(const uchar *a, const uchar *b, uint key_length, bool insert_or_update); int pack_cmp(const uchar *b, uint key_length,bool insert_or_update); @@ -2077,7 +2088,8 @@ public: const Relay_log_info *rli, uint16 mflags); void sql_type(String &str) const; virtual uchar *pack(uchar *to, const uchar *from, uint max_length); - virtual const uchar *unpack(uchar *to, const uchar *from, uint param_data); + virtual const uchar *unpack(uchar *to, const uchar *from, + const uchar *from_end, uint param_data); virtual void set_default(); Field *new_key_field(MEM_ROOT *root, struct st_table *new_table, diff --git a/sql/filesort.cc b/sql/filesort.cc index 86d2fb1a8d0..c12337ee9be 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -60,7 +60,7 @@ static uint sortlength(THD *thd, SORT_FIELD *sortorder, uint s_length, static SORT_ADDON_FIELD *get_addon_fields(THD *thd, Field **ptabfield, uint sortlength, uint *plength); static void unpack_addon_fields(struct st_sort_addon_field *addon_field, - uchar *buff); + uchar *buff, uchar *buff_end); /** Sort a table. Creates a set of pointers that can be used to read the rows @@ -1732,7 +1732,8 @@ get_addon_fields(THD *thd, Field **ptabfield, uint sortlength, uint *plength) */ static void -unpack_addon_fields(struct st_sort_addon_field *addon_field, uchar *buff) +unpack_addon_fields(struct st_sort_addon_field *addon_field, uchar *buff, + uchar *buff_end) { Field *field; SORT_ADDON_FIELD *addonf= addon_field; @@ -1745,7 +1746,7 @@ unpack_addon_fields(struct st_sort_addon_field *addon_field, uchar *buff) continue; } field->set_notnull(); - field->unpack(field->ptr, buff + addonf->offset); + field->unpack(field->ptr, buff + addonf->offset, buff_end, 0); } } diff --git a/sql/log_event.h b/sql/log_event.h index 5dcf8c736a1..1ce17bd7e35 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -3752,7 +3752,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, + int const result= ::unpack_row(rli, m_table, m_width, m_curr_row, + m_rows_end, &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)); diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index b81d99a47a9..7328d3451f1 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -998,7 +998,8 @@ Write_rows_log_event_old::do_prepare_row(THD *thd_arg, int error; error= unpack_row_old(const_cast(rli), table, m_width, table->record[0], - row_start, &m_cols, row_end, &m_master_reclength, + row_start, m_rows_end, + &m_cols, row_end, &m_master_reclength, table->write_set, PRE_GA_WRITE_ROWS_EVENT); bitmap_copy(table->read_set, table->write_set); return error; @@ -1085,7 +1086,8 @@ Delete_rows_log_event_old::do_prepare_row(THD *thd_arg, error= unpack_row_old(const_cast(rli), table, m_width, table->record[0], - row_start, &m_cols, row_end, &m_master_reclength, + row_start, m_rows_end, + &m_cols, row_end, &m_master_reclength, table->read_set, PRE_GA_DELETE_ROWS_EVENT); /* If we will access rows using the random access method, m_key will @@ -1184,13 +1186,15 @@ int Update_rows_log_event_old::do_prepare_row(THD *thd_arg, /* record[0] is the before image for the update */ error= unpack_row_old(const_cast(rli), table, m_width, table->record[0], - row_start, &m_cols, row_end, &m_master_reclength, + row_start, m_rows_end, + &m_cols, row_end, &m_master_reclength, table->read_set, PRE_GA_UPDATE_ROWS_EVENT); row_start = *row_end; /* m_after_image is the after image for the update */ error= unpack_row_old(const_cast(rli), table, m_width, m_after_image, - row_start, &m_cols, row_end, &m_master_reclength, + row_start, m_rows_end, + &m_cols, row_end, &m_master_reclength, table->write_set, PRE_GA_UPDATE_ROWS_EVENT); DBUG_DUMP("record[0]", table->record[0], table->s->reclength); diff --git a/sql/log_event_old.h b/sql/log_event_old.h index da5cf403fdb..8fe2e9e0a75 100644 --- a/sql/log_event_old.h +++ b/sql/log_event_old.h @@ -203,7 +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, + int const result= ::unpack_row(rli, m_table, m_width, m_curr_row, + m_rows_end, &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; diff --git a/sql/records.cc b/sql/records.cc index 01c260a7e90..10817dd8e51 100644 --- a/sql/records.cc +++ b/sql/records.cc @@ -447,7 +447,8 @@ static int rr_unpack_from_tempfile(READ_RECORD *info) if (my_b_read(info->io_cache, info->rec_buf, info->ref_length)) return -1; TABLE *table= info->table; - (*table->sort.unpack)(table->sort.addon_field, info->rec_buf); + (*table->sort.unpack)(table->sort.addon_field, info->rec_buf, + info->rec_buf + info->ref_length); return 0; } @@ -498,7 +499,8 @@ static int rr_unpack_from_buffer(READ_RECORD *info) if (info->cache_pos == info->cache_end) return -1; /* End of buffer */ TABLE *table= info->table; - (*table->sort.unpack)(table->sort.addon_field, info->cache_pos); + (*table->sort.unpack)(table->sort.addon_field, info->cache_pos, + info->cache_end); info->cache_pos+= info->ref_length; return 0; diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc index cbbf2dcec48..ea8324a1fc7 100644 --- a/sql/rpl_record.cc +++ b/sql/rpl_record.cc @@ -176,13 +176,15 @@ pack_row(TABLE *table, MY_BITMAP const* cols, @retval ER_NO_DEFAULT_FOR_FIELD Returned if one of the fields existing on the slave but not on the master does not have a default value (and isn't nullable) - + @retval ER_SLAVE_CORRUPT_EVENT + Found error when trying to unpack fields. */ #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) 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_data, uchar const *const row_buffer_end, + MY_BITMAP const *cols, uchar const **const row_end, ulong *const master_reclength) { DBUG_ENTER("unpack_row"); @@ -224,9 +226,6 @@ unpack_row(Relay_log_info const *rli, DBUG_ASSERT(null_mask & 0xFF); // One of the 8 LSB should be set - /* Field...::unpack() cannot return 0 */ - DBUG_ASSERT(pack_ptr != NULL); - if (null_bits & null_mask) { if (f->maybe_null()) @@ -272,14 +271,21 @@ unpack_row(Relay_log_info const *rli, #ifndef DBUG_OFF uchar const *const old_pack_ptr= pack_ptr; #endif - pack_ptr= f->unpack(f->ptr, pack_ptr, metadata); + pack_ptr= f->unpack(f->ptr, pack_ptr, row_buffer_end, metadata); DBUG_PRINT("debug", ("field: %s; metadata: 0x%x;" " pack_ptr: 0x%lx; pack_ptr': 0x%lx; bytes: %d", f->field_name, metadata, (ulong) old_pack_ptr, (ulong) pack_ptr, (int) (pack_ptr - old_pack_ptr))); + if (!pack_ptr) + { + rli->report(ERROR_LEVEL, ER_SLAVE_CORRUPT_EVENT, + "Could not read field `%s` of table `%s`.`%s`", + f->field_name, table->s->db.str, + table->s->table_name.str); + DBUG_RETURN(ER_SLAVE_CORRUPT_EVENT); + } } - null_mask <<= 1; } i++; diff --git a/sql/rpl_record.h b/sql/rpl_record.h index 6005d57daf3..eefcdebc114 100644 --- a/sql/rpl_record.h +++ b/sql/rpl_record.h @@ -29,7 +29,8 @@ size_t pack_row(TABLE* table, MY_BITMAP const* cols, #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) 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_data, uchar const *row_buffer_end, + MY_BITMAP const *cols, uchar const **const row_end, ulong *const master_reclength); // Fill table's record[0] with default values. diff --git a/sql/rpl_record_old.cc b/sql/rpl_record_old.cc index f861ffb10f7..6709c4f6e1a 100644 --- a/sql/rpl_record_old.cc +++ b/sql/rpl_record_old.cc @@ -82,12 +82,15 @@ pack_row_old(TABLE *table, MY_BITMAP const* cols, ER_NO_DEFAULT_FOR_FIELD Returned if one of the fields existing on the slave but not on the master does not have a default value (and isn't nullable) + ER_SLAVE_CORRUPT_EVENT + Wrong data for field found. */ #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) int unpack_row_old(Relay_log_info *rli, TABLE *table, uint const colcnt, uchar *record, - uchar const *row, MY_BITMAP const *cols, + uchar const *row, const uchar *row_buffer_end, + MY_BITMAP const *cols, uchar const **row_end, ulong *master_reclength, MY_BITMAP* const rw_set, Log_event_type const event_type) { @@ -133,10 +136,16 @@ unpack_row_old(Relay_log_info *rli, if (bitmap_is_set(cols, field_ptr - begin_ptr)) { f->move_field_offset(offset); - ptr= f->unpack(f->ptr, ptr); + ptr= f->unpack(f->ptr, ptr, row_buffer_end, 0); f->move_field_offset(-offset); - /* Field...::unpack() cannot return 0 */ - DBUG_ASSERT(ptr != NULL); + if (!ptr) + { + rli->report(ERROR_LEVEL, ER_SLAVE_CORRUPT_EVENT, + "Could not read field `%s` of table `%s`.`%s`", + f->field_name, table->s->db.str, + table->s->table_name.str); + return(ER_SLAVE_CORRUPT_EVENT); + } } else bitmap_clear_bit(rw_set, field_ptr - begin_ptr); diff --git a/sql/rpl_record_old.h b/sql/rpl_record_old.h index 300c9d9a1a6..c9c2f5739cb 100644 --- a/sql/rpl_record_old.h +++ b/sql/rpl_record_old.h @@ -23,7 +23,8 @@ size_t pack_row_old(TABLE *table, MY_BITMAP const* cols, #ifdef HAVE_REPLICATION int unpack_row_old(Relay_log_info *rli, TABLE *table, uint const colcnt, uchar *record, - uchar const *row, MY_BITMAP const *cols, + uchar const *row, uchar const *row_buffer_end, + MY_BITMAP const *cols, uchar const **row_end, ulong *master_reclength, MY_BITMAP* const rw_set, Log_event_type const event_type); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 437833eb90c..c363e39b36a 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -15763,8 +15763,13 @@ int report_error(TABLE *table, int error) print them to the .err log */ if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT) + { + push_warning_printf(table->in_use, MYSQL_ERROR::WARN_LEVEL_ERROR, error, + "Got error %d when reading table `%s`.`%s`", + error, table->s->db.str, table->s->table_name.str); sql_print_error("Got error %d when reading table '%s'", error, table->s->path.str); + } table->file->print_error(error,MYF(0)); return 1; } diff --git a/sql/table.h b/sql/table.h index 5be5f4b481c..920d2fa7818 100644 --- a/sql/table.h +++ b/sql/table.h @@ -166,7 +166,7 @@ typedef struct st_filesort_info uchar *addon_buf; /* Pointer to a buffer if sorted with fields */ size_t addon_length; /* Length of the buffer */ struct st_sort_addon_field *addon_field; /* Pointer to the fields info */ - void (*unpack)(struct st_sort_addon_field *, uchar *); /* To unpack back */ + void (*unpack)(struct st_sort_addon_field *, uchar *, uchar *); /* To unpack back */ uchar *record_pointers; /* If sorted in memory */ ha_rows found_records; /* How many records in sort */ } FILESORT_INFO; diff --git a/storage/archive/ha_archive.cc b/storage/archive/ha_archive.cc index 0549ba2d978..63c37d2d43b 100644 --- a/storage/archive/ha_archive.cc +++ b/storage/archive/ha_archive.cc @@ -1120,20 +1120,26 @@ int ha_archive::unpack_row(azio_stream *file_to_read, uchar *record) if (read != row_len || error) { - DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE); + DBUG_RETURN(error ? HA_ERR_CRASHED_ON_USAGE : HA_ERR_WRONG_IN_RECORD); } /* Copy null bits */ - const uchar *ptr= record_buffer->buffer; + const uchar *ptr= record_buffer->buffer, *end= ptr+ row_len; memcpy(record, ptr, table->s->null_bytes); ptr+= table->s->null_bytes; + if (ptr > end) + DBUG_RETURN(HA_ERR_WRONG_IN_RECORD); for (Field **field=table->field ; *field ; field++) { if (!((*field)->is_null_in_record(record))) { - ptr= (*field)->unpack(record + (*field)->offset(table->record[0]), ptr); + if (!(ptr= (*field)->unpack(record + (*field)->offset(table->record[0]), + ptr, end))) + DBUG_RETURN(HA_ERR_WRONG_IN_RECORD); } } + if (ptr != end) + DBUG_RETURN(HA_ERR_WRONG_IN_RECORD); DBUG_RETURN(0); }