Commit 0fb0d9a9 authored by Jon Olav Hauglid's avatar Jon Olav Hauglid

Bug #57130 crash in Item_field::print during SHOW CREATE TABLE or VIEW

This crash could happen if SHOW CREATE VIEW indirectly failed to open a
view due to failures to open underlying tables (or functions). Several
such errors were hidden and converted to ER_VIEW_INVALID warnings to
prevent exposing details of underlying tables for which the user have
no privileges.

However, with the changes introduced by the patch for Bug#52044,
failing to open a view will cause opened tables, views and functions
to be closed. Since the errors causing these failures were converted
to warnings, SHOW CREATE VIEW would try to continue. This made it
possible to try to access memory that had been freed, causing a crash.

This patch fixes the problem by not closing opened tables, views and
functions in these cases. This allows SHOW CREATE VIEW to continue
and also prevents it from accessing freed memory.

Test case added to lock_sync.test.
parent 70d86bd1
...@@ -738,3 +738,38 @@ SET DEBUG_SYNC= 'now SIGNAL release_thrlock'; ...@@ -738,3 +738,38 @@ SET DEBUG_SYNC= 'now SIGNAL release_thrlock';
# Connection default # Connection default
DROP TABLE t1; DROP TABLE t1;
SET DEBUG_SYNC= 'RESET'; SET DEBUG_SYNC= 'RESET';
#
# Bug#57130 crash in Item_field::print during SHOW CREATE TABLE or VIEW
#
DROP TABLE IF EXISTS t1;
DROP VIEW IF EXISTS v1;
DROP FUNCTION IF EXISTS f1;
CREATE TABLE t1(a INT);
CREATE FUNCTION f1() RETURNS INTEGER RETURN 1;
CREATE VIEW v1 AS SELECT * FROM t1 WHERE f1() = 1;
DROP FUNCTION f1;
# Connection con1
SET DEBUG_SYNC= 'open_tables_after_open_and_process_table SIGNAL opened WAIT_FOR dropped EXECUTE 2';
# Sending:
SHOW CREATE VIEW v1;
# Connection con2
SET DEBUG_SYNC= 'now WAIT_FOR opened';
SET DEBUG_SYNC= 'now SIGNAL dropped';
SET DEBUG_SYNC= 'now WAIT_FOR opened';
# Sending:
FLUSH TABLES;
# Connection default
# Waiting for FLUSH TABLES to be blocked.
SET DEBUG_SYNC= 'now SIGNAL dropped';
# Connection con1
# Reaping: SHOW CREATE VIEW v1
View Create View character_set_client collation_connection
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a` from `t1` where (`f1`() = 1) latin1 latin1_swedish_ci
Warnings:
Warning 1356 View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
# Connection con2
# Reaping: FLUSH TABLES
# Connection default
SET DEBUG_SYNC= 'RESET';
DROP VIEW v1;
DROP TABLE t1;
...@@ -1078,6 +1078,65 @@ DROP TABLE t1; ...@@ -1078,6 +1078,65 @@ DROP TABLE t1;
SET DEBUG_SYNC= 'RESET'; SET DEBUG_SYNC= 'RESET';
--echo #
--echo # Bug#57130 crash in Item_field::print during SHOW CREATE TABLE or VIEW
--echo #
--disable_warnings
DROP TABLE IF EXISTS t1;
DROP VIEW IF EXISTS v1;
DROP FUNCTION IF EXISTS f1;
--enable_warnings
CREATE TABLE t1(a INT);
CREATE FUNCTION f1() RETURNS INTEGER RETURN 1;
CREATE VIEW v1 AS SELECT * FROM t1 WHERE f1() = 1;
DROP FUNCTION f1;
connect(con2, localhost, root);
--echo # Connection con1
connect (con1, localhost, root);
# Need to trigger this sync point at least twice in order to
# get valgrind test failures without the patch
SET DEBUG_SYNC= 'open_tables_after_open_and_process_table SIGNAL opened WAIT_FOR dropped EXECUTE 2';
--echo # Sending:
--send SHOW CREATE VIEW v1
--echo # Connection con2
connection con2;
SET DEBUG_SYNC= 'now WAIT_FOR opened';
SET DEBUG_SYNC= 'now SIGNAL dropped';
SET DEBUG_SYNC= 'now WAIT_FOR opened';
--echo # Sending:
--send FLUSH TABLES
--echo # Connection default
connection default;
--echo # Waiting for FLUSH TABLES to be blocked.
let $wait_condition= SELECT COUNT(*)=1 FROM information_schema.processlist
WHERE state= 'Waiting for table flush' AND info= 'FLUSH TABLES';
--source include/wait_condition.inc
SET DEBUG_SYNC= 'now SIGNAL dropped';
--echo # Connection con1
connection con1;
--echo # Reaping: SHOW CREATE VIEW v1
--reap
--echo # Connection con2
connection con2;
--echo # Reaping: FLUSH TABLES
--reap
--echo # Connection default
connection default;
SET DEBUG_SYNC= 'RESET';
DROP VIEW v1;
DROP TABLE t1;
disconnect con1;
disconnect con2;
# Check that all connections opened by test cases in this file are really # Check that all connections opened by test cases in this file are really
# gone so execution of other tests won't be affected by their presence. # gone so execution of other tests won't be affected by their presence.
--source include/wait_until_count_sessions.inc --source include/wait_until_count_sessions.inc
...@@ -29,6 +29,8 @@ ...@@ -29,6 +29,8 @@
#include "repl_failsafe.h" #include "repl_failsafe.h"
#include "sql_parse.h" // check_access, check_table_access #include "sql_parse.h" // check_access, check_table_access
#include "sql_partition.h" // partition_element #include "sql_partition.h" // partition_element
#include "sql_derived.h" // mysql_derived_prepare,
// mysql_handle_derived,
#include "sql_db.h" // check_db_dir_existence, load_db_opt_by_name #include "sql_db.h" // check_db_dir_existence, load_db_opt_by_name
#include "sql_time.h" // interval_type_to_name #include "sql_time.h" // interval_type_to_name
#include "tztime.h" // struct Time_zone #include "tztime.h" // struct Time_zone
...@@ -683,11 +685,18 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) ...@@ -683,11 +685,18 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
thd->lex->view_prepare_mode= TRUE; thd->lex->view_prepare_mode= TRUE;
{ {
/*
Use open_tables() directly rather than open_normal_and_derived_tables().
This ensures that close_thread_tables() is not called if open tables fails
and the error is ignored. This allows us to handle broken views nicely.
*/
uint counter;
Show_create_error_handler view_error_suppressor(thd, table_list); Show_create_error_handler view_error_suppressor(thd, table_list);
thd->push_internal_handler(&view_error_suppressor); thd->push_internal_handler(&view_error_suppressor);
bool open_error= bool open_error=
open_normal_and_derived_tables(thd, table_list, open_tables(thd, &table_list, &counter,
MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL); MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL) ||
mysql_handle_derived(thd->lex, &mysql_derived_prepare);
thd->pop_internal_handler(); thd->pop_internal_handler();
if (open_error && (thd->killed || thd->is_error())) if (open_error && (thd->killed || thd->is_error()))
goto exit; goto exit;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment