Commit 2be617d8 authored by Alexander Barkov's avatar Alexander Barkov

MDEV-25243 ASAN heap-use-after-free in Item_func_sp::execute_impl upon...

MDEV-25243 ASAN heap-use-after-free in Item_func_sp::execute_impl upon concurrent view DDL and I_S query with view and function
parent 5ba77222
#
# Start of 10.2 tests
#
#
# MDEV-25243 ASAN heap-use-after-free in Item_func_sp::execute_impl upon concurrent view DDL and I_S query with view and function
#
CREATE FUNCTION f1() RETURNS INT RETURN 1;
CREATE VIEW v01 AS SELECT f1();
CREATE VIEW v02 AS SELECT f1();
connect con1,localhost,root,,;
SELECT GET_LOCK('v01',30);
GET_LOCK('v01',30)
1
SELECT GET_LOCK('v02',30);
GET_LOCK('v02',30)
1
connection default;
SELECT * FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA='test'
AND TABLE_NAME LIKE 'v0%'
AND GET_LOCK(TABLE_NAME,30)
AND RELEASE_LOCK(TABLE_NAME)
AND f1()=1
ORDER BY TABLE_NAME;
connection con1;
connection con1;
SELECT RELEASE_LOCK('v01') /* Let the first row evaluate f1 */;
RELEASE_LOCK('v01')
1
CREATE FUNCTION f2() RETURNS INT RETURN 1 /* Invalidate SP cache*/;
SELECT RELEASE_LOCK('v02') /* Let the second row evaluate f1() */;
RELEASE_LOCK('v02')
1
DROP FUNCTION f2;
disconnect con1;
connection default;
SELECT RELEASE_LOCK('v01');
RELEASE_LOCK('v01')
NULL
SELECT RELEASE_LOCK('v02');
RELEASE_LOCK('v02')
NULL
DROP VIEW v01, v02;
DROP FUNCTION f1;
#
# End of 10.2 tests
#
#
# Start of 10.2 tests
#
#
# MDEV-25243 ASAN heap-use-after-free in Item_func_sp::execute_impl upon concurrent view DDL and I_S query with view and function
#
# The originally reported non-deterministic test.
# It did not fail reliably on every run.
CREATE TABLE t (a INT);
INSERT INTO t VALUES (1),(2);
CREATE FUNCTION f(b INT) RETURNS INT RETURN 1;
CREATE VIEW v AS SELECT f(SUM(a)) FROM t;
connect con1,localhost,root,,test;
LOOP
CREATE OR REPLACE VIEW vv AS SELECT 1;
END LOOP $
connection default;
SELECT v.* FROM v JOIN INFORMATION_SCHEMA.TABLES WHERE DATA_LENGTH = -1;
f(SUM(a))
KILL CONID;
disconnect con1;
connection default;
DROP VIEW IF EXISTS vv;
DROP VIEW v;
DROP FUNCTION f;
DROP TABLE t;
# The second test version from the MDEV.
# It failed more reliably, but still was not deterministic.
CREATE FUNCTION f() RETURNS INT RETURN 1;
CREATE VIEW v AS SELECT f() FROM seq_1_to_10;
SELECT * FROM INFORMATION_SCHEMA.TABLES, v;;
connect con1,localhost,root,,;
CREATE VIEW v2 AS SELECT 1;
connection default;
disconnect con1;
DROP VIEW v;
DROP VIEW v2;
DROP FUNCTION f;
# The third test version from the MDEV.
# It failed reliably, and should be deterninistic.
CREATE FUNCTION f1() RETURNS INT RETURN 1;
CREATE VIEW v01 AS SELECT f1();
CREATE VIEW v02 AS SELECT f1();
connect con1,localhost,root,,;
SELECT GET_LOCK('v01',30);
GET_LOCK('v01',30)
1
SELECT GET_LOCK('v02',30);
GET_LOCK('v02',30)
1
connection default;
SELECT * FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA='test'
AND TABLE_NAME LIKE 'v0%'
AND GET_LOCK(TABLE_NAME,30)
AND RELEASE_LOCK(TABLE_NAME)
AND f1()=1
ORDER BY TABLE_NAME;
connection con1;
SELECT RELEASE_LOCK('v01') /* Let the first row evaluate f1 */;
RELEASE_LOCK('v01')
1
CREATE FUNCTION f2() RETURNS INT RETURN 1 /* Invalidate SP cache*/;
SELECT RELEASE_LOCK('v02') /* Let the second row evaluate f1() */;
RELEASE_LOCK('v02')
1
DROP FUNCTION f2;
disconnect con1;
connection default;
TABLE_CATALOG TABLE_SCHEMA TABLE_NAME TABLE_TYPE ENGINE VERSION ROW_FORMAT TABLE_ROWS AVG_ROW_LENGTH DATA_LENGTH MAX_DATA_LENGTH INDEX_LENGTH DATA_FREE AUTO_INCREMENT CREATE_TIME UPDATE_TIME CHECK_TIME TABLE_COLLATION CHECKSUM CREATE_OPTIONS TABLE_COMMENT
def test v01 VIEW NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL VIEW
def test v02 VIEW NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL VIEW
DROP VIEW v01, v02;
DROP FUNCTION f1;
#
# End of 10.2 tests
#
--echo #
--echo # Start of 10.2 tests
--echo #
--echo #
--echo # MDEV-25243 ASAN heap-use-after-free in Item_func_sp::execute_impl upon concurrent view DDL and I_S query with view and function
--echo #
CREATE FUNCTION f1() RETURNS INT RETURN 1;
CREATE VIEW v01 AS SELECT f1();
CREATE VIEW v02 AS SELECT f1();
--connect(con1,localhost,root,,)
SELECT GET_LOCK('v01',30);
SELECT GET_LOCK('v02',30);
--connection default
--send
SELECT * FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA='test'
AND TABLE_NAME LIKE 'v0%'
AND GET_LOCK(TABLE_NAME,30)
AND RELEASE_LOCK(TABLE_NAME)
AND f1()=1
ORDER BY TABLE_NAME;
--connection con1
--connection con1
SELECT RELEASE_LOCK('v01') /* Let the first row evaluate f1 */;
CREATE FUNCTION f2() RETURNS INT RETURN 1 /* Invalidate SP cache*/;
SELECT RELEASE_LOCK('v02') /* Let the second row evaluate f1() */;
DROP FUNCTION f2;
--disconnect con1
--connection default
--disable_result_log
--reap
--enable_result_log
SELECT RELEASE_LOCK('v01');
SELECT RELEASE_LOCK('v02');
DROP VIEW v01, v02;
DROP FUNCTION f1;
--echo #
--echo # End of 10.2 tests
--echo #
--source include/have_sequence.inc
--echo #
--echo # Start of 10.2 tests
--echo #
--echo #
--echo # MDEV-25243 ASAN heap-use-after-free in Item_func_sp::execute_impl upon concurrent view DDL and I_S query with view and function
--echo #
--echo # The originally reported non-deterministic test.
--echo # It did not fail reliably on every run.
CREATE TABLE t (a INT);
INSERT INTO t VALUES (1),(2);
CREATE FUNCTION f(b INT) RETURNS INT RETURN 1;
CREATE VIEW v AS SELECT f(SUM(a)) FROM t;
--connect (con1,localhost,root,,test)
--let $conid= `SELECT CONNECTION_ID()`
--delimiter $
--send
LOOP
CREATE OR REPLACE VIEW vv AS SELECT 1;
END LOOP $
--delimiter ;
--connection default
--disable_warnings
SELECT v.* FROM v JOIN INFORMATION_SCHEMA.TABLES WHERE DATA_LENGTH = -1;
--enable_warnings
# Cleanup
--replace_result $conid CONID
--eval KILL $conid
--disconnect con1
--connection default
DROP VIEW IF EXISTS vv;
DROP VIEW v;
DROP FUNCTION f;
DROP TABLE t;
--echo # The second test version from the MDEV.
--echo # It failed more reliably, but still was not deterministic.
CREATE FUNCTION f() RETURNS INT RETURN 1;
CREATE VIEW v AS SELECT f() FROM seq_1_to_10;
--send SELECT * FROM INFORMATION_SCHEMA.TABLES, v;
--connect(con1,localhost,root,,)
CREATE VIEW v2 AS SELECT 1;
--connection default
--disable_result_log
--reap
--enable_result_log
--disconnect con1
DROP VIEW v;
DROP VIEW v2;
DROP FUNCTION f;
--echo # The third test version from the MDEV.
--echo # It failed reliably, and should be deterninistic.
CREATE FUNCTION f1() RETURNS INT RETURN 1;
CREATE VIEW v01 AS SELECT f1();
CREATE VIEW v02 AS SELECT f1();
--connect(con1,localhost,root,,)
SELECT GET_LOCK('v01',30);
SELECT GET_LOCK('v02',30);
--connection default
--send
SELECT * FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA='test'
AND TABLE_NAME LIKE 'v0%'
AND GET_LOCK(TABLE_NAME,30)
AND RELEASE_LOCK(TABLE_NAME)
AND f1()=1
ORDER BY TABLE_NAME;
--connection con1
SELECT RELEASE_LOCK('v01') /* Let the first row evaluate f1 */;
CREATE FUNCTION f2() RETURNS INT RETURN 1 /* Invalidate SP cache*/;
SELECT RELEASE_LOCK('v02') /* Let the second row evaluate f1() */;
DROP FUNCTION f2;
--disconnect con1
--connection default
--reap
DROP VIEW v01, v02;
DROP FUNCTION f1;
--echo #
--echo # End of 10.2 tests
--echo #
......@@ -313,3 +313,15 @@ sp_cache::cleanup()
{
my_hash_free(&m_hashtable);
}
void Sp_caches::sp_caches_clear()
{
sp_cache_clear(&sp_proc_cache);
sp_cache_clear(&sp_func_cache);
#if MYSQL_VERSION_ID >= 100300
#error Remove the preprocessor condition, !!!but keep the code!!!
sp_cache_clear(&sp_package_spec_cache);
sp_cache_clear(&sp_package_body_cache);
#endif
}
......@@ -806,9 +806,6 @@ THD::THD(my_thread_id id, bool is_wsrep_applier)
(my_hash_get_key) get_var_key,
(my_hash_free_key) free_user_var, HASH_THREAD_SPECIFIC);
sp_proc_cache= NULL;
sp_func_cache= NULL;
/* For user vars replication*/
if (opt_bin_log)
my_init_dynamic_array(&user_var_events,
......@@ -1353,8 +1350,7 @@ void THD::change_user(void)
my_hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
(my_hash_get_key) get_var_key,
(my_hash_free_key) free_user_var, 0);
sp_cache_clear(&sp_proc_cache);
sp_cache_clear(&sp_func_cache);
sp_caches_clear();
}
......@@ -1410,8 +1406,7 @@ void THD::cleanup(void)
#endif /* defined(ENABLED_DEBUG_SYNC) */
my_hash_free(&user_vars);
sp_cache_clear(&sp_proc_cache);
sp_cache_clear(&sp_func_cache);
sp_caches_clear();
auto_inc_intervals_forced.empty();
auto_inc_intervals_in_cur_stmt_for_binlog.empty();
......
......@@ -2116,6 +2116,51 @@ struct wait_for_commit
};
class Sp_caches
{
public:
sp_cache *sp_proc_cache;
sp_cache *sp_func_cache;
#if MYSQL_VERSION_ID >= 100300
#error Remove the preprocessor condition, !!!but keep the code!!!
sp_cache *sp_package_spec_cache;
sp_cache *sp_package_body_cache;
#endif
Sp_caches()
:sp_proc_cache(NULL),
sp_func_cache(NULL)
#if MYSQL_VERSION_ID >= 100300
#error Remove the preprocessor condition, !!!but keep the code!!!
,
sp_package_spec_cache(NULL),
sp_package_body_cache(NULL)
#endif
{ }
~Sp_caches()
{
// All caches must be freed by the caller explicitly
DBUG_ASSERT(sp_proc_cache == NULL);
DBUG_ASSERT(sp_func_cache == NULL);
#if MYSQL_VERSION_ID >= 100300
#error Remove the preprocessor condition, !!!but keep the code!!!
DBUG_ASSERT(sp_package_spec_cache == NULL);
DBUG_ASSERT(sp_package_body_cache == NULL);
#endif
}
void sp_caches_swap(Sp_caches &rhs)
{
swap_variables(sp_cache*, sp_proc_cache, rhs.sp_proc_cache);
swap_variables(sp_cache*, sp_func_cache, rhs.sp_func_cache);
#if MYSQL_VERSION_ID >= 100300
#error Remove the preprocessor condition, !!!but keep the code!!!
swap_variables(sp_cache*, sp_package_spec_cache, rhs.sp_package_spec_cache);
swap_variables(sp_cache*, sp_package_body_cache, rhs.sp_package_body_cache);
#endif
}
void sp_caches_clear();
};
extern "C" void my_message_sql(uint error, const char *str, myf MyFlags);
class THD;
......@@ -2139,7 +2184,8 @@ class THD :public Statement,
*/
public Item_change_list,
public MDL_context_owner,
public Open_tables_state
public Open_tables_state,
public Sp_caches
{
private:
inline bool is_stmt_prepare() const
......@@ -3089,8 +3135,6 @@ class THD :public Statement,
int slave_expected_error;
sp_rcontext *spcont; // SP runtime context
sp_cache *sp_proc_cache;
sp_cache *sp_func_cache;
/** number of name_const() substitutions, see sp_head.cc:subst_spvars() */
uint query_name_consts;
......
......@@ -4907,6 +4907,7 @@ class Warnings_only_error_handler : public Internal_error_handler
int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
{
DBUG_ENTER("get_all_tables");
LEX *lex= thd->lex;
TABLE *table= tables->table;
TABLE_LIST table_acl_check;
......@@ -4923,7 +4924,28 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
#endif
uint table_open_method= tables->table_open_method;
bool can_deadlock;
DBUG_ENTER("get_all_tables");
/*
We're going to open FRM files for tables.
In case of VIEWs that contain stored function calls,
these stored functions will be parsed and put to the SP cache.
Suppose we have a view containing a stored function call:
CREATE VIEW v1 AS SELECT f1() AS c1;
and now we're running:
SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME=f1();
If a parallel thread invalidates the cache,
e.g. by creating or dropping some stored routine,
the SELECT query will re-parse f1() when processing "v1"
and replace the outdated cached version of f1() to a new one.
But the old version of f1() is referenced from the m_sp member
of the Item_func_sp instances used in the WHERE condition.
We cannot destroy it. To avoid such clashes, let's remember
all old routines into a temporary SP cache collection
and process tables with a new empty temporary SP cache collection.
Then restore to the old SP cache collection at the end.
*/
Sp_caches old_sp_caches;
old_sp_caches.sp_caches_swap(*thd);
/*
In cases when SELECT from I_S table being filled by this call is
......@@ -5092,6 +5114,13 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
err:
thd->restore_backup_open_tables_state(&open_tables_state_backup);
/*
Now restore to the saved SP cache collection
and clear the temporary SP cache collection.
*/
old_sp_caches.sp_caches_swap(*thd);
old_sp_caches.sp_caches_clear();
DBUG_RETURN(error);
}
......
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