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

Potential memory leak on execuing of create view statement

    XMLWordPrintable

Details

    Description

      sp_update_stmt_used_routines() passes thd->stmt_arena to the function sp_add_used_routine() that uses it to allocate an instance of the class Sroutine_hash_entry and places the pointer to the allocated memory into the list prelocking_ctx->sroutines_list

      On finishing execution of SP/PS its memory root is marked as read only. In case the same SP/PS is run the second time it crashes on attempt to allocate a memory on the statement's mem_root marked as read_only. The stack trace where assertion hits is below:

      Item_func_sp::val_str() [sql/item_func.h:3327]
       Item_func_sp::execute() [sql/item_func.cc:6470]
        Item_sp::execute() [sql/item.cc:2761]
         Item_sp::execute_impl [sql/item.cc:2846]
          sp_head::execute_function [sql/sp_head.cc:2016] <<=== (*)
           sp_head::rcontext_create [sql/sp_head.cc:1763]
            sp_head::rcontext_create [sql/sp_head.cc:1735]
             sp_rcontext::create [sql/sp_rcontext.cc:110]
              sql/sp_rcontext.cc:380 [sp_rcontext::init_var_items]
               Table_ident::resolve_table_rowtype_ref [sql/sp_rcontext.cc:308]
                open_tables_only_view_structure [sql/sql_base.cc:5456]
                 open_normal_and_derived_tables [sql/sql_base.cc:5406]
                  open_tables [sql/sql_base.h:259]
                   open_tables [sql/sql_base.cc:4397]
                    open_and_process_table [sql/sql_base.cc:4008]
                     DML_prelocking_strategy::handle_view [sql/sql_base.cc:4966]
                      sp_update_stmt_used_routines [sql/sp.cc:2722]
                       sp_add_used_routine [sql/sp.cc:2298]
                        Query_arena::alloc [sql/sql_class.h:1121]
                         alloc_root [mysys/my_alloc.c:228]
      

      Please draw your attention that before sp_head::rcontext_create() is called at the frame marked with in the above mentioned stack trace the active arena is switched to the call arena at line switched with (**)

        if (!(*func_ctx))
        {
          thd->set_n_backup_active_arena(call_arena, &backup_arena);  <<<== (**)
       
          if (!(*func_ctx= rcontext_create(thd, return_value_fld, argp, argcount)))
          {
            thd->restore_active_arena(call_arena, &backup_arena);
            err_status= TRUE;
            goto err_with_cleanup;
          }
       
          /*
            We have to switch temporarily back to callers arena/memroot.
            Function arguments belong to the caller and so the may reference
            memory which they will allocate during calculation long after
            this function call will be finished (e.g. in Item::cleanup()).
          */
          thd->restore_active_arena(call_arena, &backup_arena);
        }
      

      To fix the issue the following modification is performed:

      --- a/sql/sp.cc
      +++ b/sql/sp.cc
      @@ -2720,7 +2720,7 @@ void sp_update_stmt_used_routines(THD *thd, Query_tables_list *prelocking_ctx,
                                         TABLE_LIST *belong_to_view)
       {
         for (Sroutine_hash_entry *rt= src->first; rt; rt= rt->next)
      -    (void)sp_add_used_routine(prelocking_ctx, thd->stmt_arena,
      +    (void)sp_add_used_routine(prelocking_ctx, thd,
                                     &rt->mdl_request.key, rt->m_handler,
                                     belong_to_view);
       }
      

      That is, it is proposed to make any allocation of a memory performed by the function sp_add_used_routine and its callees on current active memory root instead of using statement's memory root.

      But doing this way the server hits another crash that happens on the second execution of the same SP/PS and that caused by referencing to a memory de-allocated on first time execution of SP/PS completes.

      That happens inside the function reinit_stmt_before_use()

      void reinit_stmt_before_use(THD *thd, LEX *lex)
      {
      ...
        /* Reset MDL tickets for procedures/functions */
        for (Sroutine_hash_entry *rt=
               (Sroutine_hash_entry*)thd->lex->sroutines_list.first;
             rt; rt= rt->next)
          rt->mdl_request.ticket= NULL; <<=== Access the memory referenced by rt that was released on finishing of first SP/PS invocation
      ...
      }
      

      Use case that forces the test main.sp to fail it the following one:

      --echo #
      --echo # MDEV-23902: MariaDB crash on calling function
      --echo #
       
      --delimiter |
      CREATE FUNCTION f2 () RETURNS VARCHAR(1)
      BEGIN
              DECLARE rec1 ROW TYPE OF v1;
              SELECT z INTO rec1 FROM v1;
              RETURN 1;
      END|
      --delimiter ;
       
      CREATE FUNCTION f1 () RETURNS VARCHAR(1) RETURN f2() ;
      CREATE FUNCTION f3 () RETURNS VARCHAR(1) RETURN f_not_exist();
      CREATE VIEW v1 AS SELECT f3() z;
       
      --error ER_VIEW_INVALID
      SELECT f1();
       
      --echo # Check that crash doen't happen in case f3 completes with success.
      DROP FUNCTION f3;
      CREATE FUNCTION f3 () RETURNS VARCHAR(1) RETURN '!';
       
      SELECT f1();
      

      The following prerequisite patch must be applied to re-produce the issue described above:

      --- a/sql/sql_view.cc
      +++ b/sql/sql_view.cc
      @@ -1686,9 +1686,10 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
               For suid views prepare a security context for checking underlying
               objects of the view.
             */
      -      if (!(table->view_sctx= (Security_context *)
      -            thd->stmt_arena->calloc(sizeof(Security_context))))
      +      table->view_sctx= (Security_context *)alloc_root(thd->mem_root,sizeof(Security_context));
      +      if (!table->view_sctx)
               goto err;
      +      bzero(table->view_sctx, sizeof(Security_context));
             security_ctx= table->view_sctx;
           }
      

      Attachments

        Issue Links

          Activity

            People

              shulga Dmitry Shulga
              shulga Dmitry Shulga
              Votes:
              0 Vote for this issue
              Watchers:
              3 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.