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

Crash when pushing condition into view defined as union

Details

    Description

      This test case cases a crash of the server:

      create table t1 (
         n int,
         lv varchar(31) charset latin1,
         mv varchar(31) charset utf8mb3
      ) engine=myisam;
      insert into t1 values (1,'aa','xxx'), ('2','bb','yyy'), (3,'cc','zzz');
      create view v1 as
      select case when n=1 then lv when n=2 then mv else NULL end as r from t1 
      union
      select 'a'; 
       
      prepare stmt from "select * from v1 where r < 'x'";
      execute stmt;
      

      sql/signal_handler.cc:238(handle_fatal_signal)[0x5619d7043b23]
      /lib64/libpthread.so.0(+0xf890)[0x7f08d7e88890]
      sql/item.cc:3411(Item_field::used_tables() const)[0x5619d706f433]
      sql/item.h:5171(Used_tables_and_const_cache::used_tables_and_const_cache_join(Item const*))[0x5619d6c63f7d]
      sql/item.h:5178(Used_tables_and_const_cache::used_tables_and_const_cache_update_and_join(Item*))[0x5619d6c64002]
      sql/item.h:5187(Used_tables_and_const_cache::used_tables_and_const_cache_update_and_join(unsigned int, Item**))[0x5619d6c64044]
      sql/item_func.h:161(Item_func::update_used_tables())[0x5619d6c656c0]
      sql/item.h:7677(Item_direct_ref_to_item::update_used_tables())[0x5619d708c6eb]
      sql/item.h:5177(Used_tables_and_const_cache::used_tables_and_const_cache_update_and_join(Item*))[0x5619d6c63fef]
      sql/item.h:5187(Used_tables_and_const_cache::used_tables_and_const_cache_update_and_join(unsigned int, Item**))[0x5619d6c64044]
      sql/item_func.h:161(Item_func::update_used_tables())[0x5619d6c656c0]
      sql/sql_lex.cc:4670(st_select_lex::update_used_tables())[0x5619d6cc64b1]
      sql/sql_select.cc:1927(JOIN::optimize_inner())[0x5619d6d44b40]
      sql/sql_select.cc:1690(JOIN::optimize())[0x5619d6d43f6a]
      sql/sql_union.cc:1490(st_select_lex_unit::optimize())[0x5619d6e0f9b2]
      sql/sql_derived.cc:995(mysql_derived_optimize(THD*, LEX*, TABLE_LIST*))[0x5619d6c9f894]
      sql/sql_derived.cc:200(mysql_handle_single_derived(LEX*, TABLE_LIST*, unsigned int))[0x5619d6c9d4c4]
      sql/sql_select.cc:2180(JOIN::optimize_inner())[0x5619d6d45cd9]
      sql/sql_select.cc:1690(JOIN::optimize())[0x5619d6d43f6a]
      sql/sql_select.cc:4797(mysql_select(THD*, TABLE_LIST*, unsigned int, List<Item>&, Item*, unsigned int, st_order*, st_order*, Item*, st_order*, unsigned long long, select_result*, st_select_lex_unit*, st_select_lex*))[0x5619d6d4f817]
      sql/sql_select.cc:454(handle_select(THD*, LEX*, select_result*, unsigned long))[0x5619d6d3ec32]
      sql/sql_parse.cc:6463(execute_sqlcom_select(THD*, TABLE_LIST*))[0x5619d6d02e00]
      sql/sql_parse.cc:3966(mysql_execute_command(THD*))[0x5619d6cf97c3]
      sql/sql_prepare.cc:5024(Prepared_statement::execute(String*, bool))[0x5619d6d2863c]
      sql/sql_prepare.cc:4493(Prepared_statement::execute_loop(String*, bool, unsigned char*, unsigned char*))[0x5619d6d269e3]
      sql/sql_prepare.cc:3578(mysql_sql_stmt_execute(THD*))[0x5619d6d242c3]
      sql/sql_parse.cc:3983(mysql_execute_command(THD*))[0x5619d6cf9808]
      sql/sql_parse.cc:7998(mysql_parse(THD*, char*, unsigned int, Parser_state*, bool, bool))[0x5619d6d06d66]
      sql/sql_parse.cc:1860(dispatch_command(enum_server_command, THD*, char*, unsigned int, bool, bool))[0x5619d6cf3383]
      sql/sql_parse.cc:1379(do_command(THD*))[0x5619d6cf1ba7]
      sql/sql_connect.cc:1420(do_handle_one_connection(CONNECT*))[0x5619d6e8bf11]
      sql/sql_connect.cc:1325(handle_one_connection)[0x5619d6e8bc6d]
      perfschema/pfs.cc:1871(pfs_spawn_thread)[0x5619d73ed20c]
      /lib64/libpthread.so.0(+0x80a4)[0x7f08d7e810a4]
      /lib64/libc.so.6(clone+0x6d)[0x7f08d72b904d]
       
      Trying to get some variables.
      Some pointers may be invalid and cause the dump to abort.
      Query (0x7f08c00145b8): select * from v1 where r < 'x'
      

      Attachments

        Activity

          The following patch fixes the problem:

          diff --git a/sql/item.h b/sql/item.h
          index 31568aa..1e0caaa 100644
          --- a/sql/item.h
          +++ b/sql/item.h
          @@ -7647,7 +7647,7 @@ class Item_direct_ref_to_item : public Item_direct_ref
             Item *get_tmp_table_item(THD *thd)
             { return m_item->get_tmp_table_item(thd); }
             Item *get_copy(THD *thd)
          -  { return m_item->get_copy(thd); }
          +  { return get_item_copy<Item_direct_ref_to_item>(thd, this); }
             COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
                                     bool link_item_fields,
                                     COND_EQUAL **cond_equal_ref)
          @@ -7715,7 +7715,20 @@ class Item_direct_ref_to_item : public Item_direct_ref
             bool excl_dep_on_grouping_fields(st_select_lex *sel)
             { return m_item->excl_dep_on_grouping_fields(sel); }
             bool is_expensive() { return m_item->is_expensive(); }
          -  Item* build_clone(THD *thd) { return get_copy(thd); }
          +  void set_item(Item *item) { m_item= item; }
          +  Item *build_clone(THD *thd)
          +  {
          +    Item *clone_item= m_item->build_clone(thd);
          +    if (clone_item)
          +    {
          +      Item_direct_ref_to_item *copy= (Item_direct_ref_to_item *) get_copy(thd);
          +      if (!copy)
          +        return 0;
          +      copy->set_item(clone_item);
          +      return copy;
          +    }
          +    return 0;
          +  }
          

          igor Igor Babaev (Inactive) added a comment - The following patch fixes the problem: diff --git a/sql/item.h b/sql/item.h index 31568aa..1e0caaa 100644 --- a/sql/item.h +++ b/sql/item.h @@ -7647,7 +7647,7 @@ class Item_direct_ref_to_item : public Item_direct_ref Item *get_tmp_table_item(THD *thd) { return m_item->get_tmp_table_item(thd); } Item *get_copy(THD *thd) - { return m_item->get_copy(thd); } + { return get_item_copy<Item_direct_ref_to_item>(thd, this); } COND *build_equal_items(THD *thd, COND_EQUAL *inherited, bool link_item_fields, COND_EQUAL **cond_equal_ref) @@ -7715,7 +7715,20 @@ class Item_direct_ref_to_item : public Item_direct_ref bool excl_dep_on_grouping_fields(st_select_lex *sel) { return m_item->excl_dep_on_grouping_fields(sel); } bool is_expensive() { return m_item->is_expensive(); } - Item* build_clone(THD *thd) { return get_copy(thd); } + void set_item(Item *item) { m_item= item; } + Item *build_clone(THD *thd) + { + Item *clone_item= m_item->build_clone(thd); + if (clone_item) + { + Item_direct_ref_to_item *copy= (Item_direct_ref_to_item *) get_copy(thd); + if (!copy) + return 0; + copy->set_item(clone_item); + return copy; + } + return 0; + }

          This bug was introduced with the commit

          commit 37a316c01d778a62a056d5d20110ef18bb55975e
          Author:	Dmitry Shulga <dmitry.shulga@mariadb.com>  Fri Dec  9 06:10:25 2022
          Committer:	Sergei Golubchik <serg@mariadb.org>  Sun Jan  1 15:04:03 2023
          

          The patch added the class Item_direct_ref_to_item with such implementation of virtual methods get_copy() and build_clone()

          +  Item *get_copy(THD *thd)
          +  { return m_item->get_copy(thd); }
           
          +  Item* build_clone(THD *thd) { return get_copy(thd); }
          

          As a result whenever we use an object of the type Item_direct_ref_to_item r within an expression and for this expression build_clone() is called the sub-item starting with r is not actually cloned as it shares items it refers to with the cloned expression. When the clone is cleaned up the shared items of the original expression are also cleaned up. After this any traversal of the original expression may cause a crash. In the above test case the crash happened at an attempt to traverse the original cloned item when calling SELECT_LEX::update_used_tables().
          In the above test case build_clone() is called when creating an item to be pushed into a view. Yet the method can be called in other situations.

          igor Igor Babaev (Inactive) added a comment - This bug was introduced with the commit commit 37a316c01d778a62a056d5d20110ef18bb55975e Author: Dmitry Shulga <dmitry.shulga@mariadb.com> Fri Dec 9 06:10:25 2022 Committer: Sergei Golubchik <serg@mariadb.org> Sun Jan 1 15:04:03 2023 The patch added the class Item_direct_ref_to_item with such implementation of virtual methods get_copy() and build_clone() + Item *get_copy(THD *thd) + { return m_item->get_copy(thd); }   + Item* build_clone(THD *thd) { return get_copy(thd); } As a result whenever we use an object of the type Item_direct_ref_to_item r within an expression and for this expression build_clone() is called the sub-item starting with r is not actually cloned as it shares items it refers to with the cloned expression. When the clone is cleaned up the shared items of the original expression are also cleaned up. After this any traversal of the original expression may cause a crash. In the above test case the crash happened at an attempt to traverse the original cloned item when calling SELECT_LEX::update_used_tables(). In the above test case build_clone() is called when creating an item to be pushed into a view. Yet the method can be called in other situations.

          Note that objects of the type Item_direct_ref_to_item in the current code can appear only at the first execution of prepared statement. They never appear if the query is executed directly.

          igor Igor Babaev (Inactive) added a comment - Note that objects of the type Item_direct_ref_to_item in the current code can appear only at the first execution of prepared statement. They never appear if the query is executed directly.

          From: IgorBabaev
          To: commits@mariadb.org
          Subject: [Commits] 60c1b15: MDEV-31102 Crash when pushing condition into view defined as union
          Date: Fri, 21 Apr 2023 13:46:14 -0700 (PDT)
          

          serg Sergei Golubchik added a comment - From: IgorBabaev To: commits@mariadb.org Subject: [Commits] 60c1b15: MDEV-31102 Crash when pushing condition into view defined as union Date: Fri, 21 Apr 2023 13:46:14 -0700 (PDT)

          60c1b15 is ok to push

          serg Sergei Golubchik added a comment - 60c1b15 is ok to push

          A fix for this bug was pushed into 10.4. The fix should be merged upstream as it is.

          igor Igor Babaev (Inactive) added a comment - A fix for this bug was pushed into 10.4. The fix should be merged upstream as it is.

          People

            igor Igor Babaev (Inactive)
            igor Igor Babaev (Inactive)
            Votes:
            1 Vote for this issue
            Watchers:
            6 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Git Integration

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