Details
-
Bug
-
Status: In Review (View Workflow)
-
Critical
-
Resolution: Unresolved
-
10.11, 11.4, 11.8, 12.3, 13.1, 13.2
Description
prepare_fk_prelocking_list() in sql/sql_base.cc allocates a TABLE_LIST for every foreign key that references the table being modified and passes it to TABLE_LIST::init_one_table_for_prelocking() without checking the allocation. When the allocation fails, the server crashes with signal 11 instead of failing the statement. The memory root's error handler has already raised ER_OUT_OF_RESOURCES at that point. Release builds are affected.
On 10.11 and 11.4:
TABLE_LIST *tl= (TABLE_LIST *) thd->alloc(sizeof(TABLE_LIST)); |
tl->init_one_table_for_prelocking(fk->foreign_db,
|
fk->foreign_table,
|
NULL, lock_type,
|
TABLE_LIST::PRELOCK_FK,
|
table_list->belong_to_view, op,
|
&prelocking_ctx->query_tables_last,
|
table_list->for_insert_data);
|
From 11.8 on, the same code reads:
TABLE_LIST *tl= thd->alloc<TABLE_LIST>(1);
|
tl->init_one_table_for_prelocking(fk->foreign_db, fk->foreign_table,
|
NULL, lock_type, TABLE_LIST::PRELOCK_FK, table_list->belong_to_view,
|
op, &prelocking_ctx->query_tables_last, table_list->for_insert_data);
|
add_internal_tables(), a few functions above in the same file, checks the same kind of allocation for NULL and returns an error.
How to repeat
The allocation only fails when the server runs out of memory, so this needs a debug build and a debug hook that makes exactly this allocation fail. The existing simulate_out_of_memory keyword fails the next alloc_root() call and then clears itself, so the hook below sets it right before the allocation (10.11):
DBUG_EXECUTE_IF("fk_prelocking_alloc_fail", |
DBUG_SET("+d,simulate_out_of_memory");); |
TABLE_LIST *tl= (TABLE_LIST *) thd->alloc(sizeof(TABLE_LIST)); |
--source include/have_innodb.inc
|
--source include/have_debug.inc
|
CREATE TABLE p (a INT PRIMARY KEY) ENGINE=InnoDB; |
CREATE TABLE c (a INT, FOREIGN KEY (a) REFERENCES p(a)) ENGINE=InnoDB; |
INSERT INTO p VALUES (1), (2); |
SET debug_dbug= '+d,fk_prelocking_alloc_fail'; |
--error ER_OUT_OF_RESOURCES
|
DELETE FROM p WHERE a = 1; |
SET debug_dbug= ''; |
DROP TABLE c, p; |
Expected: the DELETE fails with ER_OUT_OF_RESOURCES.
Actual:
mysqltest: At line 8: query 'DELETE FROM p WHERE a = 1' failed with wrong errno <Unknown> (2013): 'Lost connection to server during query', instead of ER_OUT_OF_RESOURCES (1041)...
|
 |
[ERROR] mariadbd got signal 11 ;
|
...
|
sql/table.h:2355(TABLE_LIST::reset())
|
sql/table.h:2370(TABLE_LIST::init_one_table(st_mysql_const_lex_string const*, st_mysql_const_lex_string const*, st_mysql_const_lex_string const*, thr_lock_type))
|
sql/table.h:2398(TABLE_LIST::init_one_table_for_prelocking(st_mysql_const_lex_string const*, st_mysql_const_lex_string const*, st_mysql_const_lex_string const*, thr_lock_type, TABLE_LIST::prelocking_types, TABLE_LIST*, unsigned char, TABLE_LIST***, char))
|
sql/sql_base.cc:5192(prepare_fk_prelocking_list(THD*, Query_tables_list*, TABLE_LIST*, bool*, unsigned char))
|
sql/sql_base.cc:5282(DML_prelocking_strategy::handle_table(THD*, Query_tables_list*, TABLE_LIST*, bool*))
|
sql/sql_base.cc:4016(extend_table_list(THD*, TABLE_LIST*, Prelocking_strategy*, bool))
|
sql/sql_base.cc:4322(open_and_process_table(THD*, TABLE_LIST*, unsigned int*, unsigned int, Prelocking_strategy*, bool, Open_table_context*))
|
sql/sql_base.cc:4747(open_tables(THD*, DDL_options_st const&, TABLE_LIST**, unsigned int*, unsigned int, Prelocking_strategy*))
|
sql/sql_base.cc:5781(open_and_lock_tables(THD*, DDL_options_st const&, TABLE_LIST*, bool, unsigned int, Prelocking_strategy*))
|
sql/sql_base.h:519(open_and_lock_tables(THD*, TABLE_LIST*, bool, unsigned int))
|
sql/sql_delete.cc:416(mysql_delete(THD*, TABLE_LIST*, Item*, SQL_I_List<st_order>*, unsigned long long, unsigned long long, select_result*))
|
The line numbers in sql/sql_base.cc are those of 10.11 with the hook added. The code is the same on 10.11, 11.4, 11.8, 12.3, 13.1 and main, apart from the form of the allocation shown above.
Attachments
Issue Links
- relates to
-
MDEV-41434 Missing DBUG_RETURN on error exits of DML_prelocking_strategy::handle_table() and prepare_fk_prelocking_list()
-
- In Review
-