diff --git a/.github/workflows/windows-arm64.yml b/.github/workflows/windows-arm64.yml index a061849cc25..b5d54d3575c 100644 --- a/.github/workflows/windows-arm64.yml +++ b/.github/workflows/windows-arm64.yml @@ -24,7 +24,7 @@ jobs: # unless we configure autocrlf. git config --global core.autocrlf input - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install prerequisites run: | @@ -46,12 +46,11 @@ jobs: - name: Test MTR run: | $env:PATH = "C:\Strawberry\perl\bin;$env:PATH;C:\Program Files (x86)\Windows Kits\10\Debuggers\arm64" - #Calculate parallel as 4 * number of processors - $parallel = 4 * [int]$env:NUMBER_OF_PROCESSORS + $parallel = 2 # create case-sensitive directory to run tests in $tmp = (Get-Item $env:TEMP).FullName $tmp = $tmp -replace '\\','/' $cidir = "$tmp/ci" mkdir $cidir fsutil file setCaseSensitiveInfo $cidir enable - perl bld\mysql-test\mysql-test-run.pl --force --parallel=$parallel --suite=main,innodb --vardir=$cidir/var --mysqld=--lower-case-table-names=0 --mysqld=--loose-innodb-flush-log-at-trx-commit=2 --mysqld=--debug-no-sync + perl bld\mysql-test\mysql-test-run.pl --force --parallel=$parallel --suite=main,innodb --vardir=$cidir/var --skip-rpl --mysqld=--lower-case-table-names=0 --mysqld=--loose-innodb-flush-log-at-trx-commit=2 --mysqld=--debug-no-sync --skip-test=innodb-virtual-columns \ No newline at end of file diff --git a/mysql-test/main/sp_validation.result b/mysql-test/main/sp_validation.result index f76dfeb5e98..020ee363a61 100644 --- a/mysql-test/main/sp_validation.result +++ b/mysql-test/main/sp_validation.result @@ -2085,4 +2085,43 @@ DROP PROCEDURE p2; DROP PROCEDURE p3; DROP PROCEDURE p4; DROP TABLE t1; -SET sql_mode = default; +# +# MDEV-38561: ASAN heap-use-after-free in Query_arena::free_items/sp_lex_cursor::~sp_lex_cursor +# +SET @save_sql_mode=@@sql_mode; +SET sql_mode='oracle'; +CREATE OR REPLACE PACKAGE pkg1 AS +PROCEDURE p1 (); +PROCEDURE p2 (); +END pkg1; +$ +CREATE OR REPLACE PACKAGE BODY pkg1 AS +PROCEDURE p1() IS +CURSOR c1 IS SELECT a FROM t1; +va c1%ROWTYPE; +BEGIN +SELECT 1; +END p1; +PROCEDURE p2() is +BEGIN +FOR i IN 1..2 +LOOP +SELECT i; +CREATE OR REPLACE temporary TABLE t1 (a INT); +CALL pkg1.p1; +END loop; +END p2; +END pkg1 +$ +CALL pkg1.p2(); +i +1 +1 +1 +i +2 +1 +1 +DROP PACKAGE BODY pkg1; +DROP PACKAGE pkg1; +SET sql_mode=@save_sql_mode; diff --git a/mysql-test/main/sp_validation.test b/mysql-test/main/sp_validation.test index bf1f147deec..839024148dc 100644 --- a/mysql-test/main/sp_validation.test +++ b/mysql-test/main/sp_validation.test @@ -2886,5 +2886,46 @@ DROP PROCEDURE p3; DROP PROCEDURE p4; DROP TABLE t1; -SET sql_mode = default; +--echo # +--echo # MDEV-38561: ASAN heap-use-after-free in Query_arena::free_items/sp_lex_cursor::~sp_lex_cursor +--echo # +SET @save_sql_mode=@@sql_mode; +SET sql_mode='oracle'; + +--delimiter $ + +CREATE OR REPLACE PACKAGE pkg1 AS +PROCEDURE p1 (); +PROCEDURE p2 (); +END pkg1; +$ + +CREATE OR REPLACE PACKAGE BODY pkg1 AS +PROCEDURE p1() IS + CURSOR c1 IS SELECT a FROM t1; + va c1%ROWTYPE; +BEGIN + SELECT 1; +END p1; + +PROCEDURE p2() is +BEGIN + FOR i IN 1..2 + LOOP + SELECT i; + CREATE OR REPLACE temporary TABLE t1 (a INT); + CALL pkg1.p1; + END loop; +END p2; +END pkg1 +$ + +--delimiter ; +CALL pkg1.p2(); + +DROP PACKAGE BODY pkg1; +DROP PACKAGE pkg1; + +SET sql_mode=@save_sql_mode; + --enable_ps2_protocol diff --git a/mysql-test/mariadb-test-run.pl b/mysql-test/mariadb-test-run.pl index 7b913f159c6..3013f6ee023 100755 --- a/mysql-test/mariadb-test-run.pl +++ b/mysql-test/mariadb-test-run.pl @@ -3135,6 +3135,7 @@ sub mysql_install_db { mtr_add_arg($args, "--loose-innodb-log-file-size=10M"); mtr_add_arg($args, "--loose-innodb-fast-shutdown=0"); mtr_add_arg($args, "--disable-sync-frm"); + mtr_add_arg($args, "--debug-no-sync"); mtr_add_arg($args, "--tmpdir=%s", "$opt_vardir/tmp/"); mtr_add_arg($args, "--core-file"); mtr_add_arg($args, "--console"); diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index be8ecc8b926..f00d01237ba 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -5562,10 +5562,7 @@ bool Item_func_json_array_intersect::prepare_json_and_create_hash(json_engine_t report_json_error(js, je1, 0); } - max_length= 2*(args[0]->max_length < args[1]->max_length ? - args[0]->max_length : args[1]->max_length); - - return false; + return false; } bool Item_func_json_array_intersect::fix_length_and_dec(THD *thd) @@ -5594,6 +5591,10 @@ bool Item_func_json_array_intersect::fix_length_and_dec(THD *thd) } end: + collation.set(args[0]->collation); + fix_char_length_ulonglong((ulonglong) + 2* MY_MIN(args[0]->max_char_length(), + args[1]->max_char_length())); set_maybe_null(); return FALSE; } diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 077189150dd..4ce6486c844 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -904,6 +904,8 @@ sp_head::~sp_head() delete m_pcont; free_items(); + deallocate_sp_instrs_mem_roots(); + /* If we have non-empty LEX stack then we just came out of parser with error. Now we should delete all auxilary LEXes and restore original @@ -921,6 +923,44 @@ sp_head::~sp_head() } +/** + Iterate along a list of mem_roots created for reparsing of failed + SP instructions. There are as many mem_roots in this list as a number of + failed sp instructions. +*/ + +void sp_head::deallocate_sp_instrs_mem_roots() +{ + List_iterator_fast it(m_mem_roots_to_release); + MEM_ROOT *sp_instr_mem_root; + + while ((sp_instr_mem_root= it++)) + { + free_root(sp_instr_mem_root, MYF(0)); + } + m_mem_roots_to_release.empty(); +} + + +/** + Register the memory root for later deallocation + + @param mem_root the pointer to an instance of MEM_ROOT + + @return false on success, true on error +*/ + +bool sp_head::register_instr_mem_root_for_deallocation(MEM_ROOT *mem_root) +{ + DBUG_ASSERT(mem_root != nullptr); + + if (unlikely(mem_root == nullptr)) + return false; + + return m_mem_roots_to_release.push_back(mem_root); +} + + void sp_package::LexList::cleanup() { List_iterator it(*this); diff --git a/sql/sp_head.h b/sql/sp_head.h index 11f1dae5926..5a631c7f712 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -330,6 +330,12 @@ private: */ const char *m_cpp_body_begin; + /** + List of pointers to MEM_ROOT objects created when re-parsing failing + SP instructions. + */ + List m_mem_roots_to_release; + public: /* Security context for stored routine which should be run under @@ -342,6 +348,11 @@ protected: enum_sp_aggregate_type agg_type, sql_mode_t sql_mode); virtual ~sp_head(); public: + + void deallocate_sp_instrs_mem_roots(); + + bool register_instr_mem_root_for_deallocation(MEM_ROOT *mem_root); + static void destroy(sp_head *sp); static sp_head *create(sp_package *parent, const Sp_handler *handler, enum_sp_aggregate_type agg_type, sql_mode_t sql_mode, diff --git a/sql/sp_instr.h b/sql/sp_instr.h index b43527c2e9c..3e46655e8ee 100644 --- a/sql/sp_instr.h +++ b/sql/sp_instr.h @@ -400,7 +400,8 @@ public: sp_lex_instr(uint ip, sp_pcontext *ctx, LEX *lex, bool is_lex_owner) : sp_instr(ip, ctx), m_lex_keeper(lex, is_lex_owner), - m_mem_root_for_reparsing(nullptr) + m_mem_root_for_reparsing(nullptr), + m_sp{lex->sphead} {} ~sp_lex_instr() override @@ -418,7 +419,13 @@ public: */ free_items(); m_lex_keeper.~sp_lex_keeper(); - free_root(m_mem_root_for_reparsing, MYF(0)); + + /* + Ignore the OOM error explicitly since we are inside destructor + */ + (void)m_sp->register_instr_mem_root_for_deallocation( + m_mem_root_for_reparsing); + m_mem_root_for_reparsing= nullptr; } } @@ -507,6 +514,7 @@ private: */ List cleanup_before_parsing(enum_sp_type sp_type); + sp_head *m_sp; /** Set up field object for every NEW/OLD item of the trigger and