summaryrefslogtreecommitdiff
path: root/chromium/third_party/libxml/src/xpath.c
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/libxml/src/xpath.c')
-rw-r--r--chromium/third_party/libxml/src/xpath.c205
1 files changed, 116 insertions, 89 deletions
diff --git a/chromium/third_party/libxml/src/xpath.c b/chromium/third_party/libxml/src/xpath.c
index aa86fd3a754..94611509ea4 100644
--- a/chromium/third_party/libxml/src/xpath.c
+++ b/chromium/third_party/libxml/src/xpath.c
@@ -51,6 +51,7 @@
#include "private/buf.h"
#include "private/error.h"
+#include "private/xpath.h"
#ifdef LIBXML_PATTERN_ENABLED
#define XPATH_STREAMING
@@ -144,6 +145,9 @@
* 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
/**
* xmlXPathCmpNodesExt:
@@ -486,14 +490,21 @@ double xmlXPathNINF = 0.0;
/**
* xmlXPathInit:
*
- * DEPRECATED: This function will be made private. Call xmlInitParser to
- * initialize the library.
+ * DEPRECATED: Alias for xmlInitParser.
+ */
+void
+xmlXPathInit(void) {
+ xmlInitParser();
+}
+
+/**
+ * xmlInitXPathInternal:
*
* Initialize the XPath environment
*/
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
void
-xmlXPathInit(void) {
+xmlInitXPathInternal(void) {
#if defined(NAN) && defined(INFINITY)
xmlXPathNAN = NAN;
xmlXPathPINF = INFINITY;
@@ -704,6 +715,9 @@ xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
"%s", xmlXPathErrorMessages[error]);
return;
}
+ /* Only report the first error */
+ if (ctxt->error != 0)
+ return;
ctxt->error = error;
if (ctxt->context == NULL) {
__xmlRaiseError(NULL, NULL, NULL,
@@ -2327,6 +2341,8 @@ xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
* Wrap the Nodeset @val in a new xmlXPathObjectPtr
*
* Returns the created or reused object.
+ *
+ * In case of error the node set is destroyed and NULL is returned.
*/
static xmlXPathObjectPtr
xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
@@ -2865,7 +2881,15 @@ valuePop(xmlXPathParserContextPtr ctxt)
{
xmlXPathObjectPtr ret;
- if ((ctxt == NULL) || (ctxt->valueNr <= 0))
+ /*
+ * If a memory allocation failed, it can happen that valuePush doesn't
+ * push a value on the stack. If there's no error check before the
+ * corresponding valuePop call, we would pop an unrelated object which
+ * could lead to use-after-free errors later on. So we don't pop values
+ * if an error was signaled. The stack will be cleaned later in
+ * xmlXPathFreeParserContext.
+ */
+ if ((ctxt == NULL) || (ctxt->valueNr <= 0) || (ctxt->error != 0))
return (NULL);
if (ctxt->valueNr <= ctxt->valueFrame) {
@@ -2891,6 +2915,8 @@ valuePop(xmlXPathParserContextPtr ctxt)
* a memory error is recorded in the parser context.
*
* Returns the number of items on the value stack, or -1 in case of error.
+ *
+ * The object is destroyed in case of error.
*/
int
valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
@@ -2909,6 +2935,7 @@ valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
+ xmlXPathFreeObject(value);
return (-1);
}
tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
@@ -2916,6 +2943,7 @@ valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
sizeof(ctxt->valueTab[0]));
if (tmp == NULL) {
xmlXPathPErrMemory(ctxt, "pushing value\n");
+ xmlXPathFreeObject(value);
return (-1);
}
ctxt->valueMax *= 2;
@@ -3021,16 +3049,15 @@ xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
xmlXPathObjectPtr obj;
xmlNodeSetPtr ret;
- if (ctxt == NULL) return(NULL);
- if (ctxt->value == NULL) {
+ obj = valuePop(ctxt);
+ if (obj == NULL) {
xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
return(NULL);
}
- if (!xmlXPathStackIsNodeSet(ctxt)) {
+ if (obj->type != XPATH_NODESET) {
xmlXPathSetTypeError(ctxt);
return(NULL);
}
- obj = valuePop(ctxt);
ret = obj->nodesetval;
#if 0
/* to fix memory leak of not clearing obj->user */
@@ -3056,15 +3083,15 @@ xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
xmlXPathObjectPtr obj;
void * ret;
- if ((ctxt == NULL) || (ctxt->value == NULL)) {
+ obj = valuePop(ctxt);
+ if (obj == NULL) {
xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
return(NULL);
}
- if (ctxt->value->type != XPATH_USERS) {
+ if (obj->type != XPATH_USERS) {
xmlXPathSetTypeError(ctxt);
return(NULL);
}
- obj = valuePop(ctxt);
ret = obj->user;
obj->user = NULL;
xmlXPathReleaseObject(ctxt->context, obj);
@@ -3598,10 +3625,13 @@ xmlXPathNodeSetCreate(xmlNodePtr val) {
ret->nodeMax = XML_NODESET_DEFAULT;
if (val->type == XML_NAMESPACE_DECL) {
xmlNsPtr ns = (xmlNsPtr) val;
+ xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
- /* TODO: Check memory error. */
- ret->nodeTab[ret->nodeNr++] =
- xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
+ if (nsNode == NULL) {
+ xmlXPathFreeNodeSet(ret);
+ return(NULL);
+ }
+ ret->nodeTab[ret->nodeNr++] = nsNode;
} else
ret->nodeTab[ret->nodeNr++] = val;
}
@@ -3658,7 +3688,7 @@ xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
int
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
int i;
-
+ xmlNodePtr nsNode;
if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
(ns->type != XML_NAMESPACE_DECL) ||
@@ -3706,8 +3736,10 @@ xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
cur->nodeMax *= 2;
cur->nodeTab = temp;
}
- /* TODO: Check memory error. */
- cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
+ nsNode = xmlXPathNodeSetDupNs(node, ns);
+ if(nsNode == NULL)
+ return(-1);
+ cur->nodeTab[cur->nodeNr++] = nsNode;
return(0);
}
@@ -3764,10 +3796,11 @@ xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
}
if (val->type == XML_NAMESPACE_DECL) {
xmlNsPtr ns = (xmlNsPtr) val;
+ xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
- /* TODO: Check memory error. */
- cur->nodeTab[cur->nodeNr++] =
- xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
+ if (nsNode == NULL)
+ return(-1);
+ cur->nodeTab[cur->nodeNr++] = nsNode;
} else
cur->nodeTab[cur->nodeNr++] = val;
return(0);
@@ -3819,10 +3852,11 @@ xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
}
if (val->type == XML_NAMESPACE_DECL) {
xmlNsPtr ns = (xmlNsPtr) val;
+ xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
- /* TODO: Check memory error. */
- cur->nodeTab[cur->nodeNr++] =
- xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
+ if (nsNode == NULL)
+ return(-1);
+ cur->nodeTab[cur->nodeNr++] = nsNode;
} else
cur->nodeTab[cur->nodeNr++] = val;
return(0);
@@ -3837,6 +3871,8 @@ xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
* if @val1 is NULL, a new set is created and copied from @val2
*
* Returns @val1 once extended or NULL in case of error.
+ *
+ * Frees @val1 in case of error.
*/
xmlNodeSetPtr
xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
@@ -3846,35 +3882,8 @@ xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
if (val2 == NULL) return(val1);
if (val1 == NULL) {
val1 = xmlXPathNodeSetCreate(NULL);
- if (val1 == 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
+ if (val1 == NULL)
+ return (NULL);
}
/* @@ with_ns to check whether namespace nodes should be looked at @@ */
@@ -3913,7 +3922,7 @@ xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
sizeof(xmlNodePtr));
if (val1->nodeTab == NULL) {
xmlXPathErrMemory(NULL, "merging nodeset\n");
- return(NULL);
+ goto error;
}
memset(val1->nodeTab, 0 ,
XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
@@ -3923,28 +3932,33 @@ xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
- return(NULL);
+ goto error;
}
temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
sizeof(xmlNodePtr));
if (temp == NULL) {
xmlXPathErrMemory(NULL, "merging nodeset\n");
- return(NULL);
+ goto error;
}
val1->nodeTab = temp;
val1->nodeMax *= 2;
}
if (n2->type == XML_NAMESPACE_DECL) {
xmlNsPtr ns = (xmlNsPtr) n2;
+ xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
- /* TODO: Check memory error. */
- val1->nodeTab[val1->nodeNr++] =
- xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
+ if (nsNode == NULL)
+ goto error;
+ val1->nodeTab[val1->nodeNr++] = nsNode;
} else
val1->nodeTab[val1->nodeNr++] = n2;
}
return(val1);
+
+error:
+ xmlXPathFreeNodeSet(val1);
+ return(NULL);
}
@@ -3957,6 +3971,8 @@ xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
* Checks for duplicate nodes. Clears set2.
*
* Returns @set1 once extended or NULL in case of error.
+ *
+ * Frees @set1 in case of error.
*/
static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
@@ -3985,7 +4001,6 @@ xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
/*
* Free the namespace node.
*/
- set2->nodeTab[i] = NULL;
xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
goto skip_node;
}
@@ -3999,7 +4014,7 @@ xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
if (set1->nodeTab == NULL) {
xmlXPathErrMemory(NULL, "merging nodeset\n");
- return(NULL);
+ goto error;
}
memset(set1->nodeTab, 0,
XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
@@ -4009,24 +4024,29 @@ xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
- return(NULL);
+ goto error;
}
temp = (xmlNodePtr *) xmlRealloc(
set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
if (temp == NULL) {
xmlXPathErrMemory(NULL, "merging nodeset\n");
- return(NULL);
+ goto error;
}
set1->nodeTab = temp;
set1->nodeMax *= 2;
}
set1->nodeTab[set1->nodeNr++] = n2;
skip_node:
- {}
+ set2->nodeTab[i] = NULL;
}
}
set2->nodeNr = 0;
return(set1);
+
+error:
+ xmlXPathFreeNodeSet(set1);
+ xmlXPathNodeSetClear(set2, 1);
+ return(NULL);
}
/**
@@ -4038,6 +4058,8 @@ skip_node:
* Doesn't check for duplicate nodes. Clears set2.
*
* Returns @set1 once extended or NULL in case of error.
+ *
+ * Frees @set1 in case of error.
*/
static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
@@ -4053,7 +4075,7 @@ xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
if (set1->nodeTab == NULL) {
xmlXPathErrMemory(NULL, "merging nodeset\n");
- return(NULL);
+ goto error;
}
memset(set1->nodeTab, 0,
XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
@@ -4063,22 +4085,28 @@ xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
- return(NULL);
+ goto error;
}
temp = (xmlNodePtr *) xmlRealloc(
set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
if (temp == NULL) {
xmlXPathErrMemory(NULL, "merging nodeset\n");
- return(NULL);
+ goto error;
}
set1->nodeTab = temp;
set1->nodeMax *= 2;
}
set1->nodeTab[set1->nodeNr++] = n2;
+ set2->nodeTab[i] = NULL;
}
}
set2->nodeNr = 0;
return(set1);
+
+error:
+ xmlXPathFreeNodeSet(set1);
+ xmlXPathNodeSetClear(set2, 1);
+ return(NULL);
}
/**
@@ -4396,6 +4424,8 @@ xmlXPathNewNodeSetList(xmlNodeSetPtr val)
* Wrap the Nodeset @val in a new xmlXPathObjectPtr
*
* Returns the newly created object.
+ *
+ * In case of error the node set is destroyed and NULL is returned.
*/
xmlXPathObjectPtr
xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
@@ -4404,6 +4434,7 @@ xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
if (ret == NULL) {
xmlXPathErrMemory(NULL, "creating node set object\n");
+ xmlXPathFreeNodeSet(val);
return(NULL);
}
memset(ret, 0 , sizeof(xmlXPathObject));
@@ -5286,6 +5317,8 @@ xmlXPathNewString(const xmlChar *val) {
* Wraps the @val string into an XPath object.
*
* Returns the newly created object.
+ *
+ * Frees @val in case of error.
*/
xmlXPathObjectPtr
xmlXPathWrapString (xmlChar *val) {
@@ -5294,6 +5327,7 @@ xmlXPathWrapString (xmlChar *val) {
ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
if (ret == NULL) {
xmlXPathErrMemory(NULL, "creating string object\n");
+ xmlFree(val);
return(NULL);
}
memset(ret, 0 , sizeof(xmlXPathObject));
@@ -6815,6 +6849,7 @@ xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
xmlFree(str2);
xmlXPathNumberFunction(ctxt, 1);
val = valuePop(ctxt);
+ CHECK_ERROR0;
v = val->floatval;
xmlXPathReleaseObject(ctxt->context, val);
if (!xmlXPathIsNaN(v)) {
@@ -7029,6 +7064,8 @@ xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
valuePush(ctxt, arg2);
xmlXPathNumberFunction(ctxt, 1);
arg2 = valuePop(ctxt);
+ if (ctxt->error)
+ break;
/* Falls through. */
case XPATH_NUMBER:
/* Hand check NaN and Infinity equalities */
@@ -7094,6 +7131,8 @@ xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
valuePush(ctxt, arg1);
xmlXPathNumberFunction(ctxt, 1);
arg1 = valuePop(ctxt);
+ if (ctxt->error)
+ break;
/* Hand check NaN and Infinity equalities */
if (xmlXPathIsNaN(arg1->floatval) ||
xmlXPathIsNaN(arg2->floatval)) {
@@ -7393,21 +7432,13 @@ xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
xmlXPathNumberFunction(ctxt, 1);
arg1 = valuePop(ctxt);
}
- if (arg1->type != XPATH_NUMBER) {
- xmlXPathFreeObject(arg1);
- xmlXPathFreeObject(arg2);
- XP_ERROR0(XPATH_INVALID_OPERAND);
- }
if (arg2->type != XPATH_NUMBER) {
valuePush(ctxt, arg2);
xmlXPathNumberFunction(ctxt, 1);
arg2 = valuePop(ctxt);
}
- if (arg2->type != XPATH_NUMBER) {
- xmlXPathReleaseObject(ctxt->context, arg1);
- xmlXPathReleaseObject(ctxt->context, arg2);
- XP_ERROR0(XPATH_INVALID_OPERAND);
- }
+ if (ctxt->error)
+ goto error;
/*
* Add tests for infinity and nan
* => feedback on 3.4 for Inf and NaN
@@ -7457,6 +7488,7 @@ xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
}
}
}
+error:
xmlXPathReleaseObject(ctxt->context, arg1);
xmlXPathReleaseObject(ctxt->context, arg2);
return(ret);
@@ -9993,13 +10025,13 @@ xmlXPathStringEvalNumber(const xmlChar *str) {
#endif
if (cur == NULL) return(0);
while (IS_BLANK_CH(*cur)) cur++;
- if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
- return(xmlXPathNAN);
- }
if (*cur == '-') {
isneg = 1;
cur++;
}
+ if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
+ return(xmlXPathNAN);
+ }
#ifdef __GNUC__
/*
@@ -10256,7 +10288,10 @@ xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
} else {
XP_ERROR(XPATH_START_LITERAL_ERROR);
}
- if (ret == NULL) return;
+ if (ret == NULL) {
+ xmlXPathPErrMemory(ctxt, NULL);
+ return;
+ }
lit = xmlXPathCacheNewString(ctxt->context, ret);
if (lit == NULL) {
ctxt->error = XPATH_MEMORY_ERROR;
@@ -13644,8 +13679,6 @@ xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
xmlNodePtr cur = NULL, limit = NULL;
xmlStreamCtxtPtr patstream = NULL;
- int nb_nodes = 0;
-
if ((ctxt == NULL) || (comp == NULL))
return(-1);
max_depth = xmlPatternMaxDepth(comp);
@@ -13762,8 +13795,6 @@ next_node:
ctxt->opCount++;
}
- nb_nodes++;
-
switch (cur->type) {
case XML_ELEMENT_NODE:
case XML_TEXT_NODE:
@@ -13855,11 +13886,6 @@ scan_children:
done:
-#if 0
- printf("stream eval: checked %d nodes selected %d\n",
- nb_nodes, retObj->nodesetval->nodeNr);
-#endif
-
if (patstream)
xmlFreeStreamCtxt(patstream);
return(0);
@@ -14113,6 +14139,7 @@ xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
comp = xmlXPathNewCompExpr();
if (comp == NULL) {
xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
+ xmlFreePattern(stream);
return(NULL);
}
comp->stream = stream;