Details
-
Bug
-
Status: Closed (View Workflow)
-
Critical
-
Resolution: Fixed
-
10.5, 10.6, 10.4(EOL), 10.7(EOL), 10.8(EOL)
Description
The following crash was observed on 10.8:
10.8 a635c40648519fd6c3729c9657872a16a0a20821 |
#0 0x000055635ccef651 in dict_index_t::reconstruct_fields()::{lambda(dict_field_t const&)#1}::operator()(dict_field_t const&) const (o=
|
@0x61a00000a9e0: {col = 0xbebebebebebebebe, name = {m_name = 0xbebebebebebebebe <error: Cannot access memory at address 0xbebebebebebebebe>}, prefix_len = 3774, fixed_len = 1003, descending = 0}, __closure=0x7fffda7bcbf0)
|
at /mariadb/10.8/storage/innobase/dict/dict0mem.cc:1209
|
1209 { return o.col->ind == c.ind(); });
|
One column has been instantly dropped, and some columns have been reordered. I tried to guess a test case, but I failed.
diff --git a/mysql-test/suite/innodb/t/instant_alter_crash.test b/mysql-test/suite/innodb/t/instant_alter_crash.test
|
index 43db8f619f3..75f26a80559 100644
|
--- a/mysql-test/suite/innodb/t/instant_alter_crash.test
|
+++ b/mysql-test/suite/innodb/t/instant_alter_crash.test
|
@@ -184,6 +184,12 @@ CREATE TABLE t3(id INT PRIMARY KEY, c2 INT, v2 INT AS(c2) VIRTUAL, UNIQUE(v2))
|
ENGINE=InnoDB;
|
INSERT INTO t3 SET id=1,c2=1;
|
|
+CREATE TABLE t4(id INT PRIMARY KEY,c2 INT,c3 INT,c4 INT,c5 INT,c6 INT,c7 INT)
|
+ENGINE=InnoDB;
|
+INSERT INTO t4 SET id=1;
|
+ALTER TABLE t4 DROP c4, MODIFY c5 INT AFTER c2, ADD (c8 INT, c9 INT),
|
+ALGORITHM=INSTANT;
|
+
|
SET DEBUG_SYNC='innodb_alter_inplace_before_commit SIGNAL ddl WAIT_FOR ever';
|
--send
|
ALTER TABLE t3 ADD COLUMN c3 TEXT NOT NULL DEFAULT 'sic transit gloria mundi';
|
@@ -198,10 +204,12 @@ INSERT INTO t1 VALUES(0,0);
|
disconnect ddl;
|
--source include/start_mysqld.inc
|
|
+SELECT * FROM t4;
|
SHOW CREATE TABLE t1;
|
SHOW CREATE TABLE t2;
|
SHOW CREATE TABLE t3;
|
-DROP TABLE t1,t2,t3;
|
+SHOW CREATE TABLE t4;
|
+DROP TABLE t1,t2,t3,t4;
|
|
--remove_files_wildcard $MYSQLD_DATADIR/test #sql*.frm
|
--list_files $MYSQLD_DATADIR/test |
The following should fix the failure by preventing the out-of-bounds access:
diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc
|
index 8d53f646131..37cf7dc687f 100644
|
--- a/storage/innobase/dict/dict0mem.cc
|
+++ b/storage/innobase/dict/dict0mem.cc
|
@@ -1177,6 +1177,8 @@ inline bool dict_index_t::reconstruct_fields()
|
{
|
DBUG_ASSERT(is_primary());
|
|
+ const auto old_n_fields{n_fields};
|
+
|
n_fields = (n_fields + table->instant->n_dropped)
|
& dict_index_t::MAX_N_FIELDS;
|
n_def = (n_def + table->instant->n_dropped)
|
@@ -1204,11 +1206,11 @@ inline bool dict_index_t::reconstruct_fields()
|
} else {
|
DBUG_ASSERT(!c.is_not_null());
|
const auto old = std::find_if(
|
- fields + n_first, fields + n_fields,
|
+ fields + n_first, fields + old_n_fields,
|
[c](const dict_field_t& o)
|
{ return o.col->ind == c.ind(); });
|
|
- if (old >= fields + n_fields
|
+ if (old >= fields + old_n_fields
|
|| old->prefix_len
|
|| old->col != &table->cols[c.ind()]) {
|
return true; |
I hope that mleich can come up with a test case for this.