From 4924c61999cac4738f7f4a7422d600e0b7dcf3a3 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 5 Dec 2006 10:46:03 +0100 Subject: [PATCH] BUG#24490 (segfault inside unpack_row at Field_bit_as_char::set_default()): Field_bit::set_default() did not check the bit_len, hence used the undefined bit_ptr, causing a crash. The patch adds a check that bit_len > 0 before following the bit_ptr. mysql-test/extra/rpl_tests/rpl_row_tabledefs.test: Doing select using ORDER BY to prevent table-internal order from affecting the result. mysql-test/r/rpl_row_tabledefs_2myisam.result: Result change mysql-test/r/rpl_row_tabledefs_3innodb.result: Result change sql/field.cc: Checking bit_len before following the bit_ptr, since bit_ptr has no sensible value in the case that bit_len == 0. sql/field.h: Field_bit::set_default() used the bit_ptr, but it is undefined, hence causing a crash. In reality, the hierarchy order is not correct so added a TODO comment about refactoring. sql/log_event.cc: Code was manipulating bits for a FIELD_TYPE_BIT field without checking if the bit_len was > 0, hence using an undefined bit_ptr when the class was actually a Field_bit_as_char. mysql-test/t/rpl_row_tabledefs_3innodb-slave.opt: New BitKeeper file ``mysql-test/t/rpl_row_tabledefs_3innodb-slave.opt'' --- .../extra/rpl_tests/rpl_row_tabledefs.test | 40 +++++++------- mysql-test/r/rpl_row_tabledefs_2myisam.result | 52 +++++++++---------- mysql-test/r/rpl_row_tabledefs_3innodb.result | 52 +++++++++---------- .../t/rpl_row_tabledefs_3innodb-slave.opt | 1 + sql/field.cc | 9 ++-- sql/field.h | 7 +++ sql/log_event.cc | 13 +++-- 7 files changed, 94 insertions(+), 80 deletions(-) create mode 100644 mysql-test/t/rpl_row_tabledefs_3innodb-slave.opt diff --git a/mysql-test/extra/rpl_tests/rpl_row_tabledefs.test b/mysql-test/extra/rpl_tests/rpl_row_tabledefs.test index 54c14594cf4..c50a5613386 100644 --- a/mysql-test/extra/rpl_tests/rpl_row_tabledefs.test +++ b/mysql-test/extra/rpl_tests/rpl_row_tabledefs.test @@ -80,28 +80,28 @@ INSERT INTO t1_bit VALUES (1,2); INSERT INTO t1_bit VALUES (2,5); INSERT INTO t1_char VALUES (1,2); INSERT INTO t1_char VALUES (2,5); -SELECT * FROM t1_int; -SELECT * FROM t1_bit; -SELECT * FROM t1_char; +SELECT * FROM t1_int ORDER BY a; +SELECT * FROM t1_bit ORDER BY a; +SELECT * FROM t1_char ORDER BY a; --echo **** On Slave **** sync_slave_with_master; -SELECT a,b,x FROM t1_int; -SELECT a,b,HEX(x),HEX(y),HEX(z) FROM t1_bit; -SELECT a,b,x FROM t1_char; +SELECT a,b,x FROM t1_int ORDER BY a; +SELECT a,b,HEX(x),HEX(y),HEX(z) FROM t1_bit ORDER BY a; +SELECT a,b,x FROM t1_char ORDER BY a; --echo **** On Master **** connection master; UPDATE t1_int SET b=2*b WHERE a=2; UPDATE t1_char SET b=2*b WHERE a=2; UPDATE t1_bit SET b=2*b WHERE a=2; -SELECT * FROM t1_int; -SELECT * FROM t1_bit; -SELECT * FROM t1_char; +SELECT * FROM t1_int ORDER BY a; +SELECT * FROM t1_bit ORDER BY a; +SELECT * FROM t1_char ORDER BY a; --echo **** On Slave **** sync_slave_with_master; -SELECT a,b,x FROM t1_int; -SELECT a,b,HEX(x),HEX(y),HEX(z) FROM t1_bit; -SELECT a,b,x FROM t1_char; +SELECT a,b,x FROM t1_int ORDER BY a; +SELECT a,b,HEX(x),HEX(y),HEX(z) FROM t1_bit ORDER BY a; +SELECT a,b,x FROM t1_char ORDER BY a; # Each of these inserts should generate an error and stop the slave @@ -188,11 +188,11 @@ sync_slave_with_master; connection master; INSERT INTO t7 VALUES (1),(2),(3); INSERT INTO t8 VALUES (1),(2),(3); -SELECT * FROM t7; -SELECT * FROM t8; +SELECT * FROM t7 ORDER BY a; +SELECT * FROM t8 ORDER BY a; sync_slave_with_master; -SELECT * FROM t7; -SELECT * FROM t8; +SELECT * FROM t7 ORDER BY a; +SELECT * FROM t8 ORDER BY a; # We will now try to update and then delete a row on the master where # the extra field on the slave does not have a default value. This @@ -216,20 +216,20 @@ INSERT INTO t1_nodef VALUES (2,4,6); --echo **** On Master **** connection master; UPDATE t1_nodef SET b=2*b WHERE a=1; -SELECT * FROM t1_nodef; +SELECT * FROM t1_nodef ORDER BY a; --echo **** On Slave **** sync_slave_with_master; -SELECT * FROM t1_nodef; +SELECT * FROM t1_nodef ORDER BY a; --echo **** On Master **** connection master; DELETE FROM t1_nodef WHERE a=2; -SELECT * FROM t1_nodef; +SELECT * FROM t1_nodef ORDER BY a; --echo **** On Slave **** sync_slave_with_master; -SELECT * FROM t1_nodef; +SELECT * FROM t1_nodef ORDER BY a; --echo **** Cleanup **** connection master; diff --git a/mysql-test/r/rpl_row_tabledefs_2myisam.result b/mysql-test/r/rpl_row_tabledefs_2myisam.result index ae792a5dc2a..ea2fc234c44 100644 --- a/mysql-test/r/rpl_row_tabledefs_2myisam.result +++ b/mysql-test/r/rpl_row_tabledefs_2myisam.result @@ -46,60 +46,60 @@ INSERT INTO t1_bit VALUES (1,2); INSERT INTO t1_bit VALUES (2,5); INSERT INTO t1_char VALUES (1,2); INSERT INTO t1_char VALUES (2,5); -SELECT * FROM t1_int; +SELECT * FROM t1_int ORDER BY a; a b 1 2 2 5 -SELECT * FROM t1_bit; +SELECT * FROM t1_bit ORDER BY a; a b 1 2 2 5 -SELECT * FROM t1_char; +SELECT * FROM t1_char ORDER BY a; a b 1 2 2 5 **** On Slave **** -SELECT a,b,x FROM t1_int; +SELECT a,b,x FROM t1_int ORDER BY a; a b x -2 5 4711 1 2 42 -SELECT a,b,HEX(x),HEX(y),HEX(z) FROM t1_bit; +2 5 4711 +SELECT a,b,HEX(x),HEX(y),HEX(z) FROM t1_bit ORDER BY a; a b HEX(x) HEX(y) HEX(z) -2 5 5 1C 1 1 2 3 15 2 -SELECT a,b,x FROM t1_char; +2 5 5 1C 1 +SELECT a,b,x FROM t1_char ORDER BY a; a b x -2 5 Foo is a bar 1 2 Just a test +2 5 Foo is a bar **** On Master **** UPDATE t1_int SET b=2*b WHERE a=2; UPDATE t1_char SET b=2*b WHERE a=2; UPDATE t1_bit SET b=2*b WHERE a=2; -SELECT * FROM t1_int; +SELECT * FROM t1_int ORDER BY a; a b 1 2 2 10 -SELECT * FROM t1_bit; +SELECT * FROM t1_bit ORDER BY a; a b 1 2 2 10 -SELECT * FROM t1_char; +SELECT * FROM t1_char ORDER BY a; a b 1 2 2 10 **** On Slave **** -SELECT a,b,x FROM t1_int; +SELECT a,b,x FROM t1_int ORDER BY a; a b x -2 10 4711 1 2 42 -SELECT a,b,HEX(x),HEX(y),HEX(z) FROM t1_bit; +2 10 4711 +SELECT a,b,HEX(x),HEX(y),HEX(z) FROM t1_bit ORDER BY a; a b HEX(x) HEX(y) HEX(z) -2 10 5 1C 1 1 2 3 15 2 -SELECT a,b,x FROM t1_char; +2 10 5 1C 1 +SELECT a,b,x FROM t1_char ORDER BY a; a b x -2 10 Foo is a bar 1 2 Just a test +2 10 Foo is a bar INSERT INTO t9 VALUES (2); INSERT INTO t1_nodef VALUES (1,2); SHOW SLAVE STATUS; @@ -327,22 +327,22 @@ Master_SSL_Key Seconds_Behind_Master # INSERT INTO t7 VALUES (1),(2),(3); INSERT INTO t8 VALUES (1),(2),(3); -SELECT * FROM t7; +SELECT * FROM t7 ORDER BY a; a 1 2 3 -SELECT * FROM t8; +SELECT * FROM t8 ORDER BY a; a 1 2 3 -SELECT * FROM t7; +SELECT * FROM t7 ORDER BY a; a e1 e2 e3 e4 e5 e6 e7 e8 1 NULL NULL NULL NULL NULL NULL NULL NULL 2 NULL NULL NULL NULL NULL NULL NULL NULL 3 NULL NULL NULL NULL NULL NULL NULL NULL -SELECT * FROM t8; +SELECT * FROM t8 ORDER BY a; a e1 e2 e3 e4 e5 e6 e7 e8 1 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 @@ -358,22 +358,22 @@ INSERT INTO t1_nodef VALUES (1,2,3); INSERT INTO t1_nodef VALUES (2,4,6); **** On Master **** UPDATE t1_nodef SET b=2*b WHERE a=1; -SELECT * FROM t1_nodef; +SELECT * FROM t1_nodef ORDER BY a; a b 1 4 2 4 **** On Slave **** -SELECT * FROM t1_nodef; +SELECT * FROM t1_nodef ORDER BY a; a b x 1 4 3 2 4 6 **** On Master **** DELETE FROM t1_nodef WHERE a=2; -SELECT * FROM t1_nodef; +SELECT * FROM t1_nodef ORDER BY a; a b 1 4 **** On Slave **** -SELECT * FROM t1_nodef; +SELECT * FROM t1_nodef ORDER BY a; a b x 1 4 3 **** Cleanup **** diff --git a/mysql-test/r/rpl_row_tabledefs_3innodb.result b/mysql-test/r/rpl_row_tabledefs_3innodb.result index b7f0b7b15e2..9eeadc171f8 100644 --- a/mysql-test/r/rpl_row_tabledefs_3innodb.result +++ b/mysql-test/r/rpl_row_tabledefs_3innodb.result @@ -46,60 +46,60 @@ INSERT INTO t1_bit VALUES (1,2); INSERT INTO t1_bit VALUES (2,5); INSERT INTO t1_char VALUES (1,2); INSERT INTO t1_char VALUES (2,5); -SELECT * FROM t1_int; +SELECT * FROM t1_int ORDER BY a; a b 1 2 2 5 -SELECT * FROM t1_bit; +SELECT * FROM t1_bit ORDER BY a; a b 1 2 2 5 -SELECT * FROM t1_char; +SELECT * FROM t1_char ORDER BY a; a b 1 2 2 5 **** On Slave **** -SELECT a,b,x FROM t1_int; +SELECT a,b,x FROM t1_int ORDER BY a; a b x -2 5 4711 1 2 42 -SELECT a,b,HEX(x),HEX(y),HEX(z) FROM t1_bit; +2 5 4711 +SELECT a,b,HEX(x),HEX(y),HEX(z) FROM t1_bit ORDER BY a; a b HEX(x) HEX(y) HEX(z) -2 5 5 1C 1 1 2 3 15 2 -SELECT a,b,x FROM t1_char; +2 5 5 1C 1 +SELECT a,b,x FROM t1_char ORDER BY a; a b x -2 5 Foo is a bar 1 2 Just a test +2 5 Foo is a bar **** On Master **** UPDATE t1_int SET b=2*b WHERE a=2; UPDATE t1_char SET b=2*b WHERE a=2; UPDATE t1_bit SET b=2*b WHERE a=2; -SELECT * FROM t1_int; +SELECT * FROM t1_int ORDER BY a; a b 1 2 2 10 -SELECT * FROM t1_bit; +SELECT * FROM t1_bit ORDER BY a; a b 1 2 2 10 -SELECT * FROM t1_char; +SELECT * FROM t1_char ORDER BY a; a b 1 2 2 10 **** On Slave **** -SELECT a,b,x FROM t1_int; +SELECT a,b,x FROM t1_int ORDER BY a; a b x -2 10 4711 1 2 42 -SELECT a,b,HEX(x),HEX(y),HEX(z) FROM t1_bit; +2 10 4711 +SELECT a,b,HEX(x),HEX(y),HEX(z) FROM t1_bit ORDER BY a; a b HEX(x) HEX(y) HEX(z) -2 10 5 1C 1 1 2 3 15 2 -SELECT a,b,x FROM t1_char; +2 10 5 1C 1 +SELECT a,b,x FROM t1_char ORDER BY a; a b x -2 10 Foo is a bar 1 2 Just a test +2 10 Foo is a bar INSERT INTO t9 VALUES (2); INSERT INTO t1_nodef VALUES (1,2); SHOW SLAVE STATUS; @@ -327,22 +327,22 @@ Master_SSL_Key Seconds_Behind_Master # INSERT INTO t7 VALUES (1),(2),(3); INSERT INTO t8 VALUES (1),(2),(3); -SELECT * FROM t7; +SELECT * FROM t7 ORDER BY a; a 1 2 3 -SELECT * FROM t8; +SELECT * FROM t8 ORDER BY a; a 1 2 3 -SELECT * FROM t7; +SELECT * FROM t7 ORDER BY a; a e1 e2 e3 e4 e5 e6 e7 e8 1 NULL NULL NULL NULL NULL NULL NULL NULL 2 NULL NULL NULL NULL NULL NULL NULL NULL 3 NULL NULL NULL NULL NULL NULL NULL NULL -SELECT * FROM t8; +SELECT * FROM t8 ORDER BY a; a e1 e2 e3 e4 e5 e6 e7 e8 1 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 @@ -358,22 +358,22 @@ INSERT INTO t1_nodef VALUES (1,2,3); INSERT INTO t1_nodef VALUES (2,4,6); **** On Master **** UPDATE t1_nodef SET b=2*b WHERE a=1; -SELECT * FROM t1_nodef; +SELECT * FROM t1_nodef ORDER BY a; a b 1 4 2 4 **** On Slave **** -SELECT * FROM t1_nodef; +SELECT * FROM t1_nodef ORDER BY a; a b x 1 4 3 2 4 6 **** On Master **** DELETE FROM t1_nodef WHERE a=2; -SELECT * FROM t1_nodef; +SELECT * FROM t1_nodef ORDER BY a; a b 1 4 **** On Slave **** -SELECT * FROM t1_nodef; +SELECT * FROM t1_nodef ORDER BY a; a b x 1 4 3 **** Cleanup **** diff --git a/mysql-test/t/rpl_row_tabledefs_3innodb-slave.opt b/mysql-test/t/rpl_row_tabledefs_3innodb-slave.opt new file mode 100644 index 00000000000..627becdbfb5 --- /dev/null +++ b/mysql-test/t/rpl_row_tabledefs_3innodb-slave.opt @@ -0,0 +1 @@ +--innodb diff --git a/sql/field.cc b/sql/field.cc index 1e42a53e45a..fcd5ed6f84f 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -8455,9 +8455,12 @@ const char *Field_bit::unpack(char *to, const char *from) void Field_bit::set_default() { - my_ptrdiff_t const offset= table->s->default_values - table->record[0]; - uchar bits= get_rec_bits(bit_ptr + offset, bit_ofs, bit_len); - set_rec_bits(bits, bit_ptr, bit_ofs, bit_len); + if (bit_len > 0) + { + my_ptrdiff_t const offset= table->s->default_values - table->record[0]; + uchar bits= get_rec_bits(bit_ptr + offset, bit_ofs, bit_len); + set_rec_bits(bits, bit_ptr, bit_ofs, bit_len); + } Field::set_default(); } diff --git a/sql/field.h b/sql/field.h index f0cd9cc6f03..dc7af4aa4d2 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1488,6 +1488,13 @@ private: }; +/** + BIT field represented as chars for non-MyISAM tables. + + @todo The inheritance relationship is backwards since Field_bit is + an extended version of Field_bit_as_char and not the other way + around. Hence, we should refactor it to fix the hierarchy order. + */ class Field_bit_as_char: public Field_bit { public: Field_bit_as_char(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, diff --git a/sql/log_event.cc b/sql/log_event.cc index 7bb4a72edfa..f5ddaf12d6d 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -6578,10 +6578,13 @@ copy_extra_record_fields(TABLE *table, case FIELD_TYPE_BIT: Field_bit *f= static_cast(*field_ptr); - my_ptrdiff_t const offset= table->record[1] - table->record[0]; - uchar const bits= - get_rec_bits(f->bit_ptr + offset, f->bit_ofs, f->bit_len); - set_rec_bits(bits, f->bit_ptr, f->bit_ofs, f->bit_len); + if (f->bit_len > 0) + { + my_ptrdiff_t const offset= table->record[1] - table->record[0]; + uchar const bits= + get_rec_bits(f->bit_ptr + offset, f->bit_ofs, f->bit_len); + set_rec_bits(bits, f->bit_ptr, f->bit_ofs, f->bit_len); + } break; } } @@ -6682,7 +6685,7 @@ replace_record(THD *thd, TABLE *table, present on the master from table->record[1], if there are any. */ copy_extra_record_fields(table, master_reclength, master_fields); - + /* REPLACE is defined as either INSERT or DELETE + INSERT. If possible, we can replace it with an UPDATE, but that will not