[MDEV-32466] Potential memory leak on execuing of create view statement Created: 2023-10-13  Updated: 2024-02-08  Resolved: 2023-11-24

Status: Closed
Project: MariaDB Server
Component/s: Prepared Statements, Views
Affects Version/s: 10.4
Fix Version/s: 10.4.33, 10.5.24, 10.6.17, 10.11.7, 11.0.5, 11.1.4, 11.2.3, 11.3.2, 11.4.1

Type: Bug Priority: Critical
Reporter: Dmitry Shulga Assignee: Dmitry Shulga
Resolution: Fixed Votes: 0
Labels: triage

Issue Links:
Blocks
blocks MDEV-30073 Wrong result on 2nd execution of PS f... Stalled
PartOf
is part of MDEV-14959 Control over memory allocated for SP/PS Stalled

 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;
     }



 Comments   
Comment by Dmitry Shulga [ 2023-11-15 ]

The branch for review is bb-10.4-MDEV-32466

Comment by Oleksandr Byelkin [ 2023-11-24 ]

OK to push

Generated at Thu Feb 08 10:31:34 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.