Uploaded image for project: 'MariaDB Server'
  1. MariaDB Server
  2. MDEV-35565

Server crashes simplifying group by <subquery>

Details

    • Bug
    • Status: Stalled (View Workflow)
    • Critical
    • Resolution: Unresolved
    • 10.5.27, 10.6.20, 10.11.10, 11.4.4, 11.7.1
    • 10.5, 10.6, 10.11, 11.4
    • Optimizer
    • None

    Description

      running the following

      create table t1 (a int) engine=myisam;
      insert into t1 values (1),(2);
      --echo t1 not const
       
      create table t2 (b int) engine=myisam;
       
      select * from t1, t2 where b in
      ( select (select a from t1 order by b) as d from t1 group by (select d) );
       
      drop table t1, t2;
      

      causes the server to crash in st_select_lex::optimize_unflattened_subqueries()
      JOIN::optimize_stage2 on the join for

      /* select#2 */ select (subquery#3) AS d from t1 group by (subquery#4) having <cache>(t1.a) = <ref_null_helper>((subquery#3))
      

      attempting to update the group list

      (SUBSELECT_ITEM*)((select `d`))
      

      Attachments

        Issue Links

          Activity

            There is MDEV-30756 which looks much like this.

            elenst Elena Stepanova added a comment - There is MDEV-30756 which looks much like this.
            Johnston Rex Johnston added a comment -

            preliminary analysis

            select * from t1, t2 where b in
            ( select (select a from t1 order by b) as d from t1 group by (select d) );
            

            we crash during update_depend_map_for_order() processing the group by clause for select #2.
            order->item[0] is (Item_subselect) (select `d`)
            Our depend_map is initialized as order->item[0]->used_tables()

               for (; order ; order=order->next) 
               {  
                 table_map depend_map;  
                 order->item[0]->update_used_tables();  
                 order->depend_map=depend_map=order->item[0]->used_tables(); 
            

            in gdb we observe that this is 0b10, which cannot be correct as the Item_field d is an outer reference.
            We would expect to see the OUTER_BIT_TABLE_REF bit set in this map, but in the call to update_used_tables() on the prior line, this bit isn't set.

            We can see why when we examine how upper_refs for this Item_subselect is processed.
            Unsurprisingly we see it contains an Item_ref wrapper around the Item_field d.

            In Item_subselect::recalc_used_tables we call

                      // Now, iterate over fields and collect used_tables() attribute:
                      Field_fixer fixer;
                      fixer.used_tables= 0;
                      fixer.new_parent= new_parent;
                      upper->item->walk(&Item::enumerate_field_refs_processor, 0, &fixer);
                      used_tables_cache |= fixer.used_tables;
            

            here we walk through the item tree attached to upper->item (Item_ref d) looking for anything that is an Item_field and collecting a bitmap of all the used_tables.
            The problem is that it is an indiscriminate walk, anything that is an Item_field has it's bitmap added.
            Item_ref d is a wrapper around Item_subselect (select `test`.`t1`.`a` from `test`.`t1` order by `test`.`t2`.`b`)
            and we hit field t2.b, which is NOT a part of this select, it's bitmap refers to select #1.
            It's bitmap is assigned to Item_subselect::used_tables_cache and used as a loop counter in update_depend_map_for_order()
            which walks off the end of the number of joined tables, accessing uninitialised memory.

            We need to make the method visit_field() in our Field_fixer class more discriminatory.

            class Field_fixer: public Field_enumerator
            {
            public:
              table_map used_tables; /* Collect used_tables here */
              st_select_lex *new_parent; /* Select we're in */
              void visit_field(Item_field *item) override
              {
                //for (TABLE_LIST *tbl= new_parent->leaf_tables; tbl; tbl= tbl->next_local)
                //{
                //  if (tbl->table == field->table)
                //  {
                    used_tables|= item->field->table->map;
                //    return;
                //  }
                //}
                //used_tables |= OUTER_REF_TABLE_BIT;
              }
            };
            

            we note some interesting commented-out lines.

            Johnston Rex Johnston added a comment - preliminary analysis select * from t1, t2 where b in ( select ( select a from t1 order by b) as d from t1 group by ( select d) ); we crash during update_depend_map_for_order() processing the group by clause for select #2. order->item [0] is (Item_subselect) (select `d`) Our depend_map is initialized as order->item [0] ->used_tables() for (; order ; order=order->next) { table_map depend_map; order->item[0]->update_used_tables(); order->depend_map=depend_map=order->item[0]->used_tables(); in gdb we observe that this is 0b10, which cannot be correct as the Item_field d is an outer reference. We would expect to see the OUTER_BIT_TABLE_REF bit set in this map, but in the call to update_used_tables() on the prior line, this bit isn't set. We can see why when we examine how upper_refs for this Item_subselect is processed. Unsurprisingly we see it contains an Item_ref wrapper around the Item_field d . In Item_subselect::recalc_used_tables we call // Now, iterate over fields and collect used_tables() attribute: Field_fixer fixer; fixer.used_tables= 0; fixer.new_parent= new_parent; upper->item->walk(&Item::enumerate_field_refs_processor, 0, &fixer); used_tables_cache |= fixer.used_tables; here we walk through the item tree attached to upper->item (Item_ref d ) looking for anything that is an Item_field and collecting a bitmap of all the used_tables. The problem is that it is an indiscriminate walk, anything that is an Item_field has it's bitmap added. Item_ref d is a wrapper around Item_subselect (select `test`.`t1`.`a` from `test`.`t1` order by `test`.`t2`.`b`) and we hit field t2.b, which is NOT a part of this select, it's bitmap refers to select #1. It's bitmap is assigned to Item_subselect::used_tables_cache and used as a loop counter in update_depend_map_for_order() which walks off the end of the number of joined tables, accessing uninitialised memory. We need to make the method visit_field() in our Field_fixer class more discriminatory. class Field_fixer: public Field_enumerator { public : table_map used_tables; /* Collect used_tables here */ st_select_lex *new_parent; /* Select we're in */ void visit_field(Item_field *item) override { //for (TABLE_LIST *tbl= new_parent->leaf_tables; tbl; tbl= tbl->next_local) //{ // if (tbl->table == field->table) // { used_tables|= item->field->table->map; // return; // } //} //used_tables |= OUTER_REF_TABLE_BIT; } }; we note some interesting commented-out lines.
            Johnston Rex Johnston added a comment -

            further simplification

            select * from t1, t2 where b > any ( select b as d from t1 group by (select d) );
            

            causes the same issue. d is resolved as "b" in the select list of select #2. When we walk this item during Item_subselect::recalc_used_tables we encounter and utilize an Item_field from select #1.

            Johnston Rex Johnston added a comment - further simplification select * from t1, t2 where b > any ( select b as d from t1 group by ( select d) ); causes the same issue. d is resolved as "b" in the select list of select #2. When we walk this item during Item_subselect::recalc_used_tables we encounter and utilize an Item_field from select #1.

            People

              Johnston Rex Johnston
              Johnston Rex Johnston
              Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

                Created:
                Updated:

                Git Integration

                  Error rendering 'com.xiplink.jira.git.jira_git_plugin:git-issue-webpanel'. Please contact your Jira administrators.