diff options
Diffstat (limited to 'chromium/third_party/libxml/src/xpath.c')
-rw-r--r-- | chromium/third_party/libxml/src/xpath.c | 205 |
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; |