List:Commits« Previous MessageNext Message »
From:marko.makela Date:October 8 2012 1:29pm
Subject:bzr push into mysql-5.1 branch (marko.makela:3830 to 3831) Bug#14731482
View as plain text  
 3831 Marko Mäkelä	2012-10-08
      Bug#14731482 UPDATE OR DELETE CORRUPTS A RECORD WITH A LONG PRIMARY KEY
      
      We did not allocate enough bits for index->trx_id_offset, causing an
      UPDATE or DELETE of a table with a PRIMARY KEY longer than 1024 bytes
      to corrupt the PRIMARY KEY.
      
      dict_index_t: Allocate enough bits.
      
      dict_index_build_internal_clust(): Check for overflow of
      index->trx_id_offset. Trip a debug assertion when overflow occurs.
      
      rb:1380 approved by Jimmy Yang

    added:
      internal/mysql-test/suite/i_innodb/r/innodb_bug14731482.result
      internal/mysql-test/suite/i_innodb/t/innodb_bug14731482.test
      internal/mysql-test/suite/i_innodb_plugin/r/innodb_bug14731482.result
      internal/mysql-test/suite/i_innodb_plugin/t/innodb_bug14731482.test
    modified:
      storage/innobase/dict/dict0dict.c
      storage/innobase/include/dict0mem.h
      storage/innodb_plugin/dict/dict0dict.c
      storage/innodb_plugin/include/dict0mem.h
 3830 Tor Didriksen	2012-10-01
      Bug#14683676 ENDLESS MEMORY CONSUMPTION IN SETUP_REF_ARRAY WITH MAX IN SUBQUERY
      
      n_child_sum_items kept increasing.
      Since it is used for calculating the size of ref_pointer_array,
      we will allocate larger and larger chunks of memory, until we hit some
      operating system limit.
      The memory is free()d at disconnect, but is most likely *not*
      returned to the operating system.

    modified:
      sql/sql_lex.cc
=== added file 'internal/mysql-test/suite/i_innodb/r/innodb_bug14731482.result'
--- a/internal/mysql-test/suite/i_innodb/r/innodb_bug14731482.result	1970-01-01 00:00:00 +0000
+++ b/internal/mysql-test/suite/i_innodb/r/innodb_bug14731482.result	revid:marko.makela@stripped
@@ -0,0 +1,15 @@
+CREATE TABLE t1(
+a INT,
+c1 CHAR(255) NOT NULL DEFAULT '', c2 CHAR(255) NOT NULL DEFAULT '',
+c3 CHAR(255) NOT NULL DEFAULT '', c4 CHAR(255) NOT NULL DEFAULT '',
+c5 CHAR(255) NOT NULL DEFAULT '', c6 CHAR(255) NOT NULL DEFAULT '',
+c7 CHAR(255) NOT NULL DEFAULT '', c8 CHAR(255) NOT NULL DEFAULT '',
+c9 CHAR(255) NOT NULL DEFAULT '', ca CHAR(255) NOT NULL DEFAULT '',
+cb CHAR(255) NOT NULL DEFAULT '', cc CHAR(255) NOT NULL DEFAULT '',
+cd CHAR(255) NOT NULL DEFAULT '', ce CHAR(255) NOT NULL DEFAULT '',
+cf CHAR(255) NOT NULL DEFAULT '', cg CHAR(255) NOT NULL DEFAULT '',
+PRIMARY KEY(a,c1,c2,c3,c4,c5,c6,c7,c8,c9,ca,cb,cc)
+) ENGINE=InnoDB;
+INSERT INTO t1 (a) VALUES(1),(2);
+DELETE FROM t1;
+DROP TABLE t1;

=== added file 'internal/mysql-test/suite/i_innodb/t/innodb_bug14731482.test'
--- a/internal/mysql-test/suite/i_innodb/t/innodb_bug14731482.test	1970-01-01 00:00:00 +0000
+++ b/internal/mysql-test/suite/i_innodb/t/innodb_bug14731482.test	revid:marko.makela@stripped
@@ -0,0 +1,21 @@
+# Bug#14731482 DELETE CORRUPTS A RECORD WITH A LONG PRIMARY KEY
+
+--source include/have_innodb.inc
+
+CREATE TABLE t1(
+ a INT,
+ c1 CHAR(255) NOT NULL DEFAULT '', c2 CHAR(255) NOT NULL DEFAULT '',
+ c3 CHAR(255) NOT NULL DEFAULT '', c4 CHAR(255) NOT NULL DEFAULT '',
+ c5 CHAR(255) NOT NULL DEFAULT '', c6 CHAR(255) NOT NULL DEFAULT '',
+ c7 CHAR(255) NOT NULL DEFAULT '', c8 CHAR(255) NOT NULL DEFAULT '',
+ c9 CHAR(255) NOT NULL DEFAULT '', ca CHAR(255) NOT NULL DEFAULT '',
+ cb CHAR(255) NOT NULL DEFAULT '', cc CHAR(255) NOT NULL DEFAULT '',
+ cd CHAR(255) NOT NULL DEFAULT '', ce CHAR(255) NOT NULL DEFAULT '',
+ cf CHAR(255) NOT NULL DEFAULT '', cg CHAR(255) NOT NULL DEFAULT '',
+ PRIMARY KEY(a,c1,c2,c3,c4,c5,c6,c7,c8,c9,ca,cb,cc)
+) ENGINE=InnoDB;
+
+INSERT INTO t1 (a) VALUES(1),(2);
+
+DELETE FROM t1;
+DROP TABLE t1;

=== added file 'internal/mysql-test/suite/i_innodb_plugin/r/innodb_bug14731482.result'
--- a/internal/mysql-test/suite/i_innodb_plugin/r/innodb_bug14731482.result	1970-01-01 00:00:00 +0000
+++ b/internal/mysql-test/suite/i_innodb_plugin/r/innodb_bug14731482.result	revid:marko.makela@oracle.com-20121008130150-4jnvbos1w3e211x1
@@ -0,0 +1,15 @@
+CREATE TABLE t1(
+a INT,
+c1 CHAR(255) NOT NULL DEFAULT '', c2 CHAR(255) NOT NULL DEFAULT '',
+c3 CHAR(255) NOT NULL DEFAULT '', c4 CHAR(255) NOT NULL DEFAULT '',
+c5 CHAR(255) NOT NULL DEFAULT '', c6 CHAR(255) NOT NULL DEFAULT '',
+c7 CHAR(255) NOT NULL DEFAULT '', c8 CHAR(255) NOT NULL DEFAULT '',
+c9 CHAR(255) NOT NULL DEFAULT '', ca CHAR(255) NOT NULL DEFAULT '',
+cb CHAR(255) NOT NULL DEFAULT '', cc CHAR(255) NOT NULL DEFAULT '',
+cd CHAR(255) NOT NULL DEFAULT '', ce CHAR(255) NOT NULL DEFAULT '',
+cf CHAR(255) NOT NULL DEFAULT '', cg CHAR(255) NOT NULL DEFAULT '',
+PRIMARY KEY(a,c1,c2,c3,c4,c5,c6,c7,c8,c9,ca,cb,cc)
+) ENGINE=InnoDB;
+INSERT INTO t1 (a) VALUES(1),(2);
+DELETE FROM t1;
+DROP TABLE t1;

=== added file 'internal/mysql-test/suite/i_innodb_plugin/t/innodb_bug14731482.test'
--- a/internal/mysql-test/suite/i_innodb_plugin/t/innodb_bug14731482.test	1970-01-01 00:00:00 +0000
+++ b/internal/mysql-test/suite/i_innodb_plugin/t/innodb_bug14731482.test	revid:marko.makela@stripped1w3e211x1
@@ -0,0 +1,21 @@
+# Bug#14731482 DELETE CORRUPTS A RECORD WITH A LONG PRIMARY KEY
+
+--source include/have_innodb_plugin.inc
+
+CREATE TABLE t1(
+ a INT,
+ c1 CHAR(255) NOT NULL DEFAULT '', c2 CHAR(255) NOT NULL DEFAULT '',
+ c3 CHAR(255) NOT NULL DEFAULT '', c4 CHAR(255) NOT NULL DEFAULT '',
+ c5 CHAR(255) NOT NULL DEFAULT '', c6 CHAR(255) NOT NULL DEFAULT '',
+ c7 CHAR(255) NOT NULL DEFAULT '', c8 CHAR(255) NOT NULL DEFAULT '',
+ c9 CHAR(255) NOT NULL DEFAULT '', ca CHAR(255) NOT NULL DEFAULT '',
+ cb CHAR(255) NOT NULL DEFAULT '', cc CHAR(255) NOT NULL DEFAULT '',
+ cd CHAR(255) NOT NULL DEFAULT '', ce CHAR(255) NOT NULL DEFAULT '',
+ cf CHAR(255) NOT NULL DEFAULT '', cg CHAR(255) NOT NULL DEFAULT '',
+ PRIMARY KEY(a,c1,c2,c3,c4,c5,c6,c7,c8,c9,ca,cb,cc)
+) ENGINE=InnoDB;
+
+INSERT INTO t1 (a) VALUES(1),(2);
+
+DELETE FROM t1;
+DROP TABLE t1;

=== modified file 'storage/innobase/dict/dict0dict.c'
--- a/storage/innobase/dict/dict0dict.c	revid:tor.didriksen@stripped
+++ b/storage/innobase/dict/dict0dict.c	revid:marko.makela@oracle.com-20121008130150-4jnvbos1w3e211x1
@@ -1629,7 +1629,6 @@ dict_index_build_internal_clust(
 {
 	dict_index_t*	new_index;
 	dict_field_t*	field;
-	ulint		fixed_size;
 	ulint		trx_id_pos;
 	ulint		i;
 	ibool*		indexed;
@@ -1706,7 +1705,7 @@ dict_index_build_internal_clust(
 
 		for (i = 0; i < trx_id_pos; i++) {
 
-			fixed_size = dict_col_get_fixed_size(
+			ulint	fixed_size = dict_col_get_fixed_size(
 				dict_index_get_nth_col(new_index, i));
 
 			if (fixed_size == 0) {
@@ -1722,7 +1721,20 @@ dict_index_build_internal_clust(
 				break;
 			}
 
-			new_index->trx_id_offset += (unsigned int) fixed_size;
+			/* Add fixed_size to new_index->trx_id_offset.
+			Because the latter is a bit-field, an overflow
+			can theoretically occur. Check for it. */
+			fixed_size += new_index->trx_id_offset;
+
+			new_index->trx_id_offset = fixed_size;
+
+			if (new_index->trx_id_offset != fixed_size) {
+				/* Overflow. Pretend that this is a
+				variable-length PRIMARY KEY. */
+				ut_ad(0);
+				new_index->trx_id_offset = 0;
+				break;
+			}
 		}
 
 	}

=== modified file 'storage/innobase/include/dict0mem.h'
--- a/storage/innobase/include/dict0mem.h	revid:tor.didriksen@stripped0121001111238-geatvbdun02riank
+++ b/storage/innobase/include/dict0mem.h	revid:marko.makela@stripped150-4jnvbos1w3e211x1
@@ -196,10 +196,15 @@ struct dict_index_struct{
 	unsigned	space:32;
 				/* space where the index tree is placed */
 	unsigned	page:32;/* index tree root page number */
-	unsigned	trx_id_offset:10;/* position of the the trx id column
+#define MAX_KEY_LENGTH_BITS 12
+	unsigned	trx_id_offset:MAX_KEY_LENGTH_BITS;
+				/* position of the trx id column
 				in a clustered index record, if the fields
 				before it are known to be of a fixed size,
 				0 otherwise */
+#if (1<<MAX_KEY_LENGTH_BITS) < MAX_KEY_LENGTH
+# error (1<<MAX_KEY_LENGTH_BITS) < MAX_KEY_LENGTH
+#endif
 	unsigned	n_user_defined_cols:10;
 				/* number of columns the user defined to
 				be in the index: in the internal

=== modified file 'storage/innodb_plugin/dict/dict0dict.c'
--- a/storage/innodb_plugin/dict/dict0dict.c	revid:tor.didriksen@stripped01111238-geatvbdun02riank
+++ b/storage/innodb_plugin/dict/dict0dict.c	revid:marko.makela@stripped0-4jnvbos1w3e211x1
@@ -1959,7 +1959,6 @@ dict_index_build_internal_clust(
 {
 	dict_index_t*	new_index;
 	dict_field_t*	field;
-	ulint		fixed_size;
 	ulint		trx_id_pos;
 	ulint		i;
 	ibool*		indexed;
@@ -2036,7 +2035,7 @@ dict_index_build_internal_clust(
 
 		for (i = 0; i < trx_id_pos; i++) {
 
-			fixed_size = dict_col_get_fixed_size(
+			ulint	fixed_size = dict_col_get_fixed_size(
 				dict_index_get_nth_col(new_index, i),
 				dict_table_is_comp(table));
 
@@ -2053,7 +2052,20 @@ dict_index_build_internal_clust(
 				break;
 			}
 
-			new_index->trx_id_offset += (unsigned int) fixed_size;
+			/* Add fixed_size to new_index->trx_id_offset.
+			Because the latter is a bit-field, an overflow
+			can theoretically occur. Check for it. */
+			fixed_size += new_index->trx_id_offset;
+
+			new_index->trx_id_offset = fixed_size;
+
+			if (new_index->trx_id_offset != fixed_size) {
+				/* Overflow. Pretend that this is a
+				variable-length PRIMARY KEY. */
+				ut_ad(0);
+				new_index->trx_id_offset = 0;
+				break;
+			}
 		}
 
 	}

=== modified file 'storage/innodb_plugin/include/dict0mem.h'
--- a/storage/innodb_plugin/include/dict0mem.h	revid:tor.didriksen@stripped238-geatvbdun02riank
+++ b/storage/innodb_plugin/include/dict0mem.h	revid:marko.makela@strippedjnvbos1w3e211x1
@@ -286,10 +286,15 @@ struct dict_index_struct{
 #endif /* !UNIV_HOTBACKUP */
 	unsigned	type:4;	/*!< index type (DICT_CLUSTERED, DICT_UNIQUE,
 				DICT_UNIVERSAL, DICT_IBUF) */
-	unsigned	trx_id_offset:10;/*!< position of the trx id column
+#define MAX_KEY_LENGTH_BITS 12
+	unsigned	trx_id_offset:MAX_KEY_LENGTH_BITS;
+				/*!< position of the trx id column
 				in a clustered index record, if the fields
 				before it are known to be of a fixed size,
 				0 otherwise */
+#if (1<<MAX_KEY_LENGTH_BITS) < MAX_KEY_LENGTH
+# error (1<<MAX_KEY_LENGTH_BITS) < MAX_KEY_LENGTH
+#endif
 	unsigned	n_user_defined_cols:10;
 				/*!< number of columns the user defined to
 				be in the index: in the internal

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-5.1 branch (marko.makela:3830 to 3831) Bug#14731482marko.makela8 Oct