diff --git a/mysql-test/suite/merge/merge.result b/mysql-test/suite/merge/merge.result index 19d948615bb47..2550199a24a5a 100644 --- a/mysql-test/suite/merge/merge.result +++ b/mysql-test/suite/merge/merge.result @@ -4031,3 +4031,31 @@ UPDATE v1 SET a=0; DROP VIEW v1; DROP TABLE t1; # End of 11.1 tests +# +# MDEV-38474 Double free or corruption, ASAN heap-use-after-free in st_join_table::cleanup +# +# Test case 1, fails on 10.11+ +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (b INT); +CREATE TABLE t3 (c INT); +# Inserts are optional, fails with and without data +INSERT INTO t1 VALUES (1),(2); +INSERT INTO t2 VALUES (3),(4); +INSERT INTO t3 VALUES (5),(6); +EXPLAIN SELECT * FROM t1 WHERE a IN (SELECT b FROM t2 WHERE a IN ((SELECT c FROM t3 WHERE FALSE HAVING c < 0))); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +3 MATERIALIZED NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +DROP TABLE t1, t2, t3; +# Test case 2, fails on 11.4 but not on 10.11 +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (b INT); +CREATE TABLE t3 (c INT); +CREATE TABLE t4 (d INT PRIMARY KEY); +SET SQL_SAFE_UPDATES=1; +UPDATE t1 STRAIGHT_JOIN t2 SET a = 89 WHERE 9 IN (SELECT c FROM t3 WHERE c IN (SELECT MAX(d) FROM t4)); +ERROR HY000: You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column +DROP TABLE t1, t2, t3, t4; +# +# End of 11.4 tests +# diff --git a/mysql-test/suite/merge/merge.test b/mysql-test/suite/merge/merge.test index 4b752fcdaffd7..6e95dfe2b4017 100644 --- a/mysql-test/suite/merge/merge.test +++ b/mysql-test/suite/merge/merge.test @@ -2965,3 +2965,37 @@ DROP VIEW v1; DROP TABLE t1; --echo # End of 11.1 tests + +--echo # +--echo # MDEV-38474 Double free or corruption, ASAN heap-use-after-free in st_join_table::cleanup +--echo # + +--echo # Test case 1, fails on 10.11+ +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (b INT); +CREATE TABLE t3 (c INT); + +--echo # Inserts are optional, fails with and without data +INSERT INTO t1 VALUES (1),(2); +INSERT INTO t2 VALUES (3),(4); +INSERT INTO t3 VALUES (5),(6); + +EXPLAIN SELECT * FROM t1 WHERE a IN (SELECT b FROM t2 WHERE a IN ((SELECT c FROM t3 WHERE FALSE HAVING c < 0))); + +DROP TABLE t1, t2, t3; + +--echo # Test case 2, fails on 11.4 but not on 10.11 +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (b INT); +CREATE TABLE t3 (c INT); +CREATE TABLE t4 (d INT PRIMARY KEY); + +SET SQL_SAFE_UPDATES=1; +--error ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE +UPDATE t1 STRAIGHT_JOIN t2 SET a = 89 WHERE 9 IN (SELECT c FROM t3 WHERE c IN (SELECT MAX(d) FROM t4)); + +DROP TABLE t1, t2, t3, t4; + +--echo # +--echo # End of 11.4 tests +--echo # diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index e3daab28648ba..83d318adc0ab1 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -3004,7 +3004,7 @@ void st_select_lex_node::init_query_common() into the front of the stranded_clean_list: before: root -> B -> A after: root -> this -> B -> A - During cleanup, the stranded units are cleaned in FIFO order. + During cleanup, the stranded units are cleaned in LIFO order (parent-first). */ void st_select_lex_unit::remember_my_cleanup() { diff --git a/sql/sql_union.cc b/sql/sql_union.cc index c9eebc7c05e55..21d5fa677f6a7 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -2688,8 +2688,6 @@ bool st_select_lex_unit::exec_recursive() bool st_select_lex_unit::cleanup() { - cleanup_stranded_units(); - bool error= 0; DBUG_ENTER("st_select_lex_unit::cleanup"); @@ -2778,6 +2776,11 @@ bool st_select_lex_unit::cleanup() delete pushdown_unit; pushdown_unit= nullptr; + /* + Cleanup stranded units only after this unit has completed its own + cleanup, ensuring a parent-first (LIFO) cleanup order for merged tables. + */ + cleanup_stranded_units(); DBUG_RETURN(error); }