From 4de773e90cc8ff5a38e5585780643bdcb986f515 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Mon, 29 Dec 2025 18:03:23 +0400 Subject: [PATCH] MDEV-38451 `SHOW FUNCTION CODE package_func` crashes on the second execution Routine name resolution performed on a temporary memory root during execution. So on the second execution LEX::spname members pointed to a cleared memory. Fixing to peform the resolution to parse time, like the CALL statement does. During the execution time LEX::spname members now stay untouched. --- .../compat/oracle/r/sp-package-code.result | 30 ++++++++++++ .../compat/oracle/t/sp-package-code.test | 30 ++++++++++++ sql/sql_class.h | 2 + sql/sql_cmd.h | 34 +++++++++++++ sql/sql_lex.cc | 21 ++++++++ sql/sql_lex.h | 1 + sql/sql_parse.cc | 49 ++++++++----------- sql/sql_yacc.yy | 18 ++++--- 8 files changed, 149 insertions(+), 36 deletions(-) diff --git a/mysql-test/suite/compat/oracle/r/sp-package-code.result b/mysql-test/suite/compat/oracle/r/sp-package-code.result index 0dea72dba89..2a1c44c27e4 100644 --- a/mysql-test/suite/compat/oracle/r/sp-package-code.result +++ b/mysql-test/suite/compat/oracle/r/sp-package-code.result @@ -243,3 +243,33 @@ Pos Instruction 7 jump 11 DROP PACKAGE pkg1; DROP TABLE t1; +# Start of 10.11 tests +# +# MDEV-38451 `SHOW FUNCTION CODE package_func` crashes on the second execution +# +CREATE PACKAGE pkg1 AS +PROCEDURE p1(); +END; +$$ +CREATE PACKAGE BODY pkg1 AS +FUNCTION f1() RETURN INT AS +BEGIN +RETURN 10; +END; +PROCEDURE p1() AS +BEGIN +SHOW FUNCTION CODE f1; +END; +END; +$$ +CALL pkg1.p1; +Pos Instruction +0 freturn int 10 +CALL pkg1.p1; +Pos Instruction +0 freturn int 10 +CALL pkg1.p1; +Pos Instruction +0 freturn int 10 +DROP PACKAGE pkg1; +# End of 10.11 tests diff --git a/mysql-test/suite/compat/oracle/t/sp-package-code.test b/mysql-test/suite/compat/oracle/t/sp-package-code.test index 9cca53964ec..659e3d43367 100644 --- a/mysql-test/suite/compat/oracle/t/sp-package-code.test +++ b/mysql-test/suite/compat/oracle/t/sp-package-code.test @@ -180,3 +180,33 @@ SHOW PROCEDURE CODE pkg1.p1; SHOW PACKAGE BODY CODE pkg1; DROP PACKAGE pkg1; DROP TABLE t1; + +--echo # Start of 10.11 tests + +--echo # +--echo # MDEV-38451 `SHOW FUNCTION CODE package_func` crashes on the second execution +--echo # + +DELIMITER $$; +CREATE PACKAGE pkg1 AS + PROCEDURE p1(); +END; +$$ +CREATE PACKAGE BODY pkg1 AS + FUNCTION f1() RETURN INT AS + BEGIN + RETURN 10; + END; + PROCEDURE p1() AS + BEGIN + SHOW FUNCTION CODE f1; + END; +END; +$$ +DELIMITER ;$$ +CALL pkg1.p1; +CALL pkg1.p1; +CALL pkg1.p1; +DROP PACKAGE pkg1; + +--echo # End of 10.11 tests diff --git a/sql/sql_class.h b/sql/sql_class.h index d3c50df01f0..aa78312c3b6 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -8120,6 +8120,8 @@ class Database_qualified_name public: LEX_CSTRING m_db; LEX_CSTRING m_name; + Database_qualified_name() + { } Database_qualified_name(const LEX_CSTRING *db, const LEX_CSTRING *name) :m_db(*db), m_name(*name) { } diff --git a/sql/sql_cmd.h b/sql/sql_cmd.h index f94ffee2f9f..8bf6b9f99fa 100644 --- a/sql/sql_cmd.h +++ b/sql/sql_cmd.h @@ -180,4 +180,38 @@ public: } }; + +#ifndef DBUG_OFF +/** + Sql_cmd_call represents the SHOW CODE statement: + - SHOW PROCEDURE CODE + - SHOW FUNCTION CODE + - SHOW PACKAGE BODY CODE +*/ +class Sql_cmd_show_routine_code : public Sql_cmd +{ +public: + class sp_name *m_name; + const class Sp_handler *m_handler; + enum_sql_command m_sql_command; + Sql_cmd_show_routine_code(class sp_name *name, + const class Sp_handler *handler, + enum_sql_command sql_command) + :m_name(name), + m_handler(handler), + m_sql_command(sql_command) + {} + + virtual ~Sql_cmd_show_routine_code() = default; + + bool execute(THD *thd) override; + + enum_sql_command sql_command_code() const override + { + return m_sql_command; + } +}; +#endif // DBUG_OFF + + #endif // SQL_CMD_INCLUDED diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 15391c37e6b..d31620324a6 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -9390,6 +9390,27 @@ bool LEX::add_create_view(THD *thd, DDL_options_st ddl, } +bool LEX::show_routine_code_start(THD *thd, enum_sql_command cmd, sp_name *name) +{ +#ifdef DBUG_OFF + my_error(ER_FEATURE_DISABLED, MYF(0), + "SHOW PROCEDURE|FUNCTION CODE", "--with-debug"); + return true; +#else + sql_command= cmd; + Database_qualified_name pkgname; + const Sp_handler *sph= Sp_handler::handler(cmd); + if (sph->sp_resolve_package_routine(thd, thd->lex->sphead, + name, &sph, &pkgname)) + return true; + if (!(m_sql_cmd= new (thd->mem_root) Sql_cmd_show_routine_code(name, sph, + cmd))) + return true; + return false; +#endif +} + + bool LEX::call_statement_start(THD *thd, sp_name *name) { Database_qualified_name pkgname(&null_clex_str, &null_clex_str); diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 490ba9df6ce..700cd18ae2b 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -3971,6 +3971,7 @@ public: const sp_name *name, const sp_name *name2, const char *cpp_body_end); + bool show_routine_code_start(THD *thd, enum_sql_command cmd, sp_name *name); bool call_statement_start(THD *thd, sp_name *name); bool call_statement_start(THD *thd, const Lex_ident_sys_st *name); bool call_statement_start(THD *thd, const Lex_ident_sys_st *name1, diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index a87becfc6f5..0523fc492e6 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3288,6 +3288,24 @@ static bool prepare_db_action(THD *thd, privilege_t want_access, } +#ifndef DBUG_OFF +bool Sql_cmd_show_routine_code::execute(THD *thd) +{ + sp_head *sp; + if (m_handler->sp_cache_routine(thd, m_name, &sp)) + return true; + if (!sp || sp->show_routine_code(thd)) + { + /* We don't distinguish between errors for now */ + my_error(ER_SP_DOES_NOT_EXIST, MYF(0), + m_handler->type_str(), m_name->m_name.str); + return true; + } + return false; +} +#endif // DBUG_OFF + + bool Sql_cmd_call::execute(THD *thd) { TABLE_LIST *all_tables= thd->lex->query_tables; @@ -5967,34 +5985,6 @@ mysql_execute_command(THD *thd, bool is_called_from_prepared_stmt) goto error; break; } - case SQLCOM_SHOW_PROC_CODE: - case SQLCOM_SHOW_FUNC_CODE: - case SQLCOM_SHOW_PACKAGE_BODY_CODE: - { -#ifndef DBUG_OFF - Database_qualified_name pkgname(&null_clex_str, &null_clex_str); - sp_head *sp; - const Sp_handler *sph= Sp_handler::handler(lex->sql_command); - WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW); - if (sph->sp_resolve_package_routine(thd, thd->lex->sphead, - lex->spname, &sph, &pkgname)) - return true; - if (sph->sp_cache_routine(thd, lex->spname, &sp)) - goto error; - if (!sp || sp->show_routine_code(thd)) - { - /* We don't distinguish between errors for now */ - my_error(ER_SP_DOES_NOT_EXIST, MYF(0), - sph->type_str(), lex->spname->m_name.str); - goto error; - } - break; -#else - my_error(ER_FEATURE_DISABLED, MYF(0), - "SHOW PROCEDURE|FUNCTION CODE", "--with-debug"); - goto error; -#endif // ifndef DBUG_OFF - } case SQLCOM_SHOW_CREATE_TRIGGER: { if (check_ident_length(&lex->spname->m_name)) @@ -6199,6 +6189,9 @@ mysql_execute_command(THD *thd, bool is_called_from_prepared_stmt) case SQLCOM_SIGNAL: case SQLCOM_RESIGNAL: case SQLCOM_GET_DIAGNOSTICS: + case SQLCOM_SHOW_PROC_CODE: + case SQLCOM_SHOW_FUNC_CODE: + case SQLCOM_SHOW_PACKAGE_BODY_CODE: case SQLCOM_CALL: case SQLCOM_REVOKE: case SQLCOM_GRANT: diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 61f22eb7d16..3517fed44d6 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -14024,23 +14024,25 @@ show_param: } | PROCEDURE_SYM CODE_SYM sp_name { - Lex->sql_command= SQLCOM_SHOW_PROC_CODE; - Lex->spname= $3; + if (Lex->show_routine_code_start(thd, SQLCOM_SHOW_PROC_CODE, $3)) + MYSQL_YYABORT; } | FUNCTION_SYM CODE_SYM sp_name { - Lex->sql_command= SQLCOM_SHOW_FUNC_CODE; - Lex->spname= $3; + if (Lex->show_routine_code_start(thd, SQLCOM_SHOW_FUNC_CODE, $3)) + MYSQL_YYABORT; } | PACKAGE_MARIADB_SYM BODY_MARIADB_SYM CODE_SYM sp_name { - Lex->sql_command= SQLCOM_SHOW_PACKAGE_BODY_CODE; - Lex->spname= $4; + if (Lex->show_routine_code_start(thd, SQLCOM_SHOW_PACKAGE_BODY_CODE, + $4)) + MYSQL_YYABORT; } | PACKAGE_ORACLE_SYM BODY_ORACLE_SYM CODE_SYM sp_name { - Lex->sql_command= SQLCOM_SHOW_PACKAGE_BODY_CODE; - Lex->spname= $4; + if (Lex->show_routine_code_start(thd, SQLCOM_SHOW_PACKAGE_BODY_CODE, + $4)) + MYSQL_YYABORT; } | CREATE EVENT_SYM sp_name {