diff options
author | Marko Mäkelä <marko.makela@oracle.com> | 2012-10-08 16:01:50 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@oracle.com> | 2012-10-08 16:01:50 +0300 |
commit | be509b41aab295215ad31f38be727a61792f435d (patch) | |
tree | ab07e1ee2bc167a0245e32bc23ffdce8281d73bf /storage/innobase | |
parent | 4d29767e6c57198eb4650421f730701b4dd4d2d7 (diff) | |
download | mariadb-git-be509b41aab295215ad31f38be727a61792f435d.tar.gz |
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
Diffstat (limited to 'storage/innobase')
-rw-r--r-- | storage/innobase/dict/dict0dict.c | 18 | ||||
-rw-r--r-- | storage/innobase/include/dict0mem.h | 7 |
2 files changed, 21 insertions, 4 deletions
diff --git a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c index b2baa81b73f..7139eb5db95 100644 --- a/storage/innobase/dict/dict0dict.c +++ b/storage/innobase/dict/dict0dict.c @@ -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; + } } } diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index 83dbf65ea41..8a55fef7f73 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -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 |