mxmlLoad* and mxmlSAXLoad* did not properly create text nodes when

MXML_TEXT_CALLBACK was specified (Bug #531)
This commit is contained in:
Michael R Sweet 2016-06-13 00:27:11 +00:00
parent 724d10e9e9
commit ff7486f265
3 changed files with 63 additions and 45 deletions

View File

@ -5,6 +5,8 @@ CHANGES IN Mini-XML 2.10
- The version number in mxml.h was wrong (Bug #532) - The version number in mxml.h was wrong (Bug #532)
- The mxml.spec file was out of date (Bug #521) - The mxml.spec file was out of date (Bug #521)
- mxmlLoad* and mxmlSAXLoad* did not properly create text nodes when
MXML_TEXT_CALLBACK was specified (Bug #531)
- mxmlDelete used a recursive algorithm which could require large - mxmlDelete used a recursive algorithm which could require large
amounts of stack space depending on the file (Bug #549, CVE-2016-4570) amounts of stack space depending on the file (Bug #549, CVE-2016-4570)
- mxmlWrite* used a recursive algorithm which could require large - mxmlWrite* used a recursive algorithm which could require large

View File

@ -1998,6 +1998,8 @@ mxml_load_data(
if (cb && parent) if (cb && parent)
type = (*cb)(parent); type = (*cb)(parent);
else
type = MXML_TEXT;
} }
else if (sax_cb) else if (sax_cb)
{ {

View File

@ -8,7 +8,7 @@
* ./testmxml input.xml [string-output.xml] >stdio-output.xml * ./testmxml input.xml [string-output.xml] >stdio-output.xml
* ./testmxml "<?xml ..." [string-output.xml] >stdio-output.xml * ./testmxml "<?xml ..." [string-output.xml] >stdio-output.xml
* *
* Copyright 2003-2014 by Michael R Sweet. * Copyright 2003-2016 by Michael R Sweet.
* *
* These coded instructions, statements, and computer programs are the * These coded instructions, statements, and computer programs are the
* property of Michael R Sweet and are protected by Federal copyright * property of Michael R Sweet and are protected by Federal copyright
@ -93,13 +93,13 @@ main(int argc, /* I - Number of command-line args */
if (!tree) if (!tree)
{ {
fputs("ERROR: No parent node in basic test!\n", stderr); fputs("ERROR: No parent node in basic test.\n", stderr);
return (1); return (1);
} }
if (tree->type != MXML_ELEMENT) if (tree->type != MXML_ELEMENT)
{ {
fprintf(stderr, "ERROR: Parent has type %s (%d), expected MXML_ELEMENT!\n", fprintf(stderr, "ERROR: Parent has type %s (%d), expected MXML_ELEMENT.\n",
tree->type < MXML_ELEMENT || tree->type > MXML_TEXT ? tree->type < MXML_ELEMENT || tree->type > MXML_TEXT ?
"UNKNOWN" : types[tree->type], tree->type); "UNKNOWN" : types[tree->type], tree->type);
mxmlDelete(tree); mxmlDelete(tree);
@ -108,7 +108,7 @@ main(int argc, /* I - Number of command-line args */
if (strcmp(tree->value.element.name, "element")) if (strcmp(tree->value.element.name, "element"))
{ {
fprintf(stderr, "ERROR: Parent value is \"%s\", expected \"element\"!\n", fprintf(stderr, "ERROR: Parent value is \"%s\", expected \"element\".\n",
tree->value.element.name); tree->value.element.name);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
@ -134,14 +134,14 @@ main(int argc, /* I - Number of command-line args */
if (!node) if (!node)
{ {
fputs("ERROR: No first child node in basic test!\n", stderr); fputs("ERROR: No first child node in basic test.\n", stderr);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
} }
if (node->type != MXML_INTEGER) if (node->type != MXML_INTEGER)
{ {
fprintf(stderr, "ERROR: First child has type %s (%d), expected MXML_INTEGER!\n", fprintf(stderr, "ERROR: First child has type %s (%d), expected MXML_INTEGER.\n",
node->type < MXML_ELEMENT || node->type > MXML_TEXT ? node->type < MXML_ELEMENT || node->type > MXML_TEXT ?
"UNKNOWN" : types[node->type], node->type); "UNKNOWN" : types[node->type], node->type);
mxmlDelete(tree); mxmlDelete(tree);
@ -150,7 +150,7 @@ main(int argc, /* I - Number of command-line args */
if (node->value.integer != 123) if (node->value.integer != 123)
{ {
fprintf(stderr, "ERROR: First child value is %d, expected 123!\n", fprintf(stderr, "ERROR: First child value is %d, expected 123.\n",
node->value.integer); node->value.integer);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
@ -160,14 +160,14 @@ main(int argc, /* I - Number of command-line args */
if (!node) if (!node)
{ {
fputs("ERROR: No second child node in basic test!\n", stderr); fputs("ERROR: No second child node in basic test.\n", stderr);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
} }
if (node->type != MXML_OPAQUE) if (node->type != MXML_OPAQUE)
{ {
fprintf(stderr, "ERROR: Second child has type %s (%d), expected MXML_OPAQUE!\n", fprintf(stderr, "ERROR: Second child has type %s (%d), expected MXML_OPAQUE.\n",
node->type < MXML_ELEMENT || node->type > MXML_TEXT ? node->type < MXML_ELEMENT || node->type > MXML_TEXT ?
"UNKNOWN" : types[node->type], node->type); "UNKNOWN" : types[node->type], node->type);
mxmlDelete(tree); mxmlDelete(tree);
@ -176,7 +176,7 @@ main(int argc, /* I - Number of command-line args */
if (!node->value.opaque || strcmp(node->value.opaque, "opaque")) if (!node->value.opaque || strcmp(node->value.opaque, "opaque"))
{ {
fprintf(stderr, "ERROR: Second child value is \"%s\", expected \"opaque\"!\n", fprintf(stderr, "ERROR: Second child value is \"%s\", expected \"opaque\".\n",
node->value.opaque ? node->value.opaque : "(null)"); node->value.opaque ? node->value.opaque : "(null)");
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
@ -186,14 +186,14 @@ main(int argc, /* I - Number of command-line args */
if (!node) if (!node)
{ {
fputs("ERROR: No third child node in basic test!\n", stderr); fputs("ERROR: No third child node in basic test.\n", stderr);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
} }
if (node->type != MXML_REAL) if (node->type != MXML_REAL)
{ {
fprintf(stderr, "ERROR: Third child has type %s (%d), expected MXML_REAL!\n", fprintf(stderr, "ERROR: Third child has type %s (%d), expected MXML_REAL.\n",
node->type < MXML_ELEMENT || node->type > MXML_TEXT ? node->type < MXML_ELEMENT || node->type > MXML_TEXT ?
"UNKNOWN" : types[node->type], node->type); "UNKNOWN" : types[node->type], node->type);
mxmlDelete(tree); mxmlDelete(tree);
@ -202,7 +202,7 @@ main(int argc, /* I - Number of command-line args */
if (node->value.real != 123.4f) if (node->value.real != 123.4f)
{ {
fprintf(stderr, "ERROR: Third child value is %f, expected 123.4!\n", fprintf(stderr, "ERROR: Third child value is %f, expected 123.4.\n",
node->value.real); node->value.real);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
@ -212,14 +212,14 @@ main(int argc, /* I - Number of command-line args */
if (!node) if (!node)
{ {
fputs("ERROR: No fourth child node in basic test!\n", stderr); fputs("ERROR: No fourth child node in basic test.\n", stderr);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
} }
if (node->type != MXML_TEXT) if (node->type != MXML_TEXT)
{ {
fprintf(stderr, "ERROR: Fourth child has type %s (%d), expected MXML_TEXT!\n", fprintf(stderr, "ERROR: Fourth child has type %s (%d), expected MXML_TEXT.\n",
node->type < MXML_ELEMENT || node->type > MXML_TEXT ? node->type < MXML_ELEMENT || node->type > MXML_TEXT ?
"UNKNOWN" : types[node->type], node->type); "UNKNOWN" : types[node->type], node->type);
mxmlDelete(tree); mxmlDelete(tree);
@ -229,7 +229,7 @@ main(int argc, /* I - Number of command-line args */
if (!node->value.text.whitespace || if (!node->value.text.whitespace ||
!node->value.text.string || strcmp(node->value.text.string, "text")) !node->value.text.string || strcmp(node->value.text.string, "text"))
{ {
fprintf(stderr, "ERROR: Fourth child value is %d,\"%s\", expected 1,\"text\"!\n", fprintf(stderr, "ERROR: Fourth child value is %d,\"%s\", expected 1,\"text\".\n",
node->value.text.whitespace, node->value.text.whitespace,
node->value.text.string ? node->value.text.string : "(null)"); node->value.text.string ? node->value.text.string : "(null)");
mxmlDelete(tree); mxmlDelete(tree);
@ -242,14 +242,14 @@ main(int argc, /* I - Number of command-line args */
if (!node) if (!node)
{ {
fprintf(stderr, "ERROR: No group #%d child node in basic test!\n", i + 1); fprintf(stderr, "ERROR: No group #%d child node in basic test.\n", i + 1);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
} }
if (node->type != MXML_ELEMENT) if (node->type != MXML_ELEMENT)
{ {
fprintf(stderr, "ERROR: Group child #%d has type %s (%d), expected MXML_ELEMENT!\n", fprintf(stderr, "ERROR: Group child #%d has type %s (%d), expected MXML_ELEMENT.\n",
i + 1, node->type < MXML_ELEMENT || node->type > MXML_TEXT ? i + 1, node->type < MXML_ELEMENT || node->type > MXML_TEXT ?
"UNKNOWN" : types[node->type], node->type); "UNKNOWN" : types[node->type], node->type);
mxmlDelete(tree); mxmlDelete(tree);
@ -310,7 +310,7 @@ main(int argc, /* I - Number of command-line args */
ind = mxmlIndexNew(tree, NULL, NULL); ind = mxmlIndexNew(tree, NULL, NULL);
if (!ind) if (!ind)
{ {
fputs("ERROR: Unable to create index of all nodes!\n", stderr); fputs("ERROR: Unable to create index of all nodes.\n", stderr);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
} }
@ -318,7 +318,7 @@ main(int argc, /* I - Number of command-line args */
if (ind->num_nodes != 10) if (ind->num_nodes != 10)
{ {
fprintf(stderr, "ERROR: Index of all nodes contains %d " fprintf(stderr, "ERROR: Index of all nodes contains %d "
"nodes; expected 10!\n", ind->num_nodes); "nodes; expected 10.\n", ind->num_nodes);
mxmlIndexDelete(ind); mxmlIndexDelete(ind);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
@ -327,7 +327,7 @@ main(int argc, /* I - Number of command-line args */
mxmlIndexReset(ind); mxmlIndexReset(ind);
if (!mxmlIndexFind(ind, "group", NULL)) if (!mxmlIndexFind(ind, "group", NULL))
{ {
fputs("ERROR: mxmlIndexFind for \"group\" failed!\n", stderr); fputs("ERROR: mxmlIndexFind for \"group\" failed.\n", stderr);
mxmlIndexDelete(ind); mxmlIndexDelete(ind);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
@ -338,7 +338,7 @@ main(int argc, /* I - Number of command-line args */
ind = mxmlIndexNew(tree, "group", NULL); ind = mxmlIndexNew(tree, "group", NULL);
if (!ind) if (!ind)
{ {
fputs("ERROR: Unable to create index of groups!\n", stderr); fputs("ERROR: Unable to create index of groups.\n", stderr);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
} }
@ -346,7 +346,7 @@ main(int argc, /* I - Number of command-line args */
if (ind->num_nodes != 4) if (ind->num_nodes != 4)
{ {
fprintf(stderr, "ERROR: Index of groups contains %d " fprintf(stderr, "ERROR: Index of groups contains %d "
"nodes; expected 4!\n", ind->num_nodes); "nodes; expected 4.\n", ind->num_nodes);
mxmlIndexDelete(ind); mxmlIndexDelete(ind);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
@ -355,7 +355,7 @@ main(int argc, /* I - Number of command-line args */
mxmlIndexReset(ind); mxmlIndexReset(ind);
if (!mxmlIndexEnum(ind)) if (!mxmlIndexEnum(ind))
{ {
fputs("ERROR: mxmlIndexEnum failed!\n", stderr); fputs("ERROR: mxmlIndexEnum failed.\n", stderr);
mxmlIndexDelete(ind); mxmlIndexDelete(ind);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
@ -366,7 +366,7 @@ main(int argc, /* I - Number of command-line args */
ind = mxmlIndexNew(tree, NULL, "type"); ind = mxmlIndexNew(tree, NULL, "type");
if (!ind) if (!ind)
{ {
fputs("ERROR: Unable to create index of type attributes!\n", stderr); fputs("ERROR: Unable to create index of type attributes.\n", stderr);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
} }
@ -374,7 +374,7 @@ main(int argc, /* I - Number of command-line args */
if (ind->num_nodes != 3) if (ind->num_nodes != 3)
{ {
fprintf(stderr, "ERROR: Index of type attributes contains %d " fprintf(stderr, "ERROR: Index of type attributes contains %d "
"nodes; expected 3!\n", ind->num_nodes); "nodes; expected 3.\n", ind->num_nodes);
mxmlIndexDelete(ind); mxmlIndexDelete(ind);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
@ -383,7 +383,7 @@ main(int argc, /* I - Number of command-line args */
mxmlIndexReset(ind); mxmlIndexReset(ind);
if (!mxmlIndexFind(ind, NULL, "string")) if (!mxmlIndexFind(ind, NULL, "string"))
{ {
fputs("ERROR: mxmlIndexFind for \"string\" failed!\n", stderr); fputs("ERROR: mxmlIndexFind for \"string\" failed.\n", stderr);
mxmlIndexDelete(ind); mxmlIndexDelete(ind);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
@ -394,7 +394,7 @@ main(int argc, /* I - Number of command-line args */
ind = mxmlIndexNew(tree, "group", "type"); ind = mxmlIndexNew(tree, "group", "type");
if (!ind) if (!ind)
{ {
fputs("ERROR: Unable to create index of elements and attributes!\n", stderr); fputs("ERROR: Unable to create index of elements and attributes.\n", stderr);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
} }
@ -402,7 +402,7 @@ main(int argc, /* I - Number of command-line args */
if (ind->num_nodes != 3) if (ind->num_nodes != 3)
{ {
fprintf(stderr, "ERROR: Index of elements and attributes contains %d " fprintf(stderr, "ERROR: Index of elements and attributes contains %d "
"nodes; expected 3!\n", ind->num_nodes); "nodes; expected 3.\n", ind->num_nodes);
mxmlIndexDelete(ind); mxmlIndexDelete(ind);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
@ -411,7 +411,7 @@ main(int argc, /* I - Number of command-line args */
mxmlIndexReset(ind); mxmlIndexReset(ind);
if (!mxmlIndexFind(ind, "group", "string")) if (!mxmlIndexFind(ind, "group", "string"))
{ {
fputs("ERROR: mxmlIndexFind for \"string\" failed!\n", stderr); fputs("ERROR: mxmlIndexFind for \"string\" failed.\n", stderr);
mxmlIndexDelete(ind); mxmlIndexDelete(ind);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
@ -438,13 +438,13 @@ main(int argc, /* I - Number of command-line args */
if (tree->child) if (tree->child)
{ {
fputs("ERROR: Child pointer not NULL after deleting all children!\n", stderr); fputs("ERROR: Child pointer not NULL after deleting all children.\n", stderr);
return (1); return (1);
} }
if (tree->last_child) if (tree->last_child)
{ {
fputs("ERROR: Last child pointer not NULL after deleting all children!\n", stderr); fputs("ERROR: Last child pointer not NULL after deleting all children.\n", stderr);
return (1); return (1);
} }
@ -474,7 +474,7 @@ main(int argc, /* I - Number of command-line args */
if (!tree) if (!tree)
{ {
fputs("Unable to read XML file with default callback!\n", stderr); fputs("Unable to read XML file with default callback.\n", stderr);
return (1); return (1);
} }
@ -489,14 +489,14 @@ main(int argc, /* I - Number of command-line args */
if ((node = mxmlFindPath(tree, "group/option/keyword")) == NULL) if ((node = mxmlFindPath(tree, "group/option/keyword")) == NULL)
{ {
fputs("Unable to find group/option/keyword element in XML tree!\n", stderr); fputs("Unable to find group/option/keyword element in XML tree.\n", stderr);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
} }
if (node->type != MXML_TEXT) if (node->type != MXML_TEXT)
{ {
fputs("No child node of group/option/keyword!\n", stderr); fputs("No child node of group/option/keyword.\n", stderr);
mxmlSaveFile(tree, stderr, MXML_NO_CALLBACK); mxmlSaveFile(tree, stderr, MXML_NO_CALLBACK);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
@ -504,7 +504,7 @@ main(int argc, /* I - Number of command-line args */
if ((text = mxmlGetText(node, NULL)) == NULL || strcmp(text, "InputSlot")) if ((text = mxmlGetText(node, NULL)) == NULL || strcmp(text, "InputSlot"))
{ {
fprintf(stderr, "Child node of group/option/value has value \"%s\" instead of \"InputSlot\"!\n", text ? text : "(null)"); fprintf(stderr, "Child node of group/option/value has value \"%s\" instead of \"InputSlot\".\n", text ? text : "(null)");
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
} }
@ -536,7 +536,7 @@ main(int argc, /* I - Number of command-line args */
if (!tree) if (!tree)
{ {
fputs("Unable to read XML file!\n", stderr); fputs("Unable to read XML file.\n", stderr);
return (1); return (1);
} }
@ -550,14 +550,14 @@ main(int argc, /* I - Number of command-line args */
if ((node = mxmlFindElement(tree, tree, "choice", NULL, NULL, if ((node = mxmlFindElement(tree, tree, "choice", NULL, NULL,
MXML_DESCEND)) == NULL) MXML_DESCEND)) == NULL)
{ {
fputs("Unable to find first <choice> element in XML tree!\n", stderr); fputs("Unable to find first <choice> element in XML tree.\n", stderr);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
} }
if (!mxmlFindElement(node, tree, "choice", NULL, NULL, MXML_NO_DESCEND)) if (!mxmlFindElement(node, tree, "choice", NULL, NULL, MXML_NO_DESCEND))
{ {
fputs("Unable to find second <choice> element in XML tree!\n", stderr); fputs("Unable to find second <choice> element in XML tree.\n", stderr);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
} }
@ -669,42 +669,42 @@ main(int argc, /* I - Number of command-line args */
{ {
if (event_counts[MXML_SAX_CDATA] != 1) if (event_counts[MXML_SAX_CDATA] != 1)
{ {
fprintf(stderr, "MXML_SAX_CDATA seen %d times, expected 1 times!\n", fprintf(stderr, "MXML_SAX_CDATA seen %d times, expected 1 times.\n",
event_counts[MXML_SAX_CDATA]); event_counts[MXML_SAX_CDATA]);
return (1); return (1);
} }
if (event_counts[MXML_SAX_COMMENT] != 1) if (event_counts[MXML_SAX_COMMENT] != 1)
{ {
fprintf(stderr, "MXML_SAX_COMMENT seen %d times, expected 1 times!\n", fprintf(stderr, "MXML_SAX_COMMENT seen %d times, expected 1 times.\n",
event_counts[MXML_SAX_COMMENT]); event_counts[MXML_SAX_COMMENT]);
return (1); return (1);
} }
if (event_counts[MXML_SAX_DATA] != 60) if (event_counts[MXML_SAX_DATA] != 60)
{ {
fprintf(stderr, "MXML_SAX_DATA seen %d times, expected 60 times!\n", fprintf(stderr, "MXML_SAX_DATA seen %d times, expected 60 times.\n",
event_counts[MXML_SAX_DATA]); event_counts[MXML_SAX_DATA]);
return (1); return (1);
} }
if (event_counts[MXML_SAX_DIRECTIVE] != 1) if (event_counts[MXML_SAX_DIRECTIVE] != 1)
{ {
fprintf(stderr, "MXML_SAX_DIRECTIVE seen %d times, expected 1 times!\n", fprintf(stderr, "MXML_SAX_DIRECTIVE seen %d times, expected 1 times.\n",
event_counts[MXML_SAX_DIRECTIVE]); event_counts[MXML_SAX_DIRECTIVE]);
return (1); return (1);
} }
if (event_counts[MXML_SAX_ELEMENT_CLOSE] != 20) if (event_counts[MXML_SAX_ELEMENT_CLOSE] != 20)
{ {
fprintf(stderr, "MXML_SAX_ELEMENT_CLOSE seen %d times, expected 20 times!\n", fprintf(stderr, "MXML_SAX_ELEMENT_CLOSE seen %d times, expected 20 times.\n",
event_counts[MXML_SAX_ELEMENT_CLOSE]); event_counts[MXML_SAX_ELEMENT_CLOSE]);
return (1); return (1);
} }
if (event_counts[MXML_SAX_ELEMENT_OPEN] != 20) if (event_counts[MXML_SAX_ELEMENT_OPEN] != 20)
{ {
fprintf(stderr, "MXML_SAX_ELEMENT_OPEN seen %d times, expected 20 times!\n", fprintf(stderr, "MXML_SAX_ELEMENT_OPEN seen %d times, expected 20 times.\n",
event_counts[MXML_SAX_ELEMENT_OPEN]); event_counts[MXML_SAX_ELEMENT_OPEN]);
return (1); return (1);
} }
@ -727,10 +727,24 @@ sax_cb(mxml_node_t *node, /* I - Current node */
mxml_sax_event_t event, /* I - SAX event */ mxml_sax_event_t event, /* I - SAX event */
void *data) /* I - SAX user data */ void *data) /* I - SAX user data */
{ {
static const char * const events[] = /* Events */
{
"MXML_SAX_CDATA", /* CDATA node */
"MXML_SAX_COMMENT", /* Comment node */
"MXML_SAX_DATA", /* Data node */
"MXML_SAX_DIRECTIVE", /* Processing directive node */
"MXML_SAX_ELEMENT_CLOSE", /* Element closed */
"MXML_SAX_ELEMENT_OPEN" /* Element opened */
};
/* /*
* This SAX callback just counts the different events. * This SAX callback just counts the different events.
*/ */
if (!node)
fprintf(stderr, "ERROR: SAX callback for event %s has NULL node.\n", events[event]);
event_counts[event] ++; event_counts[event] ++;
} }