Skip to content

Commit d46c1c5

Browse files
Dyre TjeldvollDyre Tjeldvoll
Dyre Tjeldvoll
authored and
Dyre Tjeldvoll
committed
BUG#19894987: HANDLE_FATAL_SIGNAL (SIG=11) IN HA_INDEX_OR_RND_END | SQL/HANDLER.H:1999
Execution of certain BINLOG statements while having temporary tables open by HANDLER statements caused server crash. Execution of BINLOG statements for Start/Format_description events may close the connection's temporary tables. If a handler had been associated with a temporary table, the BINLOG statement's call to close_temporary_tables() would result in dangling pointers to the now freed TABLE in thd->handler_table_hash. Similarly, a dangling pointer would also be left if there was a lock on the temporary table. Running with valgrind showed that freed memory was being accessed. Solution: Properly close handlers and remove locks associated with temporary tables being closed by the BINLOG statement.
1 parent 29e683f commit d46c1c5

File tree

3 files changed

+59
-4
lines changed

3 files changed

+59
-4
lines changed

sql/sql_base.cc

+11-4
Original file line numberDiff line numberDiff line change
@@ -1728,13 +1728,18 @@ bool close_temporary_tables(THD *thd)
17281728
DBUG_ASSERT(!thd->slave_thread ||
17291729
thd->system_thread != SYSTEM_THREAD_SLAVE_WORKER);
17301730

1731+
/*
1732+
Ensure we don't have open HANDLERs for tables we are about to close.
1733+
This is necessary when close_temporary_tables() is called as part
1734+
of execution of BINLOG statement (e.g. for format description event).
1735+
*/
1736+
mysql_ha_rm_temporary_tables(thd);
17311737
if (!mysql_bin_log.is_open())
17321738
{
1733-
TABLE *tmp_next;
1734-
for (table= thd->temporary_tables; table; table= tmp_next)
1739+
for (TABLE *t= thd->temporary_tables; t; t= t->next)
17351740
{
1736-
tmp_next= table->next;
1737-
close_temporary(table, 1, 1);
1741+
mysql_lock_remove(thd, thd->lock, t);
1742+
close_temporary(t, 1, 1);
17381743
}
17391744

17401745
thd->temporary_tables= 0;
@@ -1743,6 +1748,7 @@ bool close_temporary_tables(THD *thd)
17431748

17441749
DBUG_RETURN(FALSE);
17451750
}
1751+
17461752
/*
17471753
We are about to generate DROP TEMPORARY TABLE statements for all
17481754
the left out temporary tables. If GTID_NEXT is set (e.g. if user
@@ -1866,6 +1872,7 @@ bool close_temporary_tables(THD *thd)
18661872
}
18671873

18681874
next= table->next;
1875+
mysql_lock_remove(thd, thd->lock, table);
18691876
close_temporary(table, 1, 1);
18701877
}
18711878
thd->clear_error();

sql/sql_handler.cc

+47
Original file line numberDiff line numberDiff line change
@@ -986,6 +986,53 @@ void mysql_ha_flush(THD *thd)
986986
}
987987

988988

989+
/**
990+
Remove temporary tables from the HANDLER's hash table. The reason
991+
for having a separate function, rather than calling
992+
mysql_ha_rm_tables() is that it is not always feasible (e.g. in
993+
close_temporary_tables) to obtain a TABLE_LIST containing the
994+
temporary tables.
995+
996+
@See close_temporary_tables
997+
@param thd Thread identifier.
998+
*/
999+
void mysql_ha_rm_temporary_tables(THD *thd)
1000+
{
1001+
DBUG_ENTER("mysql_ha_rm_temporary_tables");
1002+
1003+
TABLE_LIST *tmp_handler_tables= NULL;
1004+
for (uint i= 0; i < thd->handler_tables_hash.records; i++)
1005+
{
1006+
TABLE_LIST *handler_table= reinterpret_cast<TABLE_LIST*>
1007+
(my_hash_element(&thd->handler_tables_hash, i));
1008+
1009+
if (handler_table->table && handler_table->table->s->tmp_table)
1010+
{
1011+
handler_table->next_local= tmp_handler_tables;
1012+
tmp_handler_tables= handler_table;
1013+
}
1014+
}
1015+
1016+
while (tmp_handler_tables)
1017+
{
1018+
TABLE_LIST *nl= tmp_handler_tables->next_local;
1019+
mysql_ha_close_table(thd, tmp_handler_tables);
1020+
my_hash_delete(&thd->handler_tables_hash, (uchar*) tmp_handler_tables);
1021+
tmp_handler_tables= nl;
1022+
}
1023+
1024+
/*
1025+
Mark MDL_context as no longer breaking protocol if we have
1026+
closed last HANDLER.
1027+
*/
1028+
if (thd->handler_tables_hash.records == 0)
1029+
{
1030+
thd->mdl_context.set_needs_thr_lock_abort(FALSE);
1031+
}
1032+
DBUG_VOID_RETURN;
1033+
}
1034+
1035+
9891036
/**
9901037
Close all HANDLER's tables.
9911038

sql/sql_handler.h

+1
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ class Sql_cmd_handler_close : public Sql_cmd
124124
void mysql_ha_flush(THD *thd);
125125
void mysql_ha_flush_tables(THD *thd, TABLE_LIST *all_tables);
126126
void mysql_ha_rm_tables(THD *thd, TABLE_LIST *tables);
127+
void mysql_ha_rm_temporary_tables(THD *thd);
127128
void mysql_ha_cleanup(THD *thd);
128129
void mysql_ha_set_explicit_lock_duration(THD *thd);
129130

0 commit comments

Comments
 (0)