mirror of
https://github.com/MariaDB/server.git
synced 2026-10-23 18:49:29 +03:00
MDEV-39210 ExtractValue/UpdateXML crash.
XML parser fixed to handle <! and <? correctly.
This commit is contained in:
@@ -68,6 +68,10 @@ typedef struct xml_stack_st
|
||||
int (*enter)(struct xml_stack_st *st,const char *val, size_t len);
|
||||
int (*value)(struct xml_stack_st *st,const char *val, size_t len);
|
||||
int (*leave_xml)(struct xml_stack_st *st,const char *val, size_t len);
|
||||
|
||||
int (*processing_instruction)(struct xml_stack_st *st,
|
||||
const char *target, size_t target_len,
|
||||
const char *value, size_t value_len);
|
||||
} MY_XML_PARSER;
|
||||
|
||||
void my_xml_parser_create(MY_XML_PARSER *st);
|
||||
@@ -83,6 +87,8 @@ void my_xml_set_enter_handler(MY_XML_PARSER *st, int (*)(MY_XML_PARSER *,
|
||||
void my_xml_set_leave_handler(MY_XML_PARSER *st, int (*)(MY_XML_PARSER *,
|
||||
const char *,
|
||||
size_t len));
|
||||
void my_xml_set_processing_instruction_handler(MY_XML_PARSER *st,
|
||||
int (*)(MY_XML_PARSER *, const char *, size_t, const char *, size_t));
|
||||
void my_xml_set_user_data(MY_XML_PARSER *st, void *);
|
||||
|
||||
size_t my_xml_error_pos(MY_XML_PARSER *st);
|
||||
|
||||
@@ -1322,3 +1322,95 @@ foo
|
||||
#
|
||||
# Start of 10.5 tests
|
||||
#
|
||||
#
|
||||
# ExtractValue/UpdateXML crash
|
||||
#
|
||||
SELECT ExtractValue('<!a/><!b/>', '/a');
|
||||
ExtractValue('<!a/><!b/>', '/a')
|
||||
NULL
|
||||
Warnings:
|
||||
Warning 1525 Incorrect XML value: 'parse error at line 1 pos 2: unknown token unexpected (ident or '/' wanted)'
|
||||
SELECT UpdateXML('<!a/><!b/>', '/a', '<new/>');
|
||||
UpdateXML('<!a/><!b/>', '/a', '<new/>')
|
||||
NULL
|
||||
Warnings:
|
||||
Warning 1525 Incorrect XML value: 'parse error at line 1 pos 2: unknown token unexpected (ident or '/' wanted)'
|
||||
SELECT ExtractValue('<!a/><!b/><!c/>', '/a');
|
||||
ExtractValue('<!a/><!b/><!c/>', '/a')
|
||||
NULL
|
||||
Warnings:
|
||||
Warning 1525 Incorrect XML value: 'parse error at line 1 pos 2: unknown token unexpected (ident or '/' wanted)'
|
||||
SELECT ExtractValue('<?a/?><?b/?>', '/a');
|
||||
ExtractValue('<?a/?><?b/?>', '/a')
|
||||
NULL
|
||||
Warnings:
|
||||
Warning 1525 Incorrect XML value: 'parse error at line 1 pos 5: unknown token unexpected (ident wanted)'
|
||||
SELECT ExtractValue('<!a/><?b/?>', '/a');
|
||||
ExtractValue('<!a/><?b/?>', '/a')
|
||||
NULL
|
||||
Warnings:
|
||||
Warning 1525 Incorrect XML value: 'parse error at line 1 pos 2: unknown token unexpected (ident or '/' wanted)'
|
||||
SET @xml='<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE note [
|
||||
<!ELEMENT note (to, from, heading, body)>
|
||||
<!ELEMENT to (#PCDATA)>
|
||||
<!ELEMENT from (#PCDATA)>
|
||||
<!ELEMENT heading (#PCDATA)>
|
||||
<!ELEMENT body (#PCDATA)>
|
||||
]>
|
||||
<note>
|
||||
<to>Tove</to>
|
||||
<from>Jani</from>
|
||||
<heading>Reminder</heading>
|
||||
<body>See you this weekend!</body>
|
||||
</note>
|
||||
';
|
||||
SELECT ExtractValue(@xml, '/note/from');
|
||||
ExtractValue(@xml, '/note/from')
|
||||
Jani
|
||||
set @xml= '<?xml version="1.0"?>
|
||||
<employee>
|
||||
<dt1>--01--+01:00</dt1>
|
||||
<dt2>--12--+01:00</dt2>
|
||||
<?dt3 123456 ?>
|
||||
<dt3>--02--</dt3>
|
||||
<dt4>--03--Z</dt4>
|
||||
<?dt4 123456 ?>
|
||||
</employee>
|
||||
<?employee ABSDEV !@#$ ?>';
|
||||
SELECT ExtractValue(@xml, '/employee/dt3');
|
||||
ExtractValue(@xml, '/employee/dt3')
|
||||
--02--
|
||||
set @xml= '<? xml version="1.0"?>
|
||||
<employee>
|
||||
<dt1>--01--+01:00</dt1>
|
||||
<dt2>--12--+01:00</dt2>
|
||||
<?dt3 123456 ?>
|
||||
<dt3>--02--</dt3>
|
||||
<dt4>--03--Z</dt4>
|
||||
<?dt4 123456 ?>
|
||||
</employee>
|
||||
<? employee ABSDEV !@#$ ?>';
|
||||
SELECT ExtractValue(@xml, '/employee/dt3');
|
||||
ExtractValue(@xml, '/employee/dt3')
|
||||
NULL
|
||||
Warnings:
|
||||
Warning 1525 Incorrect XML value: 'parse error at line 1 pos 21: unknown token unexpected ('>' wanted)'
|
||||
set @xml= '<?xml version="1.0"?>
|
||||
<employee>
|
||||
<dt1>--01--+01:00</dt1>
|
||||
<dt2>--12--+01:00</dt2>
|
||||
<?dt3 123456 ?>
|
||||
<dt3>--02--</dt3>
|
||||
<dt4>--03--Z</dt4>
|
||||
<?dt4 123456 ? >
|
||||
</employee>
|
||||
<?employee ABSDEV !@#$ ?>';
|
||||
SELECT ExtractValue(@xml, '/employee/dt3');
|
||||
ExtractValue(@xml, '/employee/dt3')
|
||||
NULL
|
||||
Warnings:
|
||||
Warning 1525 Incorrect XML value: 'parse error at line 10 pos 27: unexpected END-OF-INPUT'
|
||||
#
|
||||
# Start of 10.6 tests
|
||||
#
|
||||
|
||||
@@ -824,3 +824,76 @@ SELECT 'foo' AS f UNION SELECT BINARY( UpdateXML('<a></a>', '/a', '<b></b>')) AS
|
||||
--echo #
|
||||
--echo # Start of 10.5 tests
|
||||
--echo #
|
||||
|
||||
--echo #
|
||||
--echo # ExtractValue/UpdateXML crash
|
||||
--echo #
|
||||
|
||||
#view protocol generates additional warning
|
||||
--disable_view_protocol
|
||||
SELECT ExtractValue('<!a/><!b/>', '/a');
|
||||
SELECT UpdateXML('<!a/><!b/>', '/a', '<new/>');
|
||||
SELECT ExtractValue('<!a/><!b/><!c/>', '/a');
|
||||
SELECT ExtractValue('<?a/?><?b/?>', '/a');
|
||||
SELECT ExtractValue('<!a/><?b/?>', '/a');
|
||||
--enable_view_protocol
|
||||
|
||||
SET @xml='<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE note [
|
||||
<!ELEMENT note (to, from, heading, body)>
|
||||
<!ELEMENT to (#PCDATA)>
|
||||
<!ELEMENT from (#PCDATA)>
|
||||
<!ELEMENT heading (#PCDATA)>
|
||||
<!ELEMENT body (#PCDATA)>
|
||||
]>
|
||||
<note>
|
||||
<to>Tove</to>
|
||||
<from>Jani</from>
|
||||
<heading>Reminder</heading>
|
||||
<body>See you this weekend!</body>
|
||||
</note>
|
||||
';
|
||||
|
||||
SELECT ExtractValue(@xml, '/note/from');
|
||||
|
||||
set @xml= '<?xml version="1.0"?>
|
||||
<employee>
|
||||
<dt1>--01--+01:00</dt1>
|
||||
<dt2>--12--+01:00</dt2>
|
||||
<?dt3 123456 ?>
|
||||
<dt3>--02--</dt3>
|
||||
<dt4>--03--Z</dt4>
|
||||
<?dt4 123456 ?>
|
||||
</employee>
|
||||
<?employee ABSDEV !@#$ ?>';
|
||||
|
||||
SELECT ExtractValue(@xml, '/employee/dt3');
|
||||
|
||||
set @xml= '<? xml version="1.0"?>
|
||||
<employee>
|
||||
<dt1>--01--+01:00</dt1>
|
||||
<dt2>--12--+01:00</dt2>
|
||||
<?dt3 123456 ?>
|
||||
<dt3>--02--</dt3>
|
||||
<dt4>--03--Z</dt4>
|
||||
<?dt4 123456 ?>
|
||||
</employee>
|
||||
<? employee ABSDEV !@#$ ?>';
|
||||
|
||||
SELECT ExtractValue(@xml, '/employee/dt3');
|
||||
|
||||
set @xml= '<?xml version="1.0"?>
|
||||
<employee>
|
||||
<dt1>--01--+01:00</dt1>
|
||||
<dt2>--12--+01:00</dt2>
|
||||
<?dt3 123456 ?>
|
||||
<dt3>--02--</dt3>
|
||||
<dt4>--03--Z</dt4>
|
||||
<?dt4 123456 ? >
|
||||
</employee>
|
||||
<?employee ABSDEV !@#$ ?>';
|
||||
|
||||
SELECT ExtractValue(@xml, '/employee/dt3');
|
||||
--echo #
|
||||
--echo # Start of 10.6 tests
|
||||
--echo #
|
||||
|
||||
161
strings/xml.c
161
strings/xml.c
@@ -30,9 +30,9 @@
|
||||
#define MY_XML_SLASH '/'
|
||||
#define MY_XML_COMMENT 'C'
|
||||
#define MY_XML_TEXT 'T'
|
||||
#define MY_XML_QUESTION '?'
|
||||
#define MY_XML_EXCLAM '!'
|
||||
#define MY_XML_CDATA 'D'
|
||||
#define MY_XML_PROCESSING_INSTRUCTION '?'
|
||||
#define MY_XML_CDATA 'A'
|
||||
#define MY_XML_DTD 'D'
|
||||
|
||||
typedef struct xml_attr_st
|
||||
{
|
||||
@@ -95,8 +95,8 @@ static const char *lex2str(int lex)
|
||||
case MY_XML_SLASH: return "'/'";
|
||||
case MY_XML_COMMENT: return "COMMENT";
|
||||
case MY_XML_TEXT: return "TEXT";
|
||||
case MY_XML_QUESTION: return "'?'";
|
||||
case MY_XML_EXCLAM: return "'!'";
|
||||
case MY_XML_PROCESSING_INSTRUCTION: return "'?'";
|
||||
case MY_XML_DTD: return "DTD";
|
||||
}
|
||||
return "unknown token";
|
||||
}
|
||||
@@ -145,6 +145,43 @@ static int my_xml_scan(MY_XML_PARSER *p,MY_XML_ATTR *a)
|
||||
a->end=p->cur;
|
||||
lex=MY_XML_COMMENT;
|
||||
}
|
||||
else if (!my_xml_parser_prefix_cmp(p, C_STRING_WITH_LEN("<?")))
|
||||
{
|
||||
lex= MY_XML_UNKNOWN;
|
||||
p->cur+= 2;
|
||||
|
||||
a->beg= p->cur;
|
||||
if (my_xml_is_id0(p->cur[0]))
|
||||
{
|
||||
int termination_expected= FALSE;
|
||||
|
||||
p->cur++;
|
||||
while (p->cur < p->end && my_xml_is_id1(p->cur[0]))
|
||||
p->cur++;
|
||||
|
||||
a->end=p->cur;
|
||||
/*
|
||||
After the target name the syntax requires the
|
||||
terminating '?>' or some spaces then an
|
||||
arbitrary string to the '>?'.
|
||||
*/
|
||||
if (p->cur < p->end && !my_xml_is_space(p->cur[0]))
|
||||
termination_expected= TRUE;
|
||||
|
||||
while (p->cur < p->end)
|
||||
{
|
||||
if (my_xml_parser_prefix_cmp(p, C_STRING_WITH_LEN("?>")) == 0)
|
||||
{
|
||||
lex= MY_XML_PROCESSING_INSTRUCTION;
|
||||
p->cur+= 2;
|
||||
break;
|
||||
}
|
||||
else if (termination_expected)
|
||||
break;
|
||||
p->cur++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!my_xml_parser_prefix_cmp(p, C_STRING_WITH_LEN("<![CDATA[")))
|
||||
{
|
||||
p->cur+= 9;
|
||||
@@ -159,7 +196,56 @@ static int my_xml_scan(MY_XML_PARSER *p,MY_XML_ATTR *a)
|
||||
}
|
||||
lex= MY_XML_CDATA;
|
||||
}
|
||||
else if (strchr("?=/<>!",p->cur[0]))
|
||||
else if (!my_xml_parser_prefix_cmp(p, C_STRING_WITH_LEN("<!DOCTYPE")))
|
||||
{
|
||||
/* skip <!DOCTYPE part. TODO: add parser for the DTD */
|
||||
int in_quote= 0;
|
||||
int level= 1;
|
||||
|
||||
p->cur+= 9;
|
||||
lex= MY_XML_UNKNOWN;
|
||||
for (; p->cur < p->end; p->cur++)
|
||||
{
|
||||
if (p->cur[0] == '"' || p->cur[0] == '\'')
|
||||
{
|
||||
if (!in_quote)
|
||||
in_quote= p->cur[0];
|
||||
else
|
||||
{
|
||||
if (p->cur[0] == in_quote)
|
||||
in_quote= 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (in_quote)
|
||||
continue;
|
||||
|
||||
switch (p->cur[0])
|
||||
{
|
||||
case MY_XML_LT:
|
||||
{
|
||||
level++;
|
||||
break;
|
||||
}
|
||||
case MY_XML_GT:
|
||||
{
|
||||
level--;
|
||||
if (level == 0)
|
||||
{
|
||||
lex= MY_XML_DTD;
|
||||
p->cur++;
|
||||
goto dtd_end;
|
||||
}
|
||||
}
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
dtd_end:
|
||||
a->end= p->cur;
|
||||
}
|
||||
|
||||
else if (strchr("=/<>",p->cur[0]))
|
||||
{
|
||||
p->cur++;
|
||||
a->end=p->cur;
|
||||
@@ -340,14 +426,23 @@ int my_xml_parse(MY_XML_PARSER *p,const char *str, size_t len)
|
||||
if (p->cur[0] == '<')
|
||||
{
|
||||
int lex;
|
||||
int question=0;
|
||||
int exclam=0;
|
||||
|
||||
lex=my_xml_scan(p,&a);
|
||||
|
||||
if (MY_XML_COMMENT == lex)
|
||||
if (MY_XML_COMMENT == lex ||
|
||||
MY_XML_DTD == lex)
|
||||
continue;
|
||||
|
||||
if (MY_XML_PROCESSING_INSTRUCTION == lex)
|
||||
{
|
||||
if (p->processing_instruction &&
|
||||
MY_XML_OK != p->processing_instruction(p,
|
||||
a.beg, (size_t) (a.end-a.beg),
|
||||
a.end, (size_t) (p->cur - a.end - 2)))
|
||||
return MY_XML_ERROR;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (lex == MY_XML_CDATA)
|
||||
{
|
||||
a.beg+= 9;
|
||||
@@ -371,16 +466,6 @@ int my_xml_parse(MY_XML_PARSER *p,const char *str, size_t len)
|
||||
goto gt;
|
||||
}
|
||||
|
||||
if (MY_XML_EXCLAM == lex)
|
||||
{
|
||||
lex=my_xml_scan(p,&a);
|
||||
exclam=1;
|
||||
}
|
||||
else if (MY_XML_QUESTION == lex)
|
||||
{
|
||||
lex=my_xml_scan(p,&a);
|
||||
question=1;
|
||||
}
|
||||
|
||||
if (MY_XML_IDENT == lex)
|
||||
{
|
||||
@@ -395,8 +480,7 @@ int my_xml_parse(MY_XML_PARSER *p,const char *str, size_t len)
|
||||
return MY_XML_ERROR;
|
||||
}
|
||||
|
||||
while ((MY_XML_IDENT == (lex=my_xml_scan(p,&a))) ||
|
||||
((MY_XML_STRING == lex && exclam)))
|
||||
while (MY_XML_IDENT == (lex=my_xml_scan(p,&a)))
|
||||
{
|
||||
MY_XML_ATTR b;
|
||||
if (MY_XML_EQ == (lex=my_xml_scan(p,&b)))
|
||||
@@ -424,15 +508,6 @@ int my_xml_parse(MY_XML_PARSER *p,const char *str, size_t len)
|
||||
(MY_XML_OK != my_xml_leave(p,a.beg,(size_t) (a.end-a.beg))))
|
||||
return MY_XML_ERROR;
|
||||
}
|
||||
else if ((MY_XML_STRING == lex) && exclam)
|
||||
{
|
||||
/*
|
||||
We are in <!DOCTYPE>, e.g.
|
||||
<!DOCTYPE name SYSTEM "SystemLiteral">
|
||||
<!DOCTYPE name PUBLIC "PublidLiteral" "SystemLiteral">
|
||||
Just skip "SystemLiteral" and "PublicidLiteral"
|
||||
*/
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
@@ -445,24 +520,6 @@ int my_xml_parse(MY_XML_PARSER *p,const char *str, size_t len)
|
||||
}
|
||||
|
||||
gt:
|
||||
if (question)
|
||||
{
|
||||
if (lex != MY_XML_QUESTION)
|
||||
{
|
||||
snprintf(p->errstr,sizeof(p->errstr),"%s unexpected ('?' wanted)",lex2str(lex));
|
||||
return MY_XML_ERROR;
|
||||
}
|
||||
if (MY_XML_OK != my_xml_leave(p,NULL,0))
|
||||
return MY_XML_ERROR;
|
||||
lex=my_xml_scan(p,&a);
|
||||
}
|
||||
|
||||
if (exclam)
|
||||
{
|
||||
if (MY_XML_OK != my_xml_leave(p,NULL,0))
|
||||
return MY_XML_ERROR;
|
||||
}
|
||||
|
||||
if (lex != MY_XML_GT)
|
||||
{
|
||||
snprintf(p->errstr,sizeof(p->errstr),"%s unexpected ('>' wanted)",lex2str(lex));
|
||||
@@ -537,6 +594,14 @@ void my_xml_set_leave_handler(MY_XML_PARSER *p,
|
||||
}
|
||||
|
||||
|
||||
void my_xml_set_processing_instruction_handler(MY_XML_PARSER *p,
|
||||
int (*p_i)(MY_XML_PARSER *, const char *, size_t,
|
||||
const char *, size_t))
|
||||
{
|
||||
p->processing_instruction= p_i;
|
||||
}
|
||||
|
||||
|
||||
void my_xml_set_user_data(MY_XML_PARSER *p, void *user_data)
|
||||
{
|
||||
p->user_data=user_data;
|
||||
|
||||
Reference in New Issue
Block a user