Commit e9f3ca61 authored by Yuchen Pei's avatar Yuchen Pei

MDEV-31117 Fix spider connection info parsing

Spider connection string is a comma-separated parameter definitions,
where each definition is of the form "<param_title> <param_value>",
where <param_value> is quote delimited on both ends, with backslashes
acting as an escaping prefix.

Despite the simple syntax, the existing spider connection string
parser was poorly-written, complex, hard to reason and error-prone,
causing issues like the one described in MDEV-31117. For example it
treated param title the same way as param value when assigning, and
have nonsensical fields like delim_title_len and delim_title.

Thus as part of the bugfix, we clean up the spider comment connection
string parsing, including:

- Factoring out some code from the parsing function
- Simplify the struct `st_spider_param_string_parse`
- And any necessary changes caused by the above changes
parent ff682ead
#
# MDEV-31117 Spider UBSAN runtime error: applying non-zero offset x to null pointer in st_spider_param_string_parse::restore_delims
#
for master_1
for child2
for child3
CREATE TABLE t (c INT) ENGINE=Spider COMMENT='abc';
ERROR HY000: The connect info 'abc' is invalid
ALTER TABLE mysql.help_topic ENGINE=Spider;
ERROR HY000: The connect info 'help topics' is invalid
CREATE SERVER srv FOREIGN DATA WRAPPER MYSQL OPTIONS (SOCKET "$MASTER_1_MYSOCK", DATABASE 'test',user 'root');
create table t2 (c int);
create table t1 (c int) ENGINE=Spider COMMENT='WRAPPER "mysql", "srv" "srv",TABLE "t2"';
ERROR HY000: The connect info '"srv" "srv",TABLE "t2"' is invalid
create table t1 (c int) ENGINE=Spider CONNECTION='WRAPPER "mysql", srv \'srv\',TABLE "t2", password "say \\"hello\\ world!\\""';
drop table t1, t2;
for master_1
for child2
for child3
--echo #
--echo # MDEV-31117 Spider UBSAN runtime error: applying non-zero offset x to null pointer in st_spider_param_string_parse::restore_delims
--echo #
--disable_query_log
--disable_result_log
--source ../../t/test_init.inc
--enable_result_log
--enable_query_log
--error 12501
CREATE TABLE t (c INT) ENGINE=Spider COMMENT='abc';
--error 12501
ALTER TABLE mysql.help_topic ENGINE=Spider;
evalp CREATE SERVER srv FOREIGN DATA WRAPPER MYSQL OPTIONS (SOCKET "$MASTER_1_MYSOCK", DATABASE 'test',user 'root');
create table t2 (c int);
# param title should not have delimiter
--error 12501
create table t1 (c int) ENGINE=Spider COMMENT='WRAPPER "mysql", "srv" "srv",TABLE "t2"';
# test escaping
create table t1 (c int) ENGINE=Spider CONNECTION='WRAPPER "mysql", srv \'srv\',TABLE "t2", password "say \\"hello\\ world!\\""';
drop table t1, t2;
--disable_query_log
--disable_result_log
--source ../t/test_deinit.inc
--enable_query_log
--enable_result_log
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -30,281 +30,21 @@ ...@@ -30,281 +30,21 @@
typedef struct st_spider_param_string_parse typedef struct st_spider_param_string_parse
{ {
char *start_ptr; /* Pointer to the start of the parameter string */ char *start_title; /* Pointer to the start of the current parameter
char *end_ptr; /* Pointer to the end of the parameter string */ title */
char *start_title_ptr; /* Pointer to the start of the current parameter char *end_title; /* Pointer to the end of the current
title */ parameter value */
char *end_title_ptr; /* Pointer to the end of the current parameter char *start_value; /* Pointer to the start of the current parameter
title */ value */
char *start_value_ptr; /* Pointer to the start of the current parameter char *end_value; /* Pointer to the end of the current parameter
value */ value */
char *end_value_ptr; /* Pointer to the end of the current parameter char delim_value; /* Current parameter value's delimiter
value */ character, either a single or a double quote */
int error_num; /* Error code of the error message to print when int error_num; /* Error code of the error message to print when
an error is detected */ an error is detected */
uint delim_title_len; /* Length of the paramater title's delimiter */
uint delim_value_len; /* Length of the paramater value's delimiter */ int fail(bool restore_delim);
char delim_title; /* Current parameter title's delimiter character */ bool locate_param_def(char*& start_param);
char delim_value; /* Current parameter value's delimiter character */
/**
Initialize the parameter string parse information.
@param param_string Pointer to the parameter string being parsed.
@param error_code Error code of the error message to print when
an error is detected.
*/
inline void init(char *param_string, int error_code)
{
start_ptr = param_string;
end_ptr = start_ptr + strlen(start_ptr);
init_param_title();
init_param_value();
error_num = error_code;
}
/**
Initialize the current parameter title.
*/
inline void init_param_title()
{
start_title_ptr = end_title_ptr = NULL;
delim_title_len = 0;
delim_title = '\0';
}
/**
Save pointers to the start and end positions of the current parameter
title in the parameter string. Also save the parameter title's
delimiter character.
@param start_value Pointer to the start position of the current
parameter title.
@param end_value Pointer to the end position of the current
parameter title.
*/
inline void set_param_title(char *start_title, char *end_title)
{
start_title_ptr = start_title;
end_title_ptr = end_title;
if (*start_title == '"' ||
*start_title == '\'')
{
delim_title = *start_title;
if (start_title >= start_ptr && *--start_title == '\\')
delim_title_len = 2;
else
delim_title_len = 1;
}
}
/**
Initialize the current parameter value.
*/
inline void init_param_value()
{
start_value_ptr = end_value_ptr = NULL;
delim_value_len = 0;
delim_value = '\0';
}
/**
Save pointers to the start and end positions of the current parameter
value in the parameter string. Also save the parameter value's
delimiter character.
@param start_value Pointer to the start position of the current
parameter value.
@param end_value Pointer to the end position of the current
parameter value.
*/
inline void set_param_value(char *start_value, char *end_value)
{
start_value_ptr = start_value--;
end_value_ptr = end_value;
if (*start_value == '"' ||
*start_value == '\'')
{
delim_value = *start_value;
if (*--start_value == '\\')
delim_value_len = 2;
else
delim_value_len = 1;
}
}
/**
Determine whether the current parameter in the parameter string has
extra parameter values.
@return 0 Current parameter value in the parameter string
does not have extra parameter values.
<> 0 Error code indicating that the current parameter
value in the parameter string has extra
parameter values.
*/
inline int has_extra_parameter_values()
{
int error_num = 0;
DBUG_ENTER("has_extra_parameter_values");
if (end_value_ptr)
{
/* There is a current parameter value */
char *end_param_ptr = end_value_ptr;
while (end_param_ptr < end_ptr &&
(*end_param_ptr == ' ' || *end_param_ptr == '\r' ||
*end_param_ptr == '\n' || *end_param_ptr == '\t'))
end_param_ptr++;
if (end_param_ptr < end_ptr && *end_param_ptr != '\0')
{
/* Extra values in parameter definition */
error_num = print_param_error();
}
}
DBUG_RETURN(error_num);
}
inline int get_next_parameter_head(char *st, char **nx)
{
DBUG_ENTER("get_next_parameter_head");
char *sq = strchr(st, '\'');
char *dq = strchr(st, '"');
if (!sq && !dq)
{
DBUG_RETURN(print_param_error());
}
if (dq && (!sq || sq > dq))
{
while (1)
{
++dq;
if (*dq == '\\')
{
++dq;
}
else if (*dq == '"')
{
break;
}
else if (*dq == '\0')
{
DBUG_RETURN(print_param_error());
}
}
while (1)
{
++dq;
if (*dq == '\0')
{
*nx = dq;
break;
}
else if (*dq == ',')
{
*dq = '\0';
*nx = dq + 1;
break;
}
else if (*dq != ' ' && *dq != '\r' && *dq != '\n' && *dq != '\t')
{
DBUG_RETURN(print_param_error());
}
}
}
else /* sq && (!dq || sq <= dq) */
{
while (1)
{
++sq;
if (*sq == '\\')
{
++sq;
}
else if (*sq == '\'')
{
break;
}
else if (*sq == '\0')
{
DBUG_RETURN(print_param_error());
}
}
while (1)
{
++sq;
if (*sq == '\0')
{
*nx = sq;
break;
}
else if (*sq == ',')
{
*sq = '\0';
*nx = sq + 1;
break;
}
else if (*sq != ' ' && *sq != '\r' && *sq != '\n' && *sq != '\t')
{
DBUG_RETURN(print_param_error());
}
}
}
DBUG_RETURN(0);
}
/**
Restore the current parameter's input delimiter characters in the
parameter string. They were NULLed during parameter parsing.
*/
inline void restore_delims()
{
char *end = end_title_ptr - 1;
switch (delim_title_len)
{
case 2:
*end++ = '\\';
/* Fall through */
case 1:
*end = delim_title;
}
end = end_value_ptr - 1;
switch (delim_value_len)
{
case 2:
*end++ = '\\';
/* Fall through */
case 1:
*end = delim_value;
}
}
/**
Print a parameter string error message.
@return Error code.
*/
int print_param_error();
} SPIDER_PARAM_STRING_PARSE; } SPIDER_PARAM_STRING_PARSE;
uchar *spider_tbl_get_key( uchar *spider_tbl_get_key(
...@@ -352,19 +92,12 @@ void spider_free_tmp_share_alloc( ...@@ -352,19 +92,12 @@ void spider_free_tmp_share_alloc(
SPIDER_SHARE *share SPIDER_SHARE *share
); );
char *spider_get_string_between_quote(
char *ptr,
bool alloc,
SPIDER_PARAM_STRING_PARSE *param_string_parse = NULL
);
int spider_create_string_list( int spider_create_string_list(
char ***string_list, char ***string_list,
uint **string_length_list, uint **string_length_list,
uint *list_length, uint *list_length,
char *str, char *str,
uint length, uint length
SPIDER_PARAM_STRING_PARSE *param_string_parse
); );
int spider_create_long_list( int spider_create_long_list(
...@@ -373,8 +106,7 @@ int spider_create_long_list( ...@@ -373,8 +106,7 @@ int spider_create_long_list(
char *str, char *str,
uint length, uint length,
long min_val, long min_val,
long max_val, long max_val
SPIDER_PARAM_STRING_PARSE *param_string_parse
); );
int spider_create_longlong_list( int spider_create_longlong_list(
...@@ -383,8 +115,7 @@ int spider_create_longlong_list( ...@@ -383,8 +115,7 @@ int spider_create_longlong_list(
char *str, char *str,
uint length, uint length,
longlong min_val, longlong min_val,
longlong max_val, longlong max_val
SPIDER_PARAM_STRING_PARSE *param_string_parse
); );
int spider_increase_string_list( int spider_increase_string_list(
......
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