Skip to content

Commit

Permalink
MDEV-17896 Assertion `pfs->get_refcount() > 0' failed
Browse files Browse the repository at this point in the history
Unfortunate DROP TEMPORARY..IF EXISTS on a regular table may allow
subsequent CREATE TABLE statements to steal away the PFS_table_share
instance from the dropped table.
  • Loading branch information
robertbindar committed Nov 1, 2019
1 parent d925aec commit 6f86150
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 0 deletions.
16 changes: 16 additions & 0 deletions mysql-test/suite/perfschema/r/misc.result
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,19 @@ truncate performance_schema.events_statements_history 0
select * from t1 3
insert into t1 select RAND()*10000 from t1 6
drop table t1;
#
# MDEV-17896 Assertion `pfs->get_refcount() > 0' failed
# in release_table_share
#
SELECT COUNT(*)<@@performance_schema_max_table_instances FROM
performance_schema.objects_summary_global_by_type WHERE OBJECT_TYPE='TABLE';
COUNT(*)<@@performance_schema_max_table_instances
1
CREATE TABLE t0(a INT);
SELECT * FROM t0;
a
DROP TEMPORARY TABLE IF EXISTS t0;
Warnings:
Note 1051 Unknown table 'test.t0'
FLUSH TABLE t0;
DROP TABLE t0;
48 changes: 48 additions & 0 deletions mysql-test/suite/perfschema/t/misc.test
Original file line number Diff line number Diff line change
Expand Up @@ -222,3 +222,51 @@ insert into t1 select RAND()*10000 from t1;
select sql_text, rows_examined from performance_schema.events_statements_history;
drop table t1;

--echo #
--echo # MDEV-17896 Assertion `pfs->get_refcount() > 0' failed
--echo # in release_table_share
--echo #

# There must be at least one available slot in PFS table_share_array for
# this test to be meaningful. If there are no free slots we must
# restart mysqld, it is the only way to reset PFS table_share_array
let $query= SELECT COUNT(*)<@@performance_schema_max_table_instances FROM
performance_schema.objects_summary_global_by_type WHERE OBJECT_TYPE='TABLE';

let $free_slots_available= `$query`;

if (!$free_slots_available)
{
source include/restart_mysqld.inc;
}
eval $query;

CREATE TABLE t0(a INT);

# TABLE_SHARE must be cached in the table definition cache.
SELECT * FROM t0;

# Dropping t0 using DROP TEMPORARY frees up a slot in table_share_array,
# but the persistent table is not correctly dropped, i.e. TABLE_SHARE::m_psi
# still points to that slot in table_share_array.
DROP TEMPORARY TABLE IF EXISTS t0;

# Try re-using each and every slot in PFS table_share_array. If bug is
# there, we re-use t0 slot.
# The newly created table that re-uses the t0 slot ends up
# resetting the PFS_table_share refcount.
let $i= `SELECT @@performance_schema_max_table_instances`;
disable_query_log;
while ($i)
{
# Memory engine is here to reduce disk IO
eval CREATE TABLE t$i(a INT) ENGINE=MEMORY;
eval DROP TABLE t$i;
dec $i;
}
enable_query_log;

# FLUSH TABLE crashes the server when PFS_table_share is found with
# an unexpected refcount.
FLUSH TABLE t0;
DROP TABLE t0;
7 changes: 7 additions & 0 deletions sql/sql_table.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2418,6 +2418,13 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
ER_BAD_TABLE_ERROR,
ER_THD(thd, ER_BAD_TABLE_ERROR),
tbl_name.c_ptr_safe());

/*
Our job is done here. This statement was added to avoid executing
unnecessary code farther below which in some strange corner cases
caused the server to crash (see MDEV-17896).
*/
continue;
}
else
{
Expand Down

0 comments on commit 6f86150

Please sign in to comment.