mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
MDEV-29624 MDEV-29655 Fix ASAN errors on pushdown of derived table
Deallocation of TABLE_LIST::dt_handler and TABLE_LIST::pushdown_derived was performed in multiple places if code. This not only made the code more difficult to maintain but also led to memory leaks and ASAN heap-use-after-free errors. This commit puts deallocation of TABLE_LIST::dt_handler and TABLE_LIST::pushdown_derived to the single point - JOIN::cleanup()
This commit is contained in:
@ -469,6 +469,51 @@ a
|
|||||||
1
|
1
|
||||||
2
|
2
|
||||||
3
|
3
|
||||||
|
#
|
||||||
|
# MDEV-29655: ASAN heap-use-after-free in
|
||||||
|
# Pushdown_derived::Pushdown_derived
|
||||||
|
#
|
||||||
|
connection slave;
|
||||||
|
DROP TABLE IF EXISTS federated.t1;
|
||||||
|
CREATE TABLE federated.t1 (
|
||||||
|
id int(20) NOT NULL,
|
||||||
|
name varchar(16) NOT NULL default ''
|
||||||
|
)
|
||||||
|
DEFAULT CHARSET=latin1;
|
||||||
|
INSERT INTO federated.t1 VALUES
|
||||||
|
(3,'xxx'), (7,'yyy'), (4,'xxx'), (1,'zzz'), (5,'yyy');
|
||||||
|
connection master;
|
||||||
|
DROP TABLE IF EXISTS federated.t1;
|
||||||
|
CREATE TABLE federated.t1 (
|
||||||
|
id int(20) NOT NULL,
|
||||||
|
name varchar(16) NOT NULL default ''
|
||||||
|
)
|
||||||
|
ENGINE="FEDERATED" DEFAULT CHARSET=latin1
|
||||||
|
CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1';
|
||||||
|
use federated;
|
||||||
|
SELECT * FROM (SELECT * FROM (SELECT * FROM (SELECT * FROM t1 where id=3) dt3
|
||||||
|
WHERE id=2) dt2) dt;
|
||||||
|
id name
|
||||||
|
connection slave;
|
||||||
|
CREATE TABLE federated.t10 (a INT,b INT);
|
||||||
|
CREATE TABLE federated.t11 (a INT, b INT);
|
||||||
|
INSERT INTO federated.t10 VALUES (1,1),(2,2);
|
||||||
|
INSERT INTO federated.t11 VALUES (1,1),(2,2);
|
||||||
|
connection master;
|
||||||
|
CREATE TABLE federated.t10
|
||||||
|
ENGINE="FEDERATED" DEFAULT CHARSET=latin1
|
||||||
|
CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t10';
|
||||||
|
CREATE TABLE federated.t11
|
||||||
|
ENGINE="FEDERATED" DEFAULT CHARSET=latin1
|
||||||
|
CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t11';
|
||||||
|
use federated;
|
||||||
|
SELECT * FROM t10 LEFT JOIN
|
||||||
|
(t11, (SELECT * FROM (SELECT * FROM (SELECT * FROM t1 where id=3) dt3
|
||||||
|
WHERE id=2) dt2) dt
|
||||||
|
) ON t10.a=t11.a;
|
||||||
|
a b a b id name
|
||||||
|
1 1 NULL NULL NULL NULL
|
||||||
|
2 2 NULL NULL NULL NULL
|
||||||
set global federated_pushdown=0;
|
set global federated_pushdown=0;
|
||||||
connection master;
|
connection master;
|
||||||
DROP TABLE IF EXISTS federated.t1;
|
DROP TABLE IF EXISTS federated.t1;
|
||||||
|
@ -267,7 +267,6 @@ INSERT INTO federated.t2
|
|||||||
SELECT * FROM (SELECT * FROM federated.t1 LIMIT 70000) dt;
|
SELECT * FROM (SELECT * FROM federated.t1 LIMIT 70000) dt;
|
||||||
SELECT COUNT(DISTINCT a) FROM federated.t2;
|
SELECT COUNT(DISTINCT a) FROM federated.t2;
|
||||||
|
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
--echo # MDEV-29640 FederatedX does not properly handle pushdown
|
--echo # MDEV-29640 FederatedX does not properly handle pushdown
|
||||||
--echo # in case of difference in local and remote table names
|
--echo # in case of difference in local and remote table names
|
||||||
@ -314,6 +313,64 @@ CREATE TABLE federated.t3 (a INT)
|
|||||||
EXPLAIN SELECT * FROM federated.t3;
|
EXPLAIN SELECT * FROM federated.t3;
|
||||||
SELECT * FROM federated.t3;
|
SELECT * FROM federated.t3;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-29655: ASAN heap-use-after-free in
|
||||||
|
--echo # Pushdown_derived::Pushdown_derived
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
connection slave;
|
||||||
|
DROP TABLE IF EXISTS federated.t1;
|
||||||
|
|
||||||
|
CREATE TABLE federated.t1 (
|
||||||
|
id int(20) NOT NULL,
|
||||||
|
name varchar(16) NOT NULL default ''
|
||||||
|
)
|
||||||
|
DEFAULT CHARSET=latin1;
|
||||||
|
|
||||||
|
INSERT INTO federated.t1 VALUES
|
||||||
|
(3,'xxx'), (7,'yyy'), (4,'xxx'), (1,'zzz'), (5,'yyy');
|
||||||
|
|
||||||
|
connection master;
|
||||||
|
DROP TABLE IF EXISTS federated.t1;
|
||||||
|
|
||||||
|
--replace_result $SLAVE_MYPORT SLAVE_PORT
|
||||||
|
eval
|
||||||
|
CREATE TABLE federated.t1 (
|
||||||
|
id int(20) NOT NULL,
|
||||||
|
name varchar(16) NOT NULL default ''
|
||||||
|
)
|
||||||
|
ENGINE="FEDERATED" DEFAULT CHARSET=latin1
|
||||||
|
CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1';
|
||||||
|
|
||||||
|
use federated;
|
||||||
|
SELECT * FROM (SELECT * FROM (SELECT * FROM (SELECT * FROM t1 where id=3) dt3
|
||||||
|
WHERE id=2) dt2) dt;
|
||||||
|
|
||||||
|
connection slave;
|
||||||
|
CREATE TABLE federated.t10 (a INT,b INT);
|
||||||
|
CREATE TABLE federated.t11 (a INT, b INT);
|
||||||
|
INSERT INTO federated.t10 VALUES (1,1),(2,2);
|
||||||
|
INSERT INTO federated.t11 VALUES (1,1),(2,2);
|
||||||
|
|
||||||
|
connection master;
|
||||||
|
--replace_result $SLAVE_MYPORT SLAVE_PORT
|
||||||
|
eval
|
||||||
|
CREATE TABLE federated.t10
|
||||||
|
ENGINE="FEDERATED" DEFAULT CHARSET=latin1
|
||||||
|
CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t10';
|
||||||
|
|
||||||
|
--replace_result $SLAVE_MYPORT SLAVE_PORT
|
||||||
|
eval
|
||||||
|
CREATE TABLE federated.t11
|
||||||
|
ENGINE="FEDERATED" DEFAULT CHARSET=latin1
|
||||||
|
CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t11';
|
||||||
|
|
||||||
|
use federated;
|
||||||
|
SELECT * FROM t10 LEFT JOIN
|
||||||
|
(t11, (SELECT * FROM (SELECT * FROM (SELECT * FROM t1 where id=3) dt3
|
||||||
|
WHERE id=2) dt2) dt
|
||||||
|
) ON t10.a=t11.a;
|
||||||
|
|
||||||
set global federated_pushdown=0;
|
set global federated_pushdown=0;
|
||||||
|
|
||||||
source include/federated_cleanup.inc;
|
source include/federated_cleanup.inc;
|
||||||
|
@ -44,11 +44,6 @@ Pushdown_derived::Pushdown_derived(TABLE_LIST *tbl, derived_handler *h)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Pushdown_derived::~Pushdown_derived()
|
|
||||||
{
|
|
||||||
delete handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int Pushdown_derived::execute()
|
int Pushdown_derived::execute()
|
||||||
{
|
{
|
||||||
|
@ -1000,11 +1000,7 @@ bool mysql_derived_optimize(THD *thd, LEX *lex, TABLE_LIST *derived)
|
|||||||
/* Create an object for execution of the query specifying the table */
|
/* Create an object for execution of the query specifying the table */
|
||||||
if (!(derived->pushdown_derived=
|
if (!(derived->pushdown_derived=
|
||||||
new (thd->mem_root) Pushdown_derived(derived, derived->dt_handler)))
|
new (thd->mem_root) Pushdown_derived(derived, derived->dt_handler)))
|
||||||
{
|
|
||||||
delete derived->dt_handler;
|
|
||||||
derived->dt_handler= NULL;
|
|
||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lex->current_select= first_select;
|
lex->current_select= first_select;
|
||||||
@ -1229,7 +1225,6 @@ bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived)
|
|||||||
/* Execute the query that specifies the derived table by a foreign engine */
|
/* Execute the query that specifies the derived table by a foreign engine */
|
||||||
res= derived->pushdown_derived->execute();
|
res= derived->pushdown_derived->execute();
|
||||||
unit->executed= true;
|
unit->executed= true;
|
||||||
delete derived->pushdown_derived;
|
|
||||||
DBUG_RETURN(res);
|
DBUG_RETURN(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,6 +68,7 @@
|
|||||||
#include "select_handler.h"
|
#include "select_handler.h"
|
||||||
#include "my_json_writer.h"
|
#include "my_json_writer.h"
|
||||||
#include "opt_trace.h"
|
#include "opt_trace.h"
|
||||||
|
#include "derived_handler.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
A key part number that means we're using a fulltext scan.
|
A key part number that means we're using a fulltext scan.
|
||||||
@ -14086,6 +14087,7 @@ void JOIN::cleanup(bool full)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
free_pushdown_handlers(*join_list);
|
||||||
}
|
}
|
||||||
/* Restore ref array to original state */
|
/* Restore ref array to original state */
|
||||||
if (current_ref_ptrs != items0)
|
if (current_ref_ptrs != items0)
|
||||||
@ -14096,6 +14098,32 @@ void JOIN::cleanup(bool full)
|
|||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Clean up all derived pushdown handlers in this join.
|
||||||
|
|
||||||
|
@detail
|
||||||
|
Note that dt_handler is picked at the prepare stage (as opposed
|
||||||
|
to optimization stage where one could expect this).
|
||||||
|
Because of that, we have to do cleanups in this function that is called
|
||||||
|
from JOIN::cleanup() and not in JOIN_TAB::cleanup.
|
||||||
|
*/
|
||||||
|
void JOIN::free_pushdown_handlers(List<TABLE_LIST>& join_list)
|
||||||
|
{
|
||||||
|
List_iterator<TABLE_LIST> li(join_list);
|
||||||
|
TABLE_LIST *table_ref;
|
||||||
|
while ((table_ref= li++))
|
||||||
|
{
|
||||||
|
if (table_ref->nested_join)
|
||||||
|
free_pushdown_handlers(table_ref->nested_join->join_list);
|
||||||
|
if (table_ref->pushdown_derived)
|
||||||
|
{
|
||||||
|
delete table_ref->pushdown_derived;
|
||||||
|
table_ref->pushdown_derived= NULL;
|
||||||
|
}
|
||||||
|
delete table_ref->dt_handler;
|
||||||
|
table_ref->dt_handler= NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Remove the following expressions from ORDER BY and GROUP BY:
|
Remove the following expressions from ORDER BY and GROUP BY:
|
||||||
@ -27400,12 +27428,6 @@ bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
|
|||||||
result, unit, first);
|
result, unit, first);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unit->derived && unit->derived->pushdown_derived)
|
|
||||||
{
|
|
||||||
delete unit->derived->pushdown_derived;
|
|
||||||
unit->derived->pushdown_derived= NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
DBUG_RETURN(res || thd->is_error());
|
DBUG_RETURN(res || thd->is_error());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1840,6 +1840,7 @@ private:
|
|||||||
bool add_having_as_table_cond(JOIN_TAB *tab);
|
bool add_having_as_table_cond(JOIN_TAB *tab);
|
||||||
bool make_aggr_tables_info();
|
bool make_aggr_tables_info();
|
||||||
bool add_fields_for_current_rowid(JOIN_TAB *cur, List<Item> *fields);
|
bool add_fields_for_current_rowid(JOIN_TAB *cur, List<Item> *fields);
|
||||||
|
void free_pushdown_handlers(List<TABLE_LIST>& join_list);
|
||||||
};
|
};
|
||||||
|
|
||||||
enum enum_with_bush_roots { WITH_BUSH_ROOTS, WITHOUT_BUSH_ROOTS};
|
enum enum_with_bush_roots { WITH_BUSH_ROOTS, WITHOUT_BUSH_ROOTS};
|
||||||
@ -2507,8 +2508,6 @@ public:
|
|||||||
|
|
||||||
Pushdown_derived(TABLE_LIST *tbl, derived_handler *h);
|
Pushdown_derived(TABLE_LIST *tbl, derived_handler *h);
|
||||||
|
|
||||||
~Pushdown_derived();
|
|
||||||
|
|
||||||
int execute();
|
int execute();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user