From fe2b867b499273adb4a84569340d866deaf27b8e Mon Sep 17 00:00:00 2001 From: Yuchen Pei Date: Wed, 17 May 2023 11:42:57 +1000 Subject: MDEV-22534 PoC fix of segfault during 2nd ps execution In the decorrelating-in transformation, if 1) we are in an ps execution and 2) the equalities picked out for the transformation intersect with the free list, skip the transformation. See also https://jira.mariadb.org/browse/MDEV-22534?focusedCommentId=258728&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-258728 for detailed analysis --- sql/item_subselect.cc | 45 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 3833c48d562..f8f6ea79f8a 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -3099,6 +3099,14 @@ alloc_err: return TRUE; } +bool intersects_free_list(Item *item, THD *thd) +{ + for (const Item *to_find= thd->free_list; to_find; to_find= to_find->next) + if (item->walk(&Item::find_item_processor, 1, (void *) to_find)) + return true; + return false; +} + bool Item_in_subselect::exists2in_processor(void *opt_arg) { THD *thd= (THD *)opt_arg; @@ -3110,23 +3118,30 @@ bool Item_in_subselect::exists2in_processor(void *opt_arg) Query_arena *arena= NULL, backup; DBUG_ENTER("Item_in_subselect::exists2in_processor"); if (!optimizer_flag(thd, OPTIMIZER_SWITCH_EXISTS_TO_IN) || + /* fixme: Not sure this check of top level item etc. is + necessary. */ (!is_top_level_item() && (!upper_not || !upper_not->is_top_level_item())) || - first_select->group_list.elements || - join->having || - !join->conds) + first_select->group_list.elements || /* skip if with group by */ + join->having || /* skip if with having */ + !join->conds) /* skip if no conds */ DBUG_RETURN(FALSE); /* iterate over conditions, and check whether they can be moved out. */ if (find_inner_outer_equalities(&join->conds, eqs)) DBUG_RETURN(FALSE); - arena= thd->activate_stmt_arena_if_needed(&backup); - /* move out the conditions */ - if (left_expr->type() == Item::ROW_ITEM) - for (uint i= 0; i < left_expr->cols(); i++) - outer.push_back(left_expr->element_index(i)); - else - outer.push_back(left_expr); - const uint offset= first_select->item_list.elements; + /* If we are in the execution of a prepared statement, check for + intersection with the free list to avoid segfault. Note that the + check for prepared statement execution is necessary, otherwise it + will likely always find intersection thus abort the + transformation. */ + if (thd->m_statement_state.m_parent_prepared_stmt) + { + for (uint i= 0; i < (uint) eqs.elements(); i++) + { + if (intersects_free_list(*eqs.at(i).eq_ref, thd)) + DBUG_RETURN(FALSE); + } + } /* check that the subquery has only dependencies we are going pull out */ { List unused; @@ -3141,6 +3156,14 @@ bool Item_in_subselect::exists2in_processor(void *opt_arg) DBUG_ASSERT(prm.count >= (uint)eqs.elements()); will_be_correlated= prm.count > (uint)eqs.elements(); } + arena= thd->activate_stmt_arena_if_needed(&backup); + /* construct the items for left_expr */ + if (left_expr->type() == Item::ROW_ITEM) + for (uint i= 0; i < left_expr->cols(); i++) + outer.push_back(left_expr->element_index(i)); + else + outer.push_back(left_expr); + const uint offset= first_select->item_list.elements; for (uint i= 0; i < (uint)eqs.elements(); i++) { Item **eq_ref= eqs.at(i).eq_ref; -- cgit v1.2.1