From 5064750fbf9bafc9efbb84c431e9c92fa8e039be Mon Sep 17 00:00:00 2001 From: Dmitry Shulga Date: Fri, 24 Nov 2023 16:26:12 +0700 Subject: [PATCH] MDEV-32466: Potential memory leak on executing of create view statement This patch is actually follow-up for the task MDEV-23902: MariaDB crash on calling function to use correct query arena for a statement. In case invocation of a function is in progress use its call arena, else use current query arena that can be either a statement or a regular query arena. --- mysql-test/main/ps_mem_leaks.result | 22 ++++++++++++++++++++++ mysql-test/main/ps_mem_leaks.test | 28 ++++++++++++++++++++++++++++ sql/sp.cc | 3 ++- sql/sql_base.cc | 2 +- sql/sql_class.h | 11 +++++++++++ sql/sql_lex.cc | 5 +++-- sql/sql_view.cc | 2 +- 7 files changed, 68 insertions(+), 5 deletions(-) diff --git a/mysql-test/main/ps_mem_leaks.result b/mysql-test/main/ps_mem_leaks.result index 6a1155dbafee3..90e003f8e5c23 100644 --- a/mysql-test/main/ps_mem_leaks.result +++ b/mysql-test/main/ps_mem_leaks.result @@ -57,4 +57,26 @@ EXECUTE stmt; exp 0 DEALLOCATE PREPARE stmt; +# +# MDEV-32466: Potential memory leak on execuing of create view statement +# +CREATE FUNCTION f1 () RETURNS VARCHAR(1) +BEGIN +DECLARE rec1 ROW TYPE OF v1; +SELECT z INTO rec1 FROM v1; +RETURN 1; +END| +CREATE FUNCTION f2 () RETURNS VARCHAR(1) RETURN '!'; +CREATE VIEW v1 AS SELECT f2() z; +PREPARE stmt FROM "SELECT f1()"; +EXECUTE stmt; +f1() +1 +EXECUTE stmt; +f1() +1 +DEALLOCATE PREPARE stmt; +DROP FUNCTION f1; +DROP VIEW v1; +DROP FUNCTION f2; # End of 10.4 tests diff --git a/mysql-test/main/ps_mem_leaks.test b/mysql-test/main/ps_mem_leaks.test index 90de38ad482b1..a68d62fd29386 100644 --- a/mysql-test/main/ps_mem_leaks.test +++ b/mysql-test/main/ps_mem_leaks.test @@ -69,4 +69,32 @@ EXECUTE stmt; DEALLOCATE PREPARE stmt; +--echo # +--echo # MDEV-32466: Potential memory leak on execuing of create view statement +--echo # + +--delimiter | + +CREATE FUNCTION f1 () RETURNS VARCHAR(1) +BEGIN + DECLARE rec1 ROW TYPE OF v1; + SELECT z INTO rec1 FROM v1; + RETURN 1; +END| +--delimiter ; + +CREATE FUNCTION f2 () RETURNS VARCHAR(1) RETURN '!'; +CREATE VIEW v1 AS SELECT f2() z; + +PREPARE stmt FROM "SELECT f1()"; +EXECUTE stmt; +EXECUTE stmt; + +DEALLOCATE PREPARE stmt; + +# Clean up +DROP FUNCTION f1; +DROP VIEW v1; +DROP FUNCTION f2; + --echo # End of 10.4 tests diff --git a/sql/sp.cc b/sql/sp.cc index 87af91187e772..266dbbe9d7162 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -2720,7 +2720,8 @@ 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->active_stmt_arena_to_use(), &rt->mdl_request.key, rt->m_handler, belong_to_view); } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 91dd8cb12cdbd..7642f41e46cf5 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -7740,7 +7740,7 @@ bool setup_fields(THD *thd, Ref_ptr_array ref_pointer_array, while ((item= it++)) { if (make_pre_fix) - pre_fix->push_back(item, thd->stmt_arena->mem_root); + pre_fix->push_back(item, thd->active_stmt_arena_to_use()->mem_root); if (item->fix_fields_if_needed_for_scalar(thd, it.ref())) { diff --git a/sql/sql_class.h b/sql/sql_class.h index a903b70fa84c8..5db5aca92b874 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2790,6 +2790,17 @@ class THD: public THD_count, /* this must be first */ */ Query_arena *stmt_arena; + /** + Get either call or statement arena. In case some function is called from + within a query the call arena has to be used for a memory allocation, + else use the statement arena. + */ + Query_arena *active_stmt_arena_to_use() + { + return (state == Query_arena::STMT_SP_QUERY_ARGUMENTS) ? this : + stmt_arena; + } + void *bulk_param; /* diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 2e8bf40003ed5..a4859bcc1d27d 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -3115,8 +3115,9 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num) uint n_elems= get_cardinality_of_ref_ptrs_slice(order_group_num) * 5; if (!ref_pointer_array.is_null()) return false; - Item **array= static_cast(thd->stmt_arena->alloc(sizeof(Item*) * - n_elems)); + + Item **array= static_cast( + thd->active_stmt_arena_to_use()->alloc(sizeof(Item*) * n_elems)); if (likely(array != NULL)) ref_pointer_array= Ref_ptr_array(array, n_elems); return array == NULL; diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 3651bad7067f3..9f9a97169824a 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -1655,7 +1655,7 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, objects of the view. */ if (!(table->view_sctx= (Security_context *) - thd->stmt_arena->calloc(sizeof(Security_context)))) + thd->active_stmt_arena_to_use()->calloc(sizeof(Security_context)))) goto err; security_ctx= table->view_sctx; }