mirror of
https://gitlab.gnome.org/GNOME/libxml2.git
synced 2025-04-24 18:50:07 +03:00
malloc-fail: Fix memory leak after calling xmlXPathNodeSetMerge
Destroy the first argument in xmlXPathNodeSetMerge if the function fails. This is somewhat dangerous but matches the expectations of users. Found with libFuzzer, see #344.
This commit is contained in:
parent
d31a0e8e75
commit
8d22e06588
78
xpath.c
78
xpath.c
@ -145,6 +145,9 @@
|
|||||||
* any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
|
* any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes);
|
||||||
|
|
||||||
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
|
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
|
||||||
/**
|
/**
|
||||||
* xmlXPathCmpNodesExt:
|
* xmlXPathCmpNodesExt:
|
||||||
@ -3869,6 +3872,8 @@ xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
|
|||||||
* if @val1 is NULL, a new set is created and copied from @val2
|
* if @val1 is NULL, a new set is created and copied from @val2
|
||||||
*
|
*
|
||||||
* Returns @val1 once extended or NULL in case of error.
|
* Returns @val1 once extended or NULL in case of error.
|
||||||
|
*
|
||||||
|
* Frees @val1 in case of error.
|
||||||
*/
|
*/
|
||||||
xmlNodeSetPtr
|
xmlNodeSetPtr
|
||||||
xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
|
xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
|
||||||
@ -3878,35 +3883,8 @@ xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
|
|||||||
if (val2 == NULL) return(val1);
|
if (val2 == NULL) return(val1);
|
||||||
if (val1 == NULL) {
|
if (val1 == NULL) {
|
||||||
val1 = xmlXPathNodeSetCreate(NULL);
|
val1 = xmlXPathNodeSetCreate(NULL);
|
||||||
if (val1 == NULL)
|
if (val1 == NULL)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
#if 0
|
|
||||||
/*
|
|
||||||
* TODO: The optimization won't work in every case, since
|
|
||||||
* those nasty namespace nodes need to be added with
|
|
||||||
* xmlXPathNodeSetDupNs() to the set; thus a pure
|
|
||||||
* memcpy is not possible.
|
|
||||||
* If there was a flag on the nodesetval, indicating that
|
|
||||||
* some temporary nodes are in, that would be helpful.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* Optimization: Create an equally sized node-set
|
|
||||||
* and memcpy the content.
|
|
||||||
*/
|
|
||||||
val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
|
|
||||||
if (val1 == NULL)
|
|
||||||
return(NULL);
|
|
||||||
if (val2->nodeNr != 0) {
|
|
||||||
if (val2->nodeNr == 1)
|
|
||||||
*(val1->nodeTab) = *(val2->nodeTab);
|
|
||||||
else {
|
|
||||||
memcpy(val1->nodeTab, val2->nodeTab,
|
|
||||||
val2->nodeNr * sizeof(xmlNodePtr));
|
|
||||||
}
|
|
||||||
val1->nodeNr = val2->nodeNr;
|
|
||||||
}
|
|
||||||
return(val1);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* @@ with_ns to check whether namespace nodes should be looked at @@ */
|
/* @@ with_ns to check whether namespace nodes should be looked at @@ */
|
||||||
@ -3945,7 +3923,7 @@ xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
|
|||||||
sizeof(xmlNodePtr));
|
sizeof(xmlNodePtr));
|
||||||
if (val1->nodeTab == NULL) {
|
if (val1->nodeTab == NULL) {
|
||||||
xmlXPathErrMemory(NULL, "merging nodeset\n");
|
xmlXPathErrMemory(NULL, "merging nodeset\n");
|
||||||
return(NULL);
|
goto error;
|
||||||
}
|
}
|
||||||
memset(val1->nodeTab, 0 ,
|
memset(val1->nodeTab, 0 ,
|
||||||
XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
|
XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
|
||||||
@ -3955,13 +3933,13 @@ xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
|
|||||||
|
|
||||||
if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
|
if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
|
||||||
xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
|
xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
|
||||||
return(NULL);
|
goto error;
|
||||||
}
|
}
|
||||||
temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
|
temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
|
||||||
sizeof(xmlNodePtr));
|
sizeof(xmlNodePtr));
|
||||||
if (temp == NULL) {
|
if (temp == NULL) {
|
||||||
xmlXPathErrMemory(NULL, "merging nodeset\n");
|
xmlXPathErrMemory(NULL, "merging nodeset\n");
|
||||||
return(NULL);
|
goto error;
|
||||||
}
|
}
|
||||||
val1->nodeTab = temp;
|
val1->nodeTab = temp;
|
||||||
val1->nodeMax *= 2;
|
val1->nodeMax *= 2;
|
||||||
@ -3971,13 +3949,17 @@ xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
|
|||||||
xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
|
xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
|
||||||
|
|
||||||
if (nsNode == NULL)
|
if (nsNode == NULL)
|
||||||
return(NULL);
|
goto error;
|
||||||
val1->nodeTab[val1->nodeNr++] = nsNode;
|
val1->nodeTab[val1->nodeNr++] = nsNode;
|
||||||
} else
|
} else
|
||||||
val1->nodeTab[val1->nodeNr++] = n2;
|
val1->nodeTab[val1->nodeNr++] = n2;
|
||||||
}
|
}
|
||||||
|
|
||||||
return(val1);
|
return(val1);
|
||||||
|
|
||||||
|
error:
|
||||||
|
xmlXPathFreeNodeSet(val1);
|
||||||
|
return(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3990,6 +3972,8 @@ xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
|
|||||||
* Checks for duplicate nodes. Clears set2.
|
* Checks for duplicate nodes. Clears set2.
|
||||||
*
|
*
|
||||||
* Returns @set1 once extended or NULL in case of error.
|
* Returns @set1 once extended or NULL in case of error.
|
||||||
|
*
|
||||||
|
* Frees @set1 in case of error.
|
||||||
*/
|
*/
|
||||||
static xmlNodeSetPtr
|
static xmlNodeSetPtr
|
||||||
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
|
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
|
||||||
@ -4018,7 +4002,6 @@ xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
|
|||||||
/*
|
/*
|
||||||
* Free the namespace node.
|
* Free the namespace node.
|
||||||
*/
|
*/
|
||||||
set2->nodeTab[i] = NULL;
|
|
||||||
xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
|
xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
|
||||||
goto skip_node;
|
goto skip_node;
|
||||||
}
|
}
|
||||||
@ -4032,7 +4015,7 @@ xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
|
|||||||
XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
|
XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
|
||||||
if (set1->nodeTab == NULL) {
|
if (set1->nodeTab == NULL) {
|
||||||
xmlXPathErrMemory(NULL, "merging nodeset\n");
|
xmlXPathErrMemory(NULL, "merging nodeset\n");
|
||||||
return(NULL);
|
goto error;
|
||||||
}
|
}
|
||||||
memset(set1->nodeTab, 0,
|
memset(set1->nodeTab, 0,
|
||||||
XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
|
XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
|
||||||
@ -4042,24 +4025,29 @@ xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
|
|||||||
|
|
||||||
if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
|
if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
|
||||||
xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
|
xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
|
||||||
return(NULL);
|
goto error;
|
||||||
}
|
}
|
||||||
temp = (xmlNodePtr *) xmlRealloc(
|
temp = (xmlNodePtr *) xmlRealloc(
|
||||||
set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
|
set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
|
||||||
if (temp == NULL) {
|
if (temp == NULL) {
|
||||||
xmlXPathErrMemory(NULL, "merging nodeset\n");
|
xmlXPathErrMemory(NULL, "merging nodeset\n");
|
||||||
return(NULL);
|
goto error;
|
||||||
}
|
}
|
||||||
set1->nodeTab = temp;
|
set1->nodeTab = temp;
|
||||||
set1->nodeMax *= 2;
|
set1->nodeMax *= 2;
|
||||||
}
|
}
|
||||||
set1->nodeTab[set1->nodeNr++] = n2;
|
set1->nodeTab[set1->nodeNr++] = n2;
|
||||||
skip_node:
|
skip_node:
|
||||||
{}
|
set2->nodeTab[i] = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
set2->nodeNr = 0;
|
set2->nodeNr = 0;
|
||||||
return(set1);
|
return(set1);
|
||||||
|
|
||||||
|
error:
|
||||||
|
xmlXPathFreeNodeSet(set1);
|
||||||
|
xmlXPathNodeSetClear(set2, 1);
|
||||||
|
return(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -4071,6 +4059,8 @@ skip_node:
|
|||||||
* Doesn't check for duplicate nodes. Clears set2.
|
* Doesn't check for duplicate nodes. Clears set2.
|
||||||
*
|
*
|
||||||
* Returns @set1 once extended or NULL in case of error.
|
* Returns @set1 once extended or NULL in case of error.
|
||||||
|
*
|
||||||
|
* Frees @set1 in case of error.
|
||||||
*/
|
*/
|
||||||
static xmlNodeSetPtr
|
static xmlNodeSetPtr
|
||||||
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
|
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
|
||||||
@ -4086,7 +4076,7 @@ xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
|
|||||||
XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
|
XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
|
||||||
if (set1->nodeTab == NULL) {
|
if (set1->nodeTab == NULL) {
|
||||||
xmlXPathErrMemory(NULL, "merging nodeset\n");
|
xmlXPathErrMemory(NULL, "merging nodeset\n");
|
||||||
return(NULL);
|
goto error;
|
||||||
}
|
}
|
||||||
memset(set1->nodeTab, 0,
|
memset(set1->nodeTab, 0,
|
||||||
XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
|
XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
|
||||||
@ -4096,22 +4086,28 @@ xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
|
|||||||
|
|
||||||
if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
|
if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
|
||||||
xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
|
xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
|
||||||
return(NULL);
|
goto error;
|
||||||
}
|
}
|
||||||
temp = (xmlNodePtr *) xmlRealloc(
|
temp = (xmlNodePtr *) xmlRealloc(
|
||||||
set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
|
set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
|
||||||
if (temp == NULL) {
|
if (temp == NULL) {
|
||||||
xmlXPathErrMemory(NULL, "merging nodeset\n");
|
xmlXPathErrMemory(NULL, "merging nodeset\n");
|
||||||
return(NULL);
|
goto error;
|
||||||
}
|
}
|
||||||
set1->nodeTab = temp;
|
set1->nodeTab = temp;
|
||||||
set1->nodeMax *= 2;
|
set1->nodeMax *= 2;
|
||||||
}
|
}
|
||||||
set1->nodeTab[set1->nodeNr++] = n2;
|
set1->nodeTab[set1->nodeNr++] = n2;
|
||||||
|
set2->nodeTab[i] = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
set2->nodeNr = 0;
|
set2->nodeNr = 0;
|
||||||
return(set1);
|
return(set1);
|
||||||
|
|
||||||
|
error:
|
||||||
|
xmlXPathFreeNodeSet(set1);
|
||||||
|
xmlXPathNodeSetClear(set2, 1);
|
||||||
|
return(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user