[MDEV-20667] Server crash on pop_cursor Created: 2019-09-25  Updated: 2019-12-12  Resolved: 2019-12-12

Status: Closed
Project: MariaDB Server
Component/s: Data Definition - Procedure
Affects Version/s: 10.4.7, 10.4.8, 10.3, 10.4
Fix Version/s: 10.3.22, 10.4.12

Type: Bug Priority: Critical
Reporter: Jérôme Brauge Assignee: Alexander Barkov
Resolution: Fixed Votes: 0
Labels: None
Environment:

CentOS 7


Attachments: File cursor_crash2.sql    

 Description   

Conjunction of cursor and "goto" statement in stored procedure cause crash with stack:
sql/sp_rcontext.cc:452(sp_rcontext::pop_cursor(THD*))[0x55e353c86a13]
sql/sp_head.cc:4288(sp_instr_cpop::execute(THD*, unsigned int*))[0x55e353c7755b]
sql/sp_head.cc:1350(sp_head::execute(THD*, bool))[0x55e353c7b421]
sql/sp_head.cc:2288(sp_head::execute_procedure(THD*, List<Item>*))[0x55e353c7c5d7]
sql/sql_parse.cc:3022(do_execute_sp(THD*, sp_head*))[0x55e353cff46f]
sql/sql_parse.cc:3261(Sql_cmd_call::execute(THD*))[0x55e353d00ba6]
sql/sql_parse.cc:3272(Sql_cmd_call::execute(THD*))[0x55e353d013a7]
sql/sql_parse.cc:6099(mysql_execute_command(THD*))[0x55e353d0a30e]
sql/sp_head.cc:3607(sp_instr_stmt::exec_core(THD*, unsigned int*))[0x55e353c78e84]
sql/sp_head.cc:3343(sp_lex_keeper::reset_lex_and_exec_core(THD*, unsigned int*, bool, sp_instr*))[0x55e353c7f434]
sql/sp_head.cc:3514(sp_instr_stmt::execute(THD*, unsigned int*))[0x55e353c7fe59]
sql/sp_head.cc:1350(sp_head::execute(THD*, bool))[0x55e353c7b421]
sql/sp_head.cc:2288(sp_head::execute_procedure(THD*, List<Item>*))[0x55e353c7c5d7]
sql/sql_parse.cc:3022(do_execute_sp(THD*, sp_head*))[0x55e353cff46f]
sql/sql_parse.cc:5711(mysql_execute_command(THD*))[0x55e353d0852c]
sql/sql_parse.cc:7910(mysql_parse(THD*, char*, unsigned int, Parser_state*, bool, bool))[0x55e353d10112]
sql/sql_parse.cc:1907(dispatch_command(enum_server_command, THD*, char*, unsigned int, bool, bool))[0x55e353d12ed9]
sql/sql_parse.cc:1360(do_command(THD*))[0x55e353d1473c]
sql/sql_connect.cc:1412(do_handle_one_connection(CONNECT*))[0x55e353de44f4]
sql/sql_connect.cc:1318(handle_one_connection)[0x55e353de45d4]
perfschema/pfs.cc:1865(pfs_spawn_thread)[0x55e354398534]



 Comments   
Comment by Alice Sherepa [ 2019-09-26 ]

Thanks a lot! Reproduced on debug version 10.3-10.4:

CREATE TABLE t1 ( a varchar(6));
delimiter //;
set sql_mode=oracle;
 
CREATE PROCEDURE sp1() 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 sp1();

10.3 b6bb64e54a3e34a20cda3

/git/10.3/sql/sp_rcontext.cc:445: void sp_rcontext::pop_cursors(THD*, size_t): Assertion `m_ccount >= count' failed.
 
#3  <signal handler called>
#4  0x00007ff1e8292428 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54
#5  0x00007ff1e829402a in __GI_abort () at abort.c:89
#6  0x00007ff1e828abd7 in __assert_fail_base (fmt=<optimized out>, assertion=assertion@entry=0x563a05eee5fd "m_ccount >= count", file=file@entry=0x563a05eee528 "/10.3/sql/sp_rcontext.cc", line=line@entry=445, function=function@entry=0x563a05eef060 <sp_rcontext::pop_cursors(THD*, unsigned long)::__PRETTY_FUNCTION__> "void sp_rcontext::pop_cursors(THD*, size_t)") at assert.c:92
#7  0x00007ff1e828ac82 in __GI___assert_fail (assertion=0x563a05eee5fd "m_ccount >= count", file=0x563a05eee528 "/10.3/sql/sp_rcontext.cc", line=445, function=0x563a05eef060 <sp_rcontext::pop_cursors(THD*, unsigned long)::__PRETTY_FUNCTION__> "void sp_rcontext::pop_cursors(THD*, size_t)") at assert.c:101
#8  0x0000563a051d9426 in sp_rcontext::pop_cursors (this=0x7ff198013000, thd=0x7ff198000b00, count=1) at /10.3/sql/sp_rcontext.cc:445
#9  0x0000563a051caf49 in sp_instr_cpop::execute (this=0x7ff19806d6b0, thd=0x7ff198000b00, nextp=0x7ff1e18f8054) at /10.3/sql/sp_head.cc:4233
#10 0x0000563a051c2b48 in sp_head::execute (this=0x7ff1980a30a8, thd=0x7ff198000b00, merge_da_on_success=true) at /10.3/sql/sp_head.cc:1356
#11 0x0000563a051c5674 in sp_head::execute_procedure (this=0x7ff1980a30a8, thd=0x7ff198000b00, args=0x7ff198005780) at /10.3/sql/sp_head.cc:2296
#12 0x0000563a052a51b2 in do_execute_sp (thd=0x7ff198000b00, sp=0x7ff1980a30a8) at /10.3/sql/sql_parse.cc:2991
#13 0x0000563a052a5e24 in Sql_cmd_call::execute (this=0x7ff1980128f0, thd=0x7ff198000b00) at /10.3/sql/sql_parse.cc:3231
#14 0x0000563a052afb9e in mysql_execute_command (thd=0x7ff198000b00) at /10.3/sql/sql_parse.cc:6023
#15 0x0000563a052b532a in mysql_parse (thd=0x7ff198000b00, rawbuf=0x7ff198012818 "call pssgnumnew()", length=17, parser_state=0x7ff1e18f9460, is_com_multi=false, is_next_command=false) at /10.3/sql/sql_parse.cc:7829
#16 0x0000563a052a1efd in dispatch_command (command=COM_QUERY, thd=0x7ff198000b00, packet=0x7ff19815fe11 "call pssgnumnew()", packet_length=17, is_com_multi=false, is_next_command=false) at /10.3/sql/sql_parse.cc:1855
#17 0x0000563a052a080b in do_command (thd=0x7ff198000b00) at /10.3/sql/sql_parse.cc:1401
#18 0x0000563a054182e2 in do_handle_one_connection (connect=0x563a0854e6e0) at /10.3/sql/sql_connect.cc:1403
#19 0x0000563a0541801e in handle_one_connection (arg=0x563a0854e6e0) at /10.3/sql/sql_connect.cc:1308
#20 0x0000563a05dc5390 in pfs_spawn_thread (arg=0x563a08498eb0) at /10.3/storage/perfschema/pfs.cc:1862
#21 0x00007ff1e8ecf6ba in start_thread (arg=0x7ff1e18fa700) at pthread_create.c:333
#22 0x00007ff1e836441d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:109

Comment by Alexander Barkov [ 2019-09-27 ]

DROP PROCEDURE p1;
DELIMITER //
set sql_mode=oracle;
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;
CALL p1;

also crashes. Befor the crash, it prints the following procedure code:

+-----+------------------------+
| Pos | Instruction            |
+-----+------------------------+
|   0 | jump_if_not 5(5) 1 = 2 |
|   1 | cpush cur1@0           |
|   2 | jump 3                 |
|   3 | cpop 1                 |
|   4 | jump 8                 |
|   5 | jump_if_not 8(8) 1 = 1 |
|   6 | cpop 1                 |
|   7 | jump 8                 |
|   8 | preturn                |
+-----+------------------------+

The above code is wrong. The execution goes this way:

  • jump_if_not at position 0 jumps to 5
  • jump_if_not at position 5 does not jump
  • the cpop at position 6 does not have any cursors on the stack, hence the crash.

It seems the cpop at position 6 should not be there.

Comment by Alexander Barkov [ 2019-12-10 ]

The same problem is repeatable with this script, with an unconditional GOTO jump at the end:

DROP PROCEDURE p1;
DELIMITER //
set sql_mode=oracle;
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;

+-----+------------------------+
| Pos | Instruction            |
+-----+------------------------+
|   0 | jump_if_not 5(5) 1 = 2 |
|   1 | cpush cur1@0           |
|   2 | jump 3                 |
|   3 | cpop 1                 |
|   4 | jump 6                 |
|   5 | cpop 1                 |
|   6 | preturn                |
+-----+------------------------+

Notice, the cpop at position 5 looks wrong.

Comment by Alexander Barkov [ 2019-12-11 ]

A similar crash happens with handlers instead of cursors:

SET sql_mode=ORACLE;
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;

sp_rcontext.cc:459: void sp_rcontext::pop_handlers(size_t): Assertion `m_handlers.elements() >= count' failed.

SHOW PROCEDURE CODE p1 displays this output:

+-----+--------------------------+
| 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 12                  |
|   6 | jump 12                  |
|   7 | hpop 1                   |
|   8 | jump 9                   |
|   9 | jump_if_not 12(12) 1 = 1 |
|  10 | hpop 1                   |
|  11 | jump 12                  |
|  12 | preturn                  |
+-----+--------------------------+

The hpop on the 10th position does not have any corresponding hpush commands, hence the crash.

Comment by Alexander Barkov [ 2019-12-11 ]

Hi Varun,

Can you please review a fix for MDEV-20667 ?

https://github.com/MariaDB/server/commit/599b92768b57a514360280dbdf810e7e3c985dec

Thanks!

Generated at Thu Feb 08 09:01:15 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.