Skip to content

Commit e4a466d

Browse files
MDEV-35816 ASAN use-after-poison in st_select_lex::print
Semi-joins with CTEs as the derived table will leave dangling pointers to the JOIN instance, from the corresponding SELECT_LEX instance, after first execution has completed. Clean these up during statement reinitialization, before subsequent executions occur.
1 parent 8c7c144 commit e4a466d

File tree

3 files changed

+69
-0
lines changed

3 files changed

+69
-0
lines changed

mysql-test/main/prepare.result

+25
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,28 @@ drop table t1,t2;
115115
#
116116
# End of 10.6 tests
117117
#
118+
#
119+
# MDEV-35816 ASAN use-after-poison in st_select_lex::print
120+
#
121+
CREATE TABLE t1 (a INT);
122+
INSERT INTO t1 (a) VALUES (1),(2),(3),(4),(5);
123+
SET SESSION optimizer_trace = 'enabled=on';
124+
PREPARE stmt FROM 'SELECT STRAIGHT_JOIN * FROM t1 WHERE a IN (WITH cte AS (SELECT a FROM t1) SELECT * FROM cte)';
125+
EXECUTE stmt;
126+
a
127+
1
128+
2
129+
3
130+
4
131+
5
132+
EXECUTE stmt;
133+
a
134+
1
135+
2
136+
3
137+
4
138+
5
139+
DROP TABLE t1;
140+
#
141+
# End of 10.11 tests
142+
#

mysql-test/main/prepare.test

+15
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,18 @@ drop table t1,t2;
105105
--echo #
106106
--echo # End of 10.6 tests
107107
--echo #
108+
109+
--echo #
110+
--echo # MDEV-35816 ASAN use-after-poison in st_select_lex::print
111+
--echo #
112+
CREATE TABLE t1 (a INT);
113+
INSERT INTO t1 (a) VALUES (1),(2),(3),(4),(5);
114+
SET SESSION optimizer_trace = 'enabled=on';
115+
PREPARE stmt FROM 'SELECT STRAIGHT_JOIN * FROM t1 WHERE a IN (WITH cte AS (SELECT a FROM t1) SELECT * FROM cte)';
116+
EXECUTE stmt;
117+
EXECUTE stmt;
118+
DROP TABLE t1;
119+
120+
--echo #
121+
--echo # End of 10.11 tests
122+
--echo #

sql/sql_prepare.cc

+29
Original file line numberDiff line numberDiff line change
@@ -3134,6 +3134,33 @@ void mysql_sql_stmt_execute_immediate(THD *thd)
31343134
}
31353135

31363136

3137+
/**
3138+
Cleanup destroyed JOIN instances from derived tables' SELECT_LEX instances
3139+
before second execution by setting the SELECT_LEX instance's JOIN pointer
3140+
to nullptr.
3141+
*/
3142+
static void cleanup_joins(SELECT_LEX *sl)
3143+
{
3144+
TABLE_LIST *tl;
3145+
for (tl= sl->table_list.first; tl; tl= tl->next_local)
3146+
{
3147+
// Must be a derived view without a recursive table reference.
3148+
if (!tl->is_view_or_derived() || tl->is_with_table_recursive_reference())
3149+
continue;
3150+
3151+
SELECT_LEX_UNIT *unit= tl->get_unit();
3152+
if (!unit)
3153+
continue;
3154+
3155+
// For each query on the unit, disassociate the JOIN instance. It
3156+
// should have already been destroyed by this point. There's no way
3157+
// to assert that because it will result in EXC_BAD_ACCESS.
3158+
for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select())
3159+
sl->join= nullptr;
3160+
}
3161+
}
3162+
3163+
31373164
/**
31383165
Reinit prepared statement/stored procedure before execution.
31393166
@@ -3238,6 +3265,8 @@ void reinit_stmt_before_use(THD *thd, LEX *lex)
32383265
}
32393266
if (sl->changed_elements & TOUCHED_SEL_DERIVED)
32403267
{
3268+
cleanup_joins(sl);
3269+
32413270
#ifdef DBUG_ASSERT_EXISTS
32423271
bool res=
32433272
#endif

0 commit comments

Comments
 (0)