diff options
author | Alexander Barkov <bar@mariadb.com> | 2019-12-11 15:09:17 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.com> | 2019-12-12 16:25:16 +0400 |
commit | e0f9540bcc6ab1618b6fd475f02e019401c4c295 (patch) | |
tree | da554e11e2ad9c9eea4b67efc7e221ce4609564c | |
parent | ce47e66516ec1319dacaa3880d21622af6e00ad7 (diff) | |
download | mariadb-git-e0f9540bcc6ab1618b6fd475f02e019401c4c295.tar.gz |
MDEV-20667 Server crash on pop_cursor
When backpatching a forward GOTO label, the old code erroneously
used CURSOR/HANDLER difference between context frames "c" and "a" to tune
a cpop/hpop command. So the cpop/hpop command later tried to pop
all cursors/handlers declared between "a" and "c", but those between
"b" and "c" were not cpushed/hpoped yet during the execution of "GOTO x".
Fixing the code to use the difference between frames "b" and "a" only.
BEGIN -- a
...
GOTO x; -- b
...
<<x>> -- c
...
END -- d
-rw-r--r-- | mysql-test/suite/compat/oracle/r/sp-goto-debug.result | 236 | ||||
-rw-r--r-- | mysql-test/suite/compat/oracle/r/sp-goto.result | 79 | ||||
-rw-r--r-- | mysql-test/suite/compat/oracle/t/sp-goto-debug.test | 178 | ||||
-rw-r--r-- | mysql-test/suite/compat/oracle/t/sp-goto.test | 98 | ||||
-rw-r--r-- | sql/sp_head.cc | 6 |
5 files changed, 594 insertions, 3 deletions
diff --git a/mysql-test/suite/compat/oracle/r/sp-goto-debug.result b/mysql-test/suite/compat/oracle/r/sp-goto-debug.result new file mode 100644 index 00000000000..3660bfa2d84 --- /dev/null +++ b/mysql-test/suite/compat/oracle/r/sp-goto-debug.result @@ -0,0 +1,236 @@ +SET sql_mode=ORACLE; +# +# MDEV-20667 Server crash on pop_cursor +# +CREATE PROCEDURE p1() IS +BEGIN +IF 1=2 THEN +BEGIN +DECLARE +CURSOR cur1 IS SELECT a FROM t1 ; +BEGIN +GOTO iac_err; +END; +END; +END IF; +IF 1=1 THEN +GOTO iac_err; +END IF; +<< iac_err >> +RETURN; +END// +SHOW PROCEDURE CODE p1; +Pos Instruction +0 jump_if_not 5(5) 1 = 2 +1 cpush cur1@0 +2 jump 3 +3 cpop 1 +4 jump 7 +5 jump_if_not 7(7) 1 = 1 +6 jump 7 +7 preturn +DROP PROCEDURE p1; +CREATE PROCEDURE p1() IS +BEGIN +IF 1=2 THEN +BEGIN +DECLARE +CURSOR cur1 IS SELECT a FROM t1 ; +BEGIN +GOTO iac_err; +END; +END; +END IF; +IF 1=1 THEN +GOTO iac_err; +END IF; +<< iac_err >> +RETURN ; +END// +SHOW PROCEDURE CODE p1; +Pos Instruction +0 jump_if_not 5(5) 1 = 2 +1 cpush cur1@0 +2 jump 3 +3 cpop 1 +4 jump 7 +5 jump_if_not 7(7) 1 = 1 +6 jump 7 +7 preturn +DROP PROCEDURE p1; +CREATE PROCEDURE p1() IS +BEGIN +IF 1=2 THEN +BEGIN +DECLARE +CURSOR cur1 IS SELECT a FROM t1 ; +BEGIN +GOTO iac_err; +END; +END; +END IF; +GOTO iac_err; +<< iac_err >> +RETURN ; +END// +SHOW PROCEDURE CODE p1; +Pos Instruction +0 jump_if_not 5(5) 1 = 2 +1 cpush cur1@0 +2 jump 3 +3 cpop 1 +4 jump 5 +5 preturn +DROP PROCEDURE p1; +CREATE PROCEDURE p1() IS +BEGIN +IF 1=1 THEN +DECLARE +CURSOR cur2 IS SELECT 'cur2' FROM DUAL; +BEGIN +SELECT 'cur2'; +IF 1=1 THEN +DECLARE +CURSOR cur3 IS SELECT 'cur3' FROM DUAL; +BEGIN +SELECT 'cur3'; +IF 1=1 THEN +DECLARE +CURSOR cur4 IS SELECT 'cur4' FROM DUAL; +BEGIN +SELECT 'cur4'; +GOTO ret; +END; +END IF; +GOTO ret; +END; +END IF; +GOTO ret; +END; +END IF; +<<ret>> +RETURN; +END; +// +SHOW PROCEDURE CODE p1; +Pos Instruction +0 jump_if_not 15(15) 1 = 1 +1 cpush cur2@0 +2 stmt 0 "SELECT 'cur2'" +3 jump_if_not 13(13) 1 = 1 +4 cpush cur3@1 +5 stmt 0 "SELECT 'cur3'" +6 jump_if_not 11(11) 1 = 1 +7 cpush cur4@2 +8 stmt 0 "SELECT 'cur4'" +9 cpop 3 +10 jump 15 +11 cpop 2 +12 jump 15 +13 cpop 1 +14 jump 15 +15 preturn +DROP PROCEDURE p1; +CREATE PROCEDURE p1(lab VARCHAR(32)) IS +BEGIN +IF 1=1 THEN +DECLARE +CURSOR cur2 IS SELECT 'cur2' FROM DUAL; +BEGIN +IF 1=1 THEN +DECLARE +CURSOR cur3 IS SELECT 'cur3' FROM DUAL; +BEGIN +IF 1=1 THEN +DECLARE +CURSOR cur4 IS SELECT 'cur4' FROM DUAL; +BEGIN +IF lab = 'cur4' THEN +SELECT 'goto from cur4' AS comment; +GOTO ret; +END IF; +END; +END IF; +IF lab = 'cur3' THEN +SELECT 'goto from cur3' AS comment; +GOTO ret; +END IF; +END; +END IF; +IF lab = 'cur2' THEN +SELECT 'goto from cur2' AS comment; +GOTO ret; +END IF; +END; +END IF; +<<ret>> +RETURN; +END; +// +SHOW PROCEDURE CODE p1; +Pos Instruction +0 jump_if_not 21(21) 1 = 1 +1 cpush cur2@0 +2 jump_if_not 16(16) 1 = 1 +3 cpush cur3@1 +4 jump_if_not 11(11) 1 = 1 +5 cpush cur4@2 +6 jump_if_not 10(10) lab@0 = 'cur4' +7 stmt 0 "SELECT 'goto from cur4' AS comment" +8 cpop 3 +9 jump 21 +10 cpop 1 +11 jump_if_not 15(15) lab@0 = 'cur3' +12 stmt 0 "SELECT 'goto from cur3' AS comment" +13 cpop 2 +14 jump 21 +15 cpop 1 +16 jump_if_not 20(20) lab@0 = 'cur2' +17 stmt 0 "SELECT 'goto from cur2' AS comment" +18 cpop 1 +19 jump 21 +20 cpop 1 +21 preturn +CALL p1(''); +CALL p1('cur2'); +comment +goto from cur2 +CALL p1('cur3'); +comment +goto from cur3 +CALL p1('cur4'); +comment +goto from cur4 +DROP PROCEDURE p1; +CREATE PROCEDURE p1() IS +BEGIN +IF 1=2 THEN +BEGIN +DECLARE +CONTINUE HANDLER FOR SQLSTATE '23000' SET @x2 = 1; +BEGIN +GOTO iac_err; +END; +END; +END IF; +IF 1=1 THEN +GOTO iac_err; +END IF; +<<iac_err >> +RETURN; +END// +SHOW PROCEDURE CODE p1; +Pos Instruction +0 jump_if_not 9(9) 1 = 2 +1 hpush_jump 4 0 CONTINUE +2 stmt 31 "SET @x2 = 1" +3 hreturn 0 +4 hpop 1 +5 jump 11 +6 jump 11 +7 hpop 1 +8 jump 9 +9 jump_if_not 11(11) 1 = 1 +10 jump 11 +11 preturn +DROP PROCEDURE p1; diff --git a/mysql-test/suite/compat/oracle/r/sp-goto.result b/mysql-test/suite/compat/oracle/r/sp-goto.result index 259be7a34e6..badda507ee4 100644 --- a/mysql-test/suite/compat/oracle/r/sp-goto.result +++ b/mysql-test/suite/compat/oracle/r/sp-goto.result @@ -832,3 +832,82 @@ a 15 DROP TRIGGER trg1; DROP TABLE t1; +# +# MDEV-20667 Server crash on pop_cursor +# +CREATE TABLE t1 (a VARCHAR(6)); +CREATE PROCEDURE p1() IS +BEGIN +IF 1=2 THEN +BEGIN +DECLARE +CURSOR cur1 IS SELECT a FROM t1 ; +BEGIN +GOTO iac_err; +END; +END; +END IF; +IF 1=1 THEN +GOTO iac_err; +END IF; +<< iac_err >> +RETURN; +END// +CALL p1(); +DROP PROCEDURE p1; +DROP TABLE t1; +CREATE PROCEDURE p1() IS +BEGIN +IF 1=2 THEN +BEGIN +DECLARE +CURSOR cur1 IS SELECT a FROM t1 ; +BEGIN +GOTO iac_err; +END; +END; +END IF; +IF 1=1 THEN +GOTO iac_err; +END IF; +<< iac_err >> +RETURN ; +END// +CALL p1; +DROP PROCEDURE p1; +CREATE PROCEDURE p1() IS +BEGIN +IF 1=2 THEN +BEGIN +DECLARE +CURSOR cur1 IS SELECT a FROM t1 ; +BEGIN +GOTO iac_err; +END; +END; +END IF; +GOTO iac_err; +<< iac_err >> +RETURN ; +END// +CALL p1; +DROP PROCEDURE p1; +CREATE PROCEDURE p1() IS +BEGIN +IF 1=2 THEN +BEGIN +DECLARE +CONTINUE HANDLER FOR SQLSTATE '23000' SET @x2 = 1; +BEGIN +GOTO iac_err; +END; +END; +END IF; +IF 1=1 THEN +GOTO iac_err; +END IF; +<<iac_err >> +RETURN; +END// +CALL p1; +DROP PROCEDURE p1; diff --git a/mysql-test/suite/compat/oracle/t/sp-goto-debug.test b/mysql-test/suite/compat/oracle/t/sp-goto-debug.test new file mode 100644 index 00000000000..0ded370b17a --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/sp-goto-debug.test @@ -0,0 +1,178 @@ +-- source include/have_debug.inc + +SET sql_mode=ORACLE; + +--echo # +--echo # MDEV-20667 Server crash on pop_cursor +--echo # + +DELIMITER //; +CREATE PROCEDURE p1() IS +BEGIN + IF 1=2 THEN + BEGIN + DECLARE + CURSOR cur1 IS SELECT a FROM t1 ; + BEGIN + GOTO iac_err; + END; + END; + END IF; + IF 1=1 THEN + GOTO iac_err; + END IF; +<< iac_err >> + RETURN; +END// +DELIMITER ;// +SHOW PROCEDURE CODE p1; +DROP PROCEDURE p1; + + +DELIMITER //; +CREATE PROCEDURE p1() IS +BEGIN + IF 1=2 THEN + BEGIN + DECLARE + CURSOR cur1 IS SELECT a FROM t1 ; + BEGIN + GOTO iac_err; + END; + END; + END IF; + IF 1=1 THEN + GOTO iac_err; + END IF; +<< iac_err >> + RETURN ; +END// +DELIMITER ;// +SHOW PROCEDURE CODE p1; +DROP PROCEDURE p1; + + +DELIMITER //; +CREATE PROCEDURE p1() IS +BEGIN + IF 1=2 THEN + BEGIN + DECLARE + CURSOR cur1 IS SELECT a FROM t1 ; + BEGIN + GOTO iac_err; + END; + END; + END IF; + GOTO iac_err; +<< iac_err >> + RETURN ; +END// +DELIMITER ;// +SHOW PROCEDURE CODE p1; +DROP PROCEDURE p1; + + +DELIMITER //; +CREATE PROCEDURE p1() IS +BEGIN + IF 1=1 THEN + DECLARE + CURSOR cur2 IS SELECT 'cur2' FROM DUAL; + BEGIN + SELECT 'cur2'; + IF 1=1 THEN + DECLARE + CURSOR cur3 IS SELECT 'cur3' FROM DUAL; + BEGIN + SELECT 'cur3'; + IF 1=1 THEN + DECLARE + CURSOR cur4 IS SELECT 'cur4' FROM DUAL; + BEGIN + SELECT 'cur4'; + GOTO ret; + END; + END IF; + GOTO ret; + END; + END IF; + GOTO ret; + END; + END IF; +<<ret>> + RETURN; +END; +// +DELIMITER ;// +SHOW PROCEDURE CODE p1; +DROP PROCEDURE p1; + + +DELIMITER //; +CREATE PROCEDURE p1(lab VARCHAR(32)) IS +BEGIN + IF 1=1 THEN + DECLARE + CURSOR cur2 IS SELECT 'cur2' FROM DUAL; + BEGIN + IF 1=1 THEN + DECLARE + CURSOR cur3 IS SELECT 'cur3' FROM DUAL; + BEGIN + IF 1=1 THEN + DECLARE + CURSOR cur4 IS SELECT 'cur4' FROM DUAL; + BEGIN + IF lab = 'cur4' THEN + SELECT 'goto from cur4' AS comment; + GOTO ret; + END IF; + END; + END IF; + IF lab = 'cur3' THEN + SELECT 'goto from cur3' AS comment; + GOTO ret; + END IF; + END; + END IF; + IF lab = 'cur2' THEN + SELECT 'goto from cur2' AS comment; + GOTO ret; + END IF; + END; + END IF; +<<ret>> + RETURN; +END; +// +DELIMITER ;// +SHOW PROCEDURE CODE p1; +CALL p1(''); +CALL p1('cur2'); +CALL p1('cur3'); +CALL p1('cur4'); +DROP PROCEDURE p1; + + +DELIMITER //; +CREATE PROCEDURE p1() IS +BEGIN + IF 1=2 THEN + BEGIN + DECLARE + CONTINUE HANDLER FOR SQLSTATE '23000' SET @x2 = 1; + BEGIN + GOTO iac_err; + END; + END; + END IF; + IF 1=1 THEN + GOTO iac_err; + END IF; +<<iac_err >> + RETURN; +END// +DELIMITER ;// +SHOW PROCEDURE CODE p1; +DROP PROCEDURE p1; diff --git a/mysql-test/suite/compat/oracle/t/sp-goto.test b/mysql-test/suite/compat/oracle/t/sp-goto.test index df7f1132666..9c15d10b3de 100644 --- a/mysql-test/suite/compat/oracle/t/sp-goto.test +++ b/mysql-test/suite/compat/oracle/t/sp-goto.test @@ -869,4 +869,100 @@ insert into t1 values (1); insert into t1 values (null); SELECT * FROM t1; DROP TRIGGER trg1; -DROP TABLE t1;
\ No newline at end of file +DROP TABLE t1; + + +--echo # +--echo # MDEV-20667 Server crash on pop_cursor +--echo # + +CREATE TABLE t1 (a VARCHAR(6)); +DELIMITER //; +CREATE PROCEDURE p1() IS +BEGIN + IF 1=2 THEN + BEGIN + DECLARE + CURSOR cur1 IS SELECT a FROM t1 ; + BEGIN + GOTO iac_err; + END; + END; + END IF; + IF 1=1 THEN + GOTO iac_err; + END IF; +<< iac_err >> + RETURN; +END// +DELIMITER ;// +CALL p1(); +DROP PROCEDURE p1; +DROP TABLE t1; + + +DELIMITER //; +CREATE PROCEDURE p1() IS +BEGIN + IF 1=2 THEN + BEGIN + DECLARE + CURSOR cur1 IS SELECT a FROM t1 ; + BEGIN + GOTO iac_err; + END; + END; + END IF; + IF 1=1 THEN + GOTO iac_err; + END IF; +<< iac_err >> + RETURN ; +END// +DELIMITER ;// +CALL p1; +DROP PROCEDURE p1; + + +DELIMITER //; +CREATE PROCEDURE p1() IS +BEGIN + IF 1=2 THEN + BEGIN + DECLARE + CURSOR cur1 IS SELECT a FROM t1 ; + BEGIN + GOTO iac_err; + END; + END; + END IF; + GOTO iac_err; +<< iac_err >> + RETURN ; +END// +DELIMITER ;// +CALL p1; +DROP PROCEDURE p1; + + +DELIMITER //; +CREATE PROCEDURE p1() IS +BEGIN + IF 1=2 THEN + BEGIN + DECLARE + CONTINUE HANDLER FOR SQLSTATE '23000' SET @x2 = 1; + BEGIN + GOTO iac_err; + END; + END; + END IF; + IF 1=1 THEN + GOTO iac_err; + END IF; +<<iac_err >> + RETURN; +END// +DELIMITER ;// +CALL p1; +DROP PROCEDURE p1; diff --git a/sql/sp_head.cc b/sql/sp_head.cc index ab7faf51849..360713fc452 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -2571,7 +2571,7 @@ sp_head::backpatch_goto(THD *thd, sp_label *lab,sp_label *lab_begin_block) } if (bp->instr_type == CPOP) { - uint n= lab->ctx->diff_cursors(lab_begin_block->ctx, true); + uint n= bp->instr->m_ctx->diff_cursors(lab_begin_block->ctx, true); if (n == 0) { // Remove cpop instr @@ -2588,7 +2588,7 @@ sp_head::backpatch_goto(THD *thd, sp_label *lab,sp_label *lab_begin_block) } if (bp->instr_type == HPOP) { - uint n= lab->ctx->diff_handlers(lab_begin_block->ctx, true); + uint n= bp->instr->m_ctx->diff_handlers(lab_begin_block->ctx, true); if (n == 0) { // Remove hpop instr @@ -3082,6 +3082,8 @@ void sp_head::optimize() sp_instr *i; uint src, dst; + DBUG_EXECUTE_IF("sp_head_optimize_disable", return; ); + opt_mark(); bp.empty(); |