summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/archive.result11
-rw-r--r--mysql-test/std_data/t917689.ARZbin0 -> 8687 bytes
-rw-r--r--mysql-test/t/archive.test11
-rw-r--r--mysql-test/t/sp.test5
-rw-r--r--sql/field.cc74
-rw-r--r--sql/field.h90
-rw-r--r--sql/filesort.cc7
-rw-r--r--sql/log_event.h3
-rw-r--r--sql/log_event_old.cc12
-rw-r--r--sql/log_event_old.h3
-rw-r--r--sql/records.cc6
-rw-r--r--sql/rpl_record.cc20
-rw-r--r--sql/rpl_record.h3
-rw-r--r--sql/rpl_record_old.cc17
-rw-r--r--sql/rpl_record_old.h3
-rw-r--r--sql/sql_select.cc5
-rw-r--r--sql/table.h2
-rw-r--r--storage/archive/ha_archive.cc12
18 files changed, 203 insertions, 81 deletions
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
--- /dev/null
+++ b/mysql-test/std_data/t917689.ARZ
Binary files 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<const char*>(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<Relay_log_info*>(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<Relay_log_info*>(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<Relay_log_info*>(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<Relay_log_info*>(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);
}