MDEV-17869 AddressSanitizer: use-after-poison in Item_change_list::rollback_item_tree_changes
it's incorrect to use change_item_tree() to replace arguments of top-level AND/OR, because they (arguments) are stored in a List, so a pointer to an argument is in the list_node, and individual list_node's of top-level AND/OR can be deleted in Item_cond::build_equal_items(). In that case rollback_item_tree_changes() will modify the deleted object. Luckily, it's not needed to use change_item_tree() for top-level AND/OR, because the whole top-level item is copied and preserved in prep_where and prep_on, and restored from there. So, just don't. Additionally to the test case in the commit it fixes * ASAN failure of main.opt_tvc --ps * ASAN failure of main.having_cond_pushdown --ps
This commit is contained in:
parent
df82d68421
commit
6cb84346e1
@ -64,3 +64,19 @@ SQRT(?) is not null
|
||||
#
|
||||
# End of 10.3 tests
|
||||
#
|
||||
#
|
||||
# MDEV-17869 AddressSanitizer: use-after-poison in Item_change_list::rollback_item_tree_changes
|
||||
#
|
||||
create table t1 (pk int, v1 varchar(1));
|
||||
insert t1 values (1,'v'),(2,'v'),(3,'c');
|
||||
create table t2 (pk int, v1 varchar(1));
|
||||
insert t2 values (1,'x');
|
||||
create table t3 (pk int, i1 int, v1 varchar(1));
|
||||
insert t3 values (10,8,9);
|
||||
execute immediate 'select straight_join 1 from (t1 join t2 on (t1.v1 = t2.v1))
|
||||
where (3, 6) in (select tc.pk, t3.i1 from (t3 join t1 as tc on (tc.v1 = t3.v1)) having tc.pk > 1 );';
|
||||
1
|
||||
drop table t1, t2, t3;
|
||||
#
|
||||
# End of 10.4 tests
|
||||
#
|
||||
|
@ -52,3 +52,20 @@ execute p1 using 17864960750176564435;
|
||||
--echo #
|
||||
--echo # End of 10.3 tests
|
||||
--echo #
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-17869 AddressSanitizer: use-after-poison in Item_change_list::rollback_item_tree_changes
|
||||
--echo #
|
||||
create table t1 (pk int, v1 varchar(1));
|
||||
insert t1 values (1,'v'),(2,'v'),(3,'c');
|
||||
create table t2 (pk int, v1 varchar(1));
|
||||
insert t2 values (1,'x');
|
||||
create table t3 (pk int, i1 int, v1 varchar(1));
|
||||
insert t3 values (10,8,9);
|
||||
execute immediate 'select straight_join 1 from (t1 join t2 on (t1.v1 = t2.v1))
|
||||
where (3, 6) in (select tc.pk, t3.i1 from (t3 join t1 as tc on (tc.v1 = t3.v1)) having tc.pk > 1 );';
|
||||
drop table t1, t2, t3;
|
||||
|
||||
--echo #
|
||||
--echo # End of 10.4 tests
|
||||
--echo #
|
||||
|
10
sql/item.h
10
sql/item.h
@ -1868,6 +1868,11 @@ public:
|
||||
}
|
||||
|
||||
virtual Item* transform(THD *thd, Item_transformer transformer, uchar *arg);
|
||||
virtual Item* top_level_transform(THD *thd, Item_transformer transformer,
|
||||
uchar *arg)
|
||||
{
|
||||
return transform(thd, transformer, arg);
|
||||
}
|
||||
|
||||
/*
|
||||
This function performs a generic "compilation" of the Item tree.
|
||||
@ -1892,6 +1897,11 @@ public:
|
||||
return ((this->*transformer) (thd, arg_t));
|
||||
return 0;
|
||||
}
|
||||
virtual Item* top_level_compile(THD *thd, Item_analyzer analyzer, uchar **arg_p,
|
||||
Item_transformer transformer, uchar *arg_t)
|
||||
{
|
||||
return compile(thd, analyzer, arg_p, transformer, arg_t);
|
||||
}
|
||||
|
||||
virtual void traverse_cond(Cond_traverser traverser,
|
||||
void *arg, traverse_order order)
|
||||
|
@ -5032,7 +5032,8 @@ bool Item_cond::walk(Item_processor processor, bool walk_subquery, void *arg)
|
||||
Item returned as the result of transformation of the root node
|
||||
*/
|
||||
|
||||
Item *Item_cond::transform(THD *thd, Item_transformer transformer, uchar *arg)
|
||||
Item *Item_cond::do_transform(THD *thd, Item_transformer transformer, uchar *arg,
|
||||
bool toplevel)
|
||||
{
|
||||
DBUG_ASSERT(!thd->stmt_arena->is_stmt_prepare());
|
||||
|
||||
@ -5040,7 +5041,8 @@ Item *Item_cond::transform(THD *thd, Item_transformer transformer, uchar *arg)
|
||||
Item *item;
|
||||
while ((item= li++))
|
||||
{
|
||||
Item *new_item= item->transform(thd, transformer, arg);
|
||||
Item *new_item= toplevel ? item->top_level_transform(thd, transformer, arg)
|
||||
: item->transform(thd, transformer, arg);
|
||||
if (!new_item)
|
||||
return 0;
|
||||
|
||||
@ -5050,7 +5052,9 @@ Item *Item_cond::transform(THD *thd, Item_transformer transformer, uchar *arg)
|
||||
Otherwise we'll be allocating a lot of unnecessary memory for
|
||||
change records at each execution.
|
||||
*/
|
||||
if (new_item != item)
|
||||
if (toplevel)
|
||||
*li.ref()= new_item;
|
||||
else if (new_item != item)
|
||||
thd->change_item_tree(li.ref(), new_item);
|
||||
}
|
||||
return Item_func::transform(thd, transformer, arg);
|
||||
@ -5081,8 +5085,8 @@ Item *Item_cond::transform(THD *thd, Item_transformer transformer, uchar *arg)
|
||||
Item returned as the result of transformation of the root node
|
||||
*/
|
||||
|
||||
Item *Item_cond::compile(THD *thd, Item_analyzer analyzer, uchar **arg_p,
|
||||
Item_transformer transformer, uchar *arg_t)
|
||||
Item *Item_cond::do_compile(THD *thd, Item_analyzer analyzer, uchar **arg_p,
|
||||
Item_transformer transformer, uchar *arg_t, bool toplevel)
|
||||
{
|
||||
if (!(this->*analyzer)(arg_p))
|
||||
return 0;
|
||||
@ -5097,7 +5101,11 @@ Item *Item_cond::compile(THD *thd, Item_analyzer analyzer, uchar **arg_p,
|
||||
*/
|
||||
uchar *arg_v= *arg_p;
|
||||
Item *new_item= item->compile(thd, analyzer, &arg_v, transformer, arg_t);
|
||||
if (new_item && new_item != item)
|
||||
if (!new_item || new_item == item)
|
||||
continue;
|
||||
if (toplevel)
|
||||
*li.ref()= new_item;
|
||||
else
|
||||
thd->change_item_tree(li.ref(), new_item);
|
||||
}
|
||||
return Item_func::transform(thd, transformer, arg_t);
|
||||
|
@ -3018,12 +3018,30 @@ public:
|
||||
bool top_level() { return abort_on_null; }
|
||||
void copy_andor_arguments(THD *thd, Item_cond *item);
|
||||
bool walk(Item_processor processor, bool walk_subquery, void *arg);
|
||||
Item *transform(THD *thd, Item_transformer transformer, uchar *arg);
|
||||
Item *do_transform(THD *thd, Item_transformer transformer, uchar *arg, bool toplevel);
|
||||
Item *transform(THD *thd, Item_transformer transformer, uchar *arg)
|
||||
{
|
||||
return do_transform(thd, transformer, arg, 0);
|
||||
}
|
||||
Item *top_level_transform(THD *thd, Item_transformer transformer, uchar *arg)
|
||||
{
|
||||
return do_transform(thd, transformer, arg, 1);
|
||||
}
|
||||
void traverse_cond(Cond_traverser, void *arg, traverse_order order);
|
||||
void neg_arguments(THD *thd);
|
||||
Item* propagate_equal_fields(THD *, const Context &, COND_EQUAL *);
|
||||
Item *do_compile(THD *thd, Item_analyzer analyzer, uchar **arg_p,
|
||||
Item_transformer transformer, uchar *arg_t, bool toplevel);
|
||||
Item *compile(THD *thd, Item_analyzer analyzer, uchar **arg_p,
|
||||
Item_transformer transformer, uchar *arg_t);
|
||||
Item_transformer transformer, uchar *arg_t)
|
||||
{
|
||||
return do_compile(thd, analyzer, arg_p, transformer, arg_t, 0);
|
||||
}
|
||||
Item* top_level_compile(THD *thd, Item_analyzer analyzer, uchar **arg_p,
|
||||
Item_transformer transformer, uchar *arg_t)
|
||||
{
|
||||
return do_compile(thd, analyzer, arg_p, transformer, arg_t, 1);
|
||||
}
|
||||
bool eval_not_null_tables(void *opt_arg);
|
||||
Item *build_clone(THD *thd);
|
||||
bool excl_dep_on_table(table_map tab_map);
|
||||
|
@ -10042,9 +10042,8 @@ st_select_lex::build_pushable_cond_for_having_pushdown(THD *thd, Item *cond)
|
||||
*/
|
||||
if (cond->get_extraction_flag() == FULL_EXTRACTION_FL)
|
||||
{
|
||||
Item *result= cond->transform(thd,
|
||||
&Item::multiple_equality_transformer,
|
||||
(uchar *)this);
|
||||
Item *result= cond->top_level_transform(thd,
|
||||
&Item::multiple_equality_transformer, (uchar *)this);
|
||||
if (!result)
|
||||
return true;
|
||||
if (result->type() == Item::COND_ITEM &&
|
||||
|
@ -28295,11 +28295,11 @@ void JOIN::cache_const_exprs()
|
||||
return;
|
||||
|
||||
if (conds)
|
||||
conds->compile(thd, &Item::cache_const_expr_analyzer, &analyzer_arg,
|
||||
conds->top_level_compile(thd, &Item::cache_const_expr_analyzer, &analyzer_arg,
|
||||
&Item::cache_const_expr_transformer, &cache_flag);
|
||||
cache_flag= FALSE;
|
||||
if (having)
|
||||
having->compile(thd, &Item::cache_const_expr_analyzer,
|
||||
having->top_level_compile(thd, &Item::cache_const_expr_analyzer,
|
||||
&analyzer_arg, &Item::cache_const_expr_transformer, &cache_flag);
|
||||
|
||||
for (JOIN_TAB *tab= first_depth_first_tab(this); tab;
|
||||
@ -28308,7 +28308,7 @@ void JOIN::cache_const_exprs()
|
||||
if (*tab->on_expr_ref)
|
||||
{
|
||||
cache_flag= FALSE;
|
||||
(*tab->on_expr_ref)->compile(thd, &Item::cache_const_expr_analyzer,
|
||||
(*tab->on_expr_ref)->top_level_compile(thd, &Item::cache_const_expr_analyzer,
|
||||
&analyzer_arg, &Item::cache_const_expr_transformer, &cache_flag);
|
||||
}
|
||||
}
|
||||
@ -29365,7 +29365,6 @@ select_handler *SELECT_LEX::find_select_handler(THD *thd)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@} (end of group Query_Optimizer)
|
||||
*/
|
||||
|
@ -1121,12 +1121,10 @@ bool JOIN::transform_in_predicates_into_in_subq(THD *thd)
|
||||
{
|
||||
select_lex->parsing_place= IN_WHERE;
|
||||
conds=
|
||||
conds->transform(thd,
|
||||
&Item::in_predicate_to_in_subs_transformer,
|
||||
(uchar*) 0);
|
||||
conds->top_level_transform(thd,
|
||||
&Item::in_predicate_to_in_subs_transformer, 0);
|
||||
if (!conds)
|
||||
DBUG_RETURN(true);
|
||||
select_lex->prep_where= conds ? conds->copy_andor_structure(thd) : 0;
|
||||
select_lex->where= conds;
|
||||
}
|
||||
|
||||
@ -1141,13 +1139,10 @@ bool JOIN::transform_in_predicates_into_in_subq(THD *thd)
|
||||
if (table->on_expr)
|
||||
{
|
||||
table->on_expr=
|
||||
table->on_expr->transform(thd,
|
||||
&Item::in_predicate_to_in_subs_transformer,
|
||||
(uchar*) 0);
|
||||
table->on_expr->top_level_transform(thd,
|
||||
&Item::in_predicate_to_in_subs_transformer, 0);
|
||||
if (!table->on_expr)
|
||||
DBUG_RETURN(true);
|
||||
table->prep_on_expr= table->on_expr ?
|
||||
table->on_expr->copy_andor_structure(thd) : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user