From db2ed27e0ebe13fa70972b9993ff9bbd2f29499f Mon Sep 17 00:00:00 2001 From: Annamalai Gurusami Date: Fri, 19 Jun 2015 10:17:36 +0530 Subject: [PATCH] Bug #20762798 FK DDL: CRASH IN DICT_FOREIGN_REMOVE_FROM_CACHE Problem: If we add a referential integrity constraint with a duplicate name, an error occurs. The foreign key object would not have been added to the dictionary cache. In the error path, there is an attempt to remove this foreign key object. Since this object is not there, the search returns a NULL result. De-referencing the null object results in this crash. Solution: If the search to the foreign key object failed, then don't attempt to access it. rb#9309 approved by Marko. --- .../suite/innodb/r/add_constraint.result | 13 ++++++++++++ mysql-test/suite/innodb/t/add_constraint.test | 21 +++++++++++++++++++ storage/innobase/dict/dict0dict.c | 20 ++++++++++++------ 3 files changed, 48 insertions(+), 6 deletions(-) create mode 100644 mysql-test/suite/innodb/r/add_constraint.result create mode 100644 mysql-test/suite/innodb/t/add_constraint.test diff --git a/mysql-test/suite/innodb/r/add_constraint.result b/mysql-test/suite/innodb/r/add_constraint.result new file mode 100644 index 00000000000..cbbcb4e8fa8 --- /dev/null +++ b/mysql-test/suite/innodb/r/add_constraint.result @@ -0,0 +1,13 @@ +# +# Bug #20762798 FK DDL: CRASH IN DICT_FOREIGN_REMOVE_FROM_CACHE +# +create table t1(a int, b int, key(a),key(b))engine=innodb; +create table t2(a int, b int, key(a),key(b))engine=innodb; +alter table t2 add constraint b foreign key (b) references t1(a); +alter table t1 add constraint b1 foreign key (b) references t2(a); +alter table t2 add constraint b1 foreign key (b) references t1(a); +ERROR HY000: Can't create table '#sql-temporary' (errno: 121) +alter table t2 drop foreign key b; +alter table t1 drop foreign key b1; +drop table t2; +drop table t1; diff --git a/mysql-test/suite/innodb/t/add_constraint.test b/mysql-test/suite/innodb/t/add_constraint.test new file mode 100644 index 00000000000..eabf06434f4 --- /dev/null +++ b/mysql-test/suite/innodb/t/add_constraint.test @@ -0,0 +1,21 @@ +--source include/have_innodb.inc + +--echo # +--echo # Bug #20762798 FK DDL: CRASH IN DICT_FOREIGN_REMOVE_FROM_CACHE +--echo # + +create table t1(a int, b int, key(a),key(b))engine=innodb; +create table t2(a int, b int, key(a),key(b))engine=innodb; + +alter table t2 add constraint b foreign key (b) references t1(a); +alter table t1 add constraint b1 foreign key (b) references t2(a); + +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error ER_CANT_CREATE_TABLE +alter table t2 add constraint b1 foreign key (b) references t1(a); + +alter table t2 drop foreign key b; +alter table t1 drop foreign key b1; + +drop table t2; +drop table t1; diff --git a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c index 56baceb7a4b..5aca95aec0d 100644 --- a/storage/innobase/dict/dict0dict.c +++ b/storage/innobase/dict/dict0dict.c @@ -2533,10 +2533,14 @@ dict_foreign_remove_from_cache( if (rbt != NULL && foreign->id != NULL) { const ib_rbt_node_t* node = rbt_lookup(rbt, foreign->id); - dict_foreign_t* val = *(dict_foreign_t**) node->value; - if (val == foreign) { - rbt_delete(rbt, foreign->id); + if (node != NULL) { + dict_foreign_t* val + = *(dict_foreign_t**) node->value; + + if (val == foreign) { + rbt_delete(rbt, foreign->id); + } } } } @@ -2552,10 +2556,14 @@ dict_foreign_remove_from_cache( if (rbt != NULL && foreign->id != NULL) { const ib_rbt_node_t* node = rbt_lookup(rbt, foreign->id); - dict_foreign_t* val = *(dict_foreign_t**) node->value; - if (val == foreign) { - rbt_delete(rbt, foreign->id); + if (node != NULL) { + dict_foreign_t* val + = *(dict_foreign_t**) node->value; + + if (val == foreign) { + rbt_delete(rbt, foreign->id); + } } } }