Bug#28779 (mysql_query() allows execution of statements with unbalanced

comments)

This change set is for 5.1 (manually merged)

Before this fix, the server would accept queries that contained comments,
even when the comments were not properly closed with a '*' '/' marker.

For example,
  select 1 /* + 2 <EOF>
would be accepted as
  select 1 /* + 2 */ <EOF>
and executed as
  select 1

With this fix, the server now rejects queries with unclosed comments
as syntax errors.
Both regular comments ('/' '*') and special comments ('/' '*' '!') must be
closed with '*' '/' to be parsed correctly.
parent 80609d18
...@@ -36,3 +36,18 @@ select 1/*!999992*/; ...@@ -36,3 +36,18 @@ select 1/*!999992*/;
select 1 + /*!00000 2 */ + 3 /*!99999 noise*/ + 4; select 1 + /*!00000 2 */ + 3 /*!99999 noise*/ + 4;
1 + 2 + 3 + 4 1 + 2 + 3 + 4
10 10
drop table if exists table_28779;
create table table_28779 (a int);
prepare bar from "DELETE FROM table_28779 WHERE a = 7 OR 1=1/*' AND b = 'bar';";
ERROR 42000: 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 '/*' AND b = 'bar'' at line 1
prepare bar from "DELETE FROM table_28779 WHERE a = 7 OR 1=1/*' AND b = 'bar';*";
ERROR 42000: 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 '/*' AND b = 'bar';*' at line 1
prepare bar from "DELETE FROM table_28779 WHERE a = 7 OR 1=1/*! AND 2=2;";
ERROR 42000: 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 1
prepare bar from "DELETE FROM table_28779 WHERE a = 7 OR 1=1/*! AND 2=2;*";
ERROR 42000: 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 1
prepare bar from "DELETE FROM table_28779 WHERE a = 7 OR 1=1/*!98765' AND b = 'bar';";
ERROR 42000: 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 '/*!98765' AND b = 'bar'' at line 1
prepare bar from "DELETE FROM table_28779 WHERE a = 7 OR 1=1/*!98765' AND b = 'bar';*";
ERROR 42000: 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 '/*!98765' AND b = 'bar';*' at line 1
drop table table_28779;
...@@ -34,3 +34,34 @@ select 1/*!999992*/; ...@@ -34,3 +34,34 @@ select 1/*!999992*/;
select 1 + /*!00000 2 */ + 3 /*!99999 noise*/ + 4; select 1 + /*!00000 2 */ + 3 /*!99999 noise*/ + 4;
#
# Bug#28779 (mysql_query() allows execution of statements with unbalanced
# comments)
#
--disable_warnings
drop table if exists table_28779;
--enable_warnings
create table table_28779 (a int);
--error 1064
prepare bar from "DELETE FROM table_28779 WHERE a = 7 OR 1=1/*' AND b = 'bar';";
--error 1064
prepare bar from "DELETE FROM table_28779 WHERE a = 7 OR 1=1/*' AND b = 'bar';*";
--error 1064
prepare bar from "DELETE FROM table_28779 WHERE a = 7 OR 1=1/*! AND 2=2;";
--error 1064
prepare bar from "DELETE FROM table_28779 WHERE a = 7 OR 1=1/*! AND 2=2;*";
--error 1064
prepare bar from "DELETE FROM table_28779 WHERE a = 7 OR 1=1/*!98765' AND b = 'bar';";
--error 1064
prepare bar from "DELETE FROM table_28779 WHERE a = 7 OR 1=1/*!98765' AND b = 'bar';*";
drop table table_28779;
...@@ -719,6 +719,7 @@ static inline uint int_token(const char *str,uint length) ...@@ -719,6 +719,7 @@ static inline uint int_token(const char *str,uint length)
int MYSQLlex(void *arg, void *yythd) int MYSQLlex(void *arg, void *yythd)
{ {
reg1 uchar c; reg1 uchar c;
bool comment_closed;
int tokval, result_state; int tokval, result_state;
uint length; uint length;
enum my_lex_states state; enum my_lex_states state;
...@@ -1211,7 +1212,10 @@ int MYSQLlex(void *arg, void *yythd) ...@@ -1211,7 +1212,10 @@ int MYSQLlex(void *arg, void *yythd)
/* /*
The special comment format is very strict: The special comment format is very strict:
'/' '*' '!', followed by exactly '/' '*' '!', followed by exactly
2 digits (major), then 3 digits (minor). 1 digit (major), 2 digits (minor), then 2 digits (dot).
32302 -> 3.23.02
50032 -> 5.0.32
50114 -> 5.1.14
*/ */
char version_str[6]; char version_str[6];
version_str[0]= lip->yyPeekn(0); version_str[0]= lip->yyPeekn(0);
...@@ -1230,7 +1234,7 @@ int MYSQLlex(void *arg, void *yythd) ...@@ -1230,7 +1234,7 @@ int MYSQLlex(void *arg, void *yythd)
ulong version; ulong version;
version=strtol(version_str, NULL, 10); version=strtol(version_str, NULL, 10);
/* Accept 'M' 'M' 'm' 'm' 'm' */ /* Accept 'M' 'm' 'm' 'd' 'd' */
lip->yySkipn(5); lip->yySkipn(5);
if (version <= MYSQL_VERSION_ID) if (version <= MYSQL_VERSION_ID)
...@@ -1254,16 +1258,36 @@ int MYSQLlex(void *arg, void *yythd) ...@@ -1254,16 +1258,36 @@ int MYSQLlex(void *arg, void *yythd)
lip->yySkip(); // Accept / lip->yySkip(); // Accept /
lip->yySkip(); // Accept * lip->yySkip(); // Accept *
} }
/*
while (! lip->eof() && Discard:
((c=lip->yyGet()) != '*' || lip->yyPeek() != '/')) - regular '/' '*' comments,
- special comments '/' '*' '!' for a future version,
by scanning until we find a closing '*' '/' marker.
Note: There is no such thing as nesting comments,
the first '*' '/' sequence seen will mark the end.
*/
comment_closed= FALSE;
while (! lip->eof())
{ {
if (c == '\n') c= lip->yyGet();
if (c == '*')
{
if (lip->yyPeek() == '/')
{
lip->yySkip();
comment_closed= TRUE;
state = MY_LEX_START;
break;
}
}
else if (c == '\n')
lip->yylineno++; lip->yylineno++;
} }
if (! lip->eof()) /* Unbalanced comments with a missing '*' '/' are a syntax error */
lip->yySkip(); // remove last '/' if (! comment_closed)
return (ABORT_SYM);
state = MY_LEX_START; // Try again state = MY_LEX_START; // Try again
lip->in_comment= NO_COMMENT;
lip->set_echo(TRUE); lip->set_echo(TRUE);
break; break;
case MY_LEX_END_LONG_COMMENT: case MY_LEX_END_LONG_COMMENT:
...@@ -1315,6 +1339,9 @@ int MYSQLlex(void *arg, void *yythd) ...@@ -1315,6 +1339,9 @@ int MYSQLlex(void *arg, void *yythd)
lip->set_echo(FALSE); lip->set_echo(FALSE);
lip->yySkip(); lip->yySkip();
lip->set_echo(TRUE); lip->set_echo(TRUE);
/* Unbalanced comments with a missing '*' '/' are a syntax error */
if (lip->in_comment != NO_COMMENT)
return (ABORT_SYM);
lip->next_state=MY_LEX_END; // Mark for next loop lip->next_state=MY_LEX_END; // Mark for next loop
return(END_OF_INPUT); return(END_OF_INPUT);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment