Bug #35577 CREATE PROCEDURE causes either crash or syntax error depending on build
Submitted: 26 Mar 2008 16:36 Modified: 24 Jul 2008 17:46
Reporter: David Shrewsbury Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server: Parser Severity:S1 (Critical)
Version:5.0.50sp1a, 5.0.52, 5.0.58, 5.0.62, 5.1.23 OS:Any
Assigned to: Marc ALFF CPU Architecture:Any

[26 Mar 2008 16:36] David Shrewsbury
Description:
The following CREATE PROCEDURE (see below), when executed against 5.0.58, causes either a server crash, syntax error, or it completes with success.

On 5.0.58 64-bit built with BUILD/compile-amd64-debug-max, the following error message is consistently returned when executed with: mysql -u root test < sp.sql

ERROR 1064 (42000) at line 3: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'ELSEIF(t_done = 'a') THEN
						SET t_done = 'a';
					ELSEIF(t_done = 'a') THEN' at line 33

On 5.0.58 from mysql-enterprise-gpl-5.0.58-linux-x86_64-glibc23, the same CREATE PROCEDURE will either succeed, crash the server (not as often), or give the following error message:

ERROR 1064 (42000) at line 3: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 44

Note that the crash on 5.0.58-enterprise does not happen as often as the syntax error and sometimes takes many repeated tests or restarting of the server to reproduce it.

How to repeat:
Execute the following SQL repeatedly with: mysql -u root test < sp.sql

DELIMITER ;;
DROP PROCEDURE IF EXISTS `p1` ;;
CREATE PROCEDURE `p1`()
BEGIN

	DECLARE z_done INT DEFAULT 0;
	DECLARE t_done VARCHAR(5000);
        outer_loop: LOOP
		IF t_done=1  THEN
         		LEAVE outer_loop;
	 	END IF;

	inner_block:BEGIN
        	DECLARE z_done INT DEFAULT  0;
		SET z_done = 0;
		inner_loop: LOOP
		IF z_done=1  THEN
       		        LEAVE inner_loop;
 		END IF;
		IF (t_done = 'a') THEN
			IF (t_done <> 0) THEN
			        IF ( t_done > 0) THEN
				        IF (t_done = 'a') THEN
						SET t_done = 'a';
					ELSEIF (t_done = 'a') THEN
						SET t_done = 'a';
					ELSEIF(t_done = 'a') THEN
						SET t_done = 'a';
					ELSEIF(t_done = 'a') THEN
						SET t_done = 'a';
					ELSEIF(t_done = 'a') THEN
						SET t_done = 'a';
					ELSEIF(t_done = 'a') THEN
						SET t_done = 'a';
					ELSEIF(t_done = 'a') THEN
						SET t_done = 'a';
					ELSEIF(t_done = 'a') THEN
						SET t_done = 'a';
					END IF;
				END IF;
			END IF;
		END IF;
		END LOOP inner_loop;
		END inner_block;
	END LOOP outer_loop;
END ;;
DELIMITER ;

Suggested fix:
Seems like a memory corruption issue based on the inconsistent results.
[26 Mar 2008 16:40] MySQL Verification Team
affects 5.1.23 also.  stack trace:

mysqld.exe!MYSQLparse
mysqld.exe!parse_sql
mysqld.exe!mysql_parse
mysqld.exe!dispatch_command
mysqld.exe!do_command
mysqld.exe!handle_one_connection
mysqld.exe!pthread_start
mysqld.exe!_callthreadstart
mysqld.exe!_threadstart
[26 Mar 2008 17:55] David Shrewsbury
Correction: A higher thread_stack doesn't seem to really fix this.
[27 Mar 2008 0:59] Marc ALFF
Analysis

The root cause of the crash / unpredictable syntax errors is a stack corruption
of the *internal* parser stack in bison.

After my_yyoverflow() is called, a call to lex_end() with a non null
thd->lex->yacc_yyss stack pointer will crash the parser,
when this call originates from within the parser itself,
in sp_head::reset_lex().

Changing the *thread* stack size will have no effect.
[28 Mar 2008 17:32] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/44606

ChangeSet@1.2606, 2008-03-28 11:32:08-06:00, malff@lambda.hsd1.co.comcast.net. +12 -0
  Bug#35577 (CREATE PROCEDURE causes either crash or syntax error depending on
  build)
  
  The crash was caused by freeing the internal parser stack during the parser
  execution.
  This occured only for complex stored procedures, after reallocating the parser
  stack using my_yyoverflow(), with the following C call stack:
  - MYSQLparse()
  - any rule calling sp_head::restore_lex()
  - lex_end()
  - x_free(lex->yacc_yyss), xfree(lex->yacc_yyvs)
  
  The root cause is the implementation of stored procedures, which breaks the
  assumption from 4.1 that there is only one LEX structure per parser call.
  
  The solution is to separate the LEX structure into:
  - attributes that represent a statement (the current LEX structure),
  - attributes that relate to the parser itself (Parser_state),
  so that parsing multiple statements in stored programs can create multiple
  LEX structures while not changing the unique Parser_state.
[9 Jun 2008 15:29] Marc ALFF
See related
Bug#37269 parser crash when creating stored procedure
Bug#37228 Sever crashes when creating stored procedure with more than 10 IF/ELSEIF
[23 Jun 2008 23:17] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/48363
[10 Jul 2008 16:58] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/49482
[14 Jul 2008 21:41] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/49718
[15 Jul 2008 1:44] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/49728
[15 Jul 2008 1:45] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/49729
[15 Jul 2008 13:04] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/49760

2700 Gleb Shchepa	2008-07-15 [merge]
      merge from local tree to 5.1-bugteam
[22 Jul 2008 18:38] Bugs System
Pushed into 5.1.28
[22 Jul 2008 18:39] Bugs System
Pushed into 5.0.68
[23 Jul 2008 0:27] Paul DuBois
Noted in 5.1.28 changelog.

Freeing of an internal parser stack during parsing of complex stored
programs caused a server crash.

Setting report to Need Doc Info pending push into 5.0.x/6.0.x.
[23 Jul 2008 15:41] Paul DuBois
Noted in 5.0.68 changelog.

Setting report to Need Doc Info pending push of fix into 6.0.x.
[24 Jul 2008 17:46] Paul DuBois
Noted in 6.0.7 changelog.
[28 Jul 2008 13:47] Bugs System
Pushed into 5.0.68  (revid:kpettersson@mysql.com-20080715152926-s5kgnqhtu93b3c8v) (pib:2)
(Retry automatic marking, to ensure nothing is missed. cm01)
[28 Jul 2008 14:45] Bugs System
Pushed into 6.0.7-alpha  (revid:alik@mysql.com-20080725172155-fnc73o50e4tgl23k) (version source revid:alik@mysql.com-20080725172155-fnc73o50e4tgl23k) (pib:3)
[28 Jul 2008 16:44] Bugs System
Pushed into 5.1.28  (revid:davi.arnaut@sun.com-20080722182431-0i2f1yc4uocime9q) (version source revid:davi.arnaut@sun.com-20080722182431-0i2f1yc4uocime9q) (pib:3)
[13 Sep 2008 20:45] Bugs System
Pushed into 6.0.7-alpha  (revid:marc.alff@sun.com-20080715014312-71bsv5xo3dplugoi) (version source revid:hakan@mysql.com-20080725175322-8wgujj5xuzrjz3ke) (pib:3)