Upgrade libxml2 to 1a360c1c2ec950f478d55b31722ecf78f5698e97

Also change upstream to github.

This change moves away from stable release. Because we need CMakeLists.txt. It is not in any release yet.

They are likely to release another stable version within this year. We can upgrade to that version when it is available.

Bug: 157157503
Change-Id: If6f245dbabe36a114563d209c8e100b7e3083f20
diff --git a/xpath.c b/xpath.c
index 5e3bb9f..673482a 100644
--- a/xpath.c
+++ b/xpath.c
@@ -343,7 +343,7 @@
     }
 
     /*
-     * Speedup using document order if availble.
+     * Speedup using document order if available.
      */
     if ((node1->type == XML_ELEMENT_NODE) &&
 	(node2->type == XML_ELEMENT_NODE) &&
@@ -411,7 +411,7 @@
     if (node1 == node2->next)
 	return(-1);
     /*
-     * Speedup using document order if availble.
+     * Speedup using document order if available.
      */
     if ((node1->type == XML_ELEMENT_NODE) &&
 	(node2->type == XML_ELEMENT_NODE) &&
@@ -435,7 +435,7 @@
 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
 
 /*
- * Wrapper for the Timsort argorithm from timsort.h
+ * Wrapper for the Timsort algorithm from timsort.h
  */
 #ifdef WITH_TIM_SORT
 #define SORT_NAME libxml_domnode
@@ -610,6 +610,8 @@
     "Invalid or incomplete context\n",
     "Stack usage error\n",
     "Forbidden variable\n",
+    "Operation limit exceeded\n",
+    "Recursion limit exceeded\n",
     "?? Unknown error ??\n"	/* Must be last in the list! */
 };
 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /	\
@@ -617,7 +619,7 @@
 /**
  * xmlXPathErrMemory:
  * @ctxt:  an XPath context
- * @extra:  extra informations
+ * @extra:  extra information
  *
  * Handle a redefinition of attribute error
  */
@@ -625,6 +627,7 @@
 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
 {
     if (ctxt != NULL) {
+        xmlResetError(&ctxt->lastError);
         if (extra) {
             xmlChar buf[200];
 
@@ -659,7 +662,7 @@
 /**
  * xmlXPathPErrMemory:
  * @ctxt:  an XPath parser context
- * @extra:  extra informations
+ * @extra:  extra information
  *
  * Handle a redefinition of attribute error
  */
@@ -747,6 +750,32 @@
     xmlXPathErr(ctxt, no);
 }
 
+/**
+ * xmlXPathCheckOpLimit:
+ * @ctxt:  the XPath Parser context
+ * @opCount:  the number of operations to be added
+ *
+ * Adds opCount to the running total of operations and returns -1 if the
+ * operation limit is exceeded. Returns 0 otherwise.
+ */
+static int
+xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
+    xmlXPathContextPtr xpctxt = ctxt->context;
+
+    if ((opCount > xpctxt->opLimit) ||
+        (xpctxt->opCount > xpctxt->opLimit - opCount)) {
+        xpctxt->opCount = xpctxt->opLimit;
+        xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
+        return(-1);
+    }
+
+    xpctxt->opCount += opCount;
+    return(0);
+}
+
+#define OP_LIMIT_EXCEEDED(ctxt, n) \
+    ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
+
 /************************************************************************
  *									*
  *			Utilities					*
@@ -1076,14 +1105,15 @@
  * Returns -1 in case of failure, the index otherwise
  */
 static int
-xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
+xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
    xmlXPathOp op, int value,
    int value2, int value3, void *value4, void *value5) {
+    xmlXPathCompExprPtr comp = ctxt->comp;
     if (comp->nbStep >= comp->maxStep) {
 	xmlXPathStepOp *real;
 
         if (comp->maxStep >= XPATH_MAX_STEPS) {
-	    xmlXPathErrMemory(NULL, "adding step\n");
+	    xmlXPathPErrMemory(ctxt, "adding step\n");
 	    return(-1);
         }
 	comp->maxStep *= 2;
@@ -1091,7 +1121,7 @@
 		                      comp->maxStep * sizeof(xmlXPathStepOp));
 	if (real == NULL) {
 	    comp->maxStep /= 2;
-	    xmlXPathErrMemory(NULL, "adding step\n");
+	    xmlXPathPErrMemory(ctxt, "adding step\n");
 	    return(-1);
 	}
 	comp->steps = real;
@@ -1153,20 +1183,20 @@
 }
 
 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)	\
-    xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),			\
+    xmlXPathCompExprAdd(ctxt, (op1), (op2),			\
 	                (op), (val), (val2), (val3), (val4), (val5))
 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)			\
-    xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,		\
+    xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,		\
 	                (op), (val), (val2), (val3), (val4), (val5))
 
 #define PUSH_LEAVE_EXPR(op, val, val2)					\
-xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
+xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
 
 #define PUSH_UNARY_EXPR(op, ch, val, val2)				\
-xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
+xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
 
 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)			\
-xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),			\
+xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),			\
 			(val), (val2), 0 ,NULL ,NULL)
 
 /************************************************************************
@@ -1716,7 +1746,6 @@
 static int xmlXPathDebugObjMaxXSLTTree = 0;
 static int xmlXPathDebugObjMaxAll = 0;
 
-/* REVISIT TODO: Make this static when committing */
 static void
 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
 {
@@ -2031,7 +2060,6 @@
     xmlXPathDebugObjCounterAll--;
 }
 
-/* REVISIT TODO: Make this static when committing */
 static void
 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
 {
@@ -2226,7 +2254,7 @@
  *
  * @ctxt:  the XPath context
  * @active: enables/disables (creates/frees) the cache
- * @value: a value with semantics dependant on @options
+ * @value: a value with semantics dependent on @options
  * @options: options (currently only the value 0 is used)
  *
  * Creates/frees an object cache on the XPath context.
@@ -2386,7 +2414,7 @@
 	{
 	    xmlXPathObjectPtr ret;
 	    /*
-	    * Use the nodset-cache.
+	    * Use the nodeset-cache.
 	    */
 	    ret = (xmlXPathObjectPtr)
 		cache->nodesetObjs->items[--cache->nodesetObjs->number];
@@ -2396,6 +2424,7 @@
 		if ((ret->nodesetval->nodeMax == 0) ||
 		    (val->type == XML_NAMESPACE_DECL))
 		{
+                    /* TODO: Check memory error. */
 		    xmlXPathNodeSetAddUnique(ret->nodesetval, val);
 		} else {
 		    ret->nodesetval->nodeTab[0] = val;
@@ -2842,29 +2871,36 @@
  * @ctxt:  an XPath evaluation context
  * @value:  the XPath object
  *
- * Pushes a new XPath object on top of the value stack
+ * Pushes a new XPath object on top of the value stack. If value is NULL,
+ * a memory error is recorded in the parser context.
  *
- * returns the number of items on the value stack
+ * Returns the number of items on the value stack, or -1 in case of error.
  */
 int
 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
 {
-    if ((ctxt == NULL) || (value == NULL)) return(-1);
+    if (ctxt == NULL) return(-1);
+    if (value == NULL) {
+        /*
+         * A NULL value typically indicates that a memory allocation failed,
+         * so we set ctxt->error here to propagate the error.
+         */
+	ctxt->error = XPATH_MEMORY_ERROR;
+        return(-1);
+    }
     if (ctxt->valueNr >= ctxt->valueMax) {
         xmlXPathObjectPtr *tmp;
 
         if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
-            xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
-            ctxt->error = XPATH_MEMORY_ERROR;
-            return (0);
+            xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
+            return (-1);
         }
         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
                                              2 * ctxt->valueMax *
                                              sizeof(ctxt->valueTab[0]));
         if (tmp == NULL) {
-            xmlXPathErrMemory(NULL, "pushing value\n");
-            ctxt->error = XPATH_MEMORY_ERROR;
-            return (0);
+            xmlXPathPErrMemory(ctxt, "pushing value\n");
+            return (-1);
         }
         ctxt->valueMax *= 2;
 	ctxt->valueTab = tmp;
@@ -3320,7 +3356,7 @@
 	return(-1);
 
     /*
-     * Speedup using document order if availble.
+     * Speedup using document order if available.
      */
     if ((node1->type == XML_ELEMENT_NODE) &&
 	(node2->type == XML_ELEMENT_NODE) &&
@@ -3383,7 +3419,7 @@
     if (node1 == node2->next)
 	return(-1);
     /*
-     * Speedup using document order if availble.
+     * Speedup using document order if available.
      */
     if ((node1->type == XML_ELEMENT_NODE) &&
 	(node2->type == XML_ELEMENT_NODE) &&
@@ -3547,6 +3583,7 @@
 	if (val->type == XML_NAMESPACE_DECL) {
 	    xmlNsPtr ns = (xmlNsPtr) val;
 
+            /* TODO: Check memory error. */
 	    ret->nodeTab[ret->nodeNr++] =
 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
 	} else
@@ -3556,37 +3593,6 @@
 }
 
 /**
- * xmlXPathNodeSetCreateSize:
- * @size:  the initial size of the set
- *
- * Create a new xmlNodeSetPtr of type double and of value @val
- *
- * Returns the newly created object.
- */
-static xmlNodeSetPtr
-xmlXPathNodeSetCreateSize(int size) {
-    xmlNodeSetPtr ret;
-
-    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
-    if (ret == NULL) {
-        xmlXPathErrMemory(NULL, "creating nodeset\n");
-	return(NULL);
-    }
-    memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
-    if (size < XML_NODESET_DEFAULT)
-	size = XML_NODESET_DEFAULT;
-    ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
-    if (ret->nodeTab == NULL) {
-	xmlXPathErrMemory(NULL, "creating nodeset\n");
-	xmlFree(ret);
-	return(NULL);
-    }
-    memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
-    ret->nodeMax = size;
-    return(ret);
-}
-
-/**
  * xmlXPathNodeSetContains:
  * @cur:  the node-set
  * @val:  the node
@@ -3684,6 +3690,7 @@
         cur->nodeMax *= 2;
 	cur->nodeTab = temp;
     }
+    /* TODO: Check memory error. */
     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
     return(0);
 }
@@ -3742,6 +3749,7 @@
     if (val->type == XML_NAMESPACE_DECL) {
 	xmlNsPtr ns = (xmlNsPtr) val;
 
+        /* TODO: Check memory error. */
 	cur->nodeTab[cur->nodeNr++] =
 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
     } else
@@ -3796,6 +3804,7 @@
     if (val->type == XML_NAMESPACE_DECL) {
 	xmlNsPtr ns = (xmlNsPtr) val;
 
+        /* TODO: Check memory error. */
 	cur->nodeTab[cur->nodeNr++] =
 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
     } else
@@ -3830,7 +3839,7 @@
 	*  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 helpfull.
+	*  some temporary nodes are in, that would be helpful.
 	*/
 	/*
 	* Optimization: Create an equally sized node-set
@@ -3912,6 +3921,7 @@
 	if (n2->type == XML_NAMESPACE_DECL) {
 	    xmlNsPtr ns = (xmlNsPtr) n2;
 
+            /* TODO: Check memory error. */
 	    val1->nodeTab[val1->nodeNr++] =
 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
 	} else
@@ -3926,49 +3936,23 @@
  * xmlXPathNodeSetMergeAndClear:
  * @set1:  the first NodeSet or NULL
  * @set2:  the second NodeSet
- * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
  *
- * Merges two nodesets, all nodes from @set2 are added to @set1
- * if @set1 is NULL, a new set is created and copied from @set2.
+ * Merges two nodesets, all nodes from @set2 are added to @set1.
  * Checks for duplicate nodes. Clears set2.
  *
  * Returns @set1 once extended or NULL in case of error.
  */
 static xmlNodeSetPtr
-xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
-			     int hasNullEntries)
+xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
 {
-    if ((set1 == NULL) && (hasNullEntries == 0)) {
-	/*
-	* Note that doing a memcpy of the list, namespace nodes are
-	* just assigned to set1, since set2 is cleared anyway.
-	*/
-	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
-	if (set1 == NULL)
-	    return(NULL);
-	if (set2->nodeNr != 0) {
-	    memcpy(set1->nodeTab, set2->nodeTab,
-		set2->nodeNr * sizeof(xmlNodePtr));
-	    set1->nodeNr = set2->nodeNr;
-	}
-    } else {
+    {
 	int i, j, initNbSet1;
 	xmlNodePtr n1, n2;
 
-	if (set1 == NULL)
-            set1 = xmlXPathNodeSetCreate(NULL);
-        if (set1 == NULL)
-            return (NULL);
-
 	initNbSet1 = set1->nodeNr;
 	for (i = 0;i < set2->nodeNr;i++) {
 	    n2 = set2->nodeTab[i];
 	    /*
-	    * Skip NULLed entries.
-	    */
-	    if (n2 == NULL)
-		continue;
-	    /*
 	    * Skip duplicates.
 	    */
 	    for (j = 0; j < initNbSet1; j++) {
@@ -4033,49 +4017,21 @@
  * xmlXPathNodeSetMergeAndClearNoDupls:
  * @set1:  the first NodeSet or NULL
  * @set2:  the second NodeSet
- * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
  *
- * Merges two nodesets, all nodes from @set2 are added to @set1
- * if @set1 is NULL, a new set is created and copied from @set2.
- * Doesn't chack for duplicate nodes. Clears set2.
+ * Merges two nodesets, all nodes from @set2 are added to @set1.
+ * Doesn't check for duplicate nodes. Clears set2.
  *
  * Returns @set1 once extended or NULL in case of error.
  */
 static xmlNodeSetPtr
-xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
-				    int hasNullEntries)
+xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
 {
-    if (set2 == NULL)
-	return(set1);
-    if ((set1 == NULL) && (hasNullEntries == 0)) {
-	/*
-	* Note that doing a memcpy of the list, namespace nodes are
-	* just assigned to set1, since set2 is cleared anyway.
-	*/
-	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
-	if (set1 == NULL)
-	    return(NULL);
-	if (set2->nodeNr != 0) {
-	    memcpy(set1->nodeTab, set2->nodeTab,
-		set2->nodeNr * sizeof(xmlNodePtr));
-	    set1->nodeNr = set2->nodeNr;
-	}
-    } else {
+    {
 	int i;
 	xmlNodePtr n2;
 
-	if (set1 == NULL)
-	    set1 = xmlXPathNodeSetCreate(NULL);
-        if (set1 == NULL)
-            return (NULL);
-
 	for (i = 0;i < set2->nodeNr;i++) {
 	    n2 = set2->nodeTab[i];
-	    /*
-	    * Skip NULLed entries.
-	    */
-	    if (n2 == NULL)
-		continue;
 	    if (set1->nodeMax == 0) {
 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
@@ -4346,6 +4302,7 @@
     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
     ret->type = XPATH_NODESET;
     ret->boolval = 0;
+    /* TODO: Check memory error. */
     ret->nodesetval = xmlXPathNodeSetCreate(val);
     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
 #ifdef XP_DEBUG_OBJ_USAGE
@@ -4406,6 +4363,7 @@
         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
         if (ret) {
             for (i = 1; i < val->nodeNr; ++i) {
+                /* TODO: Propagate memory error. */
                 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
 		    < 0) break;
 	    }
@@ -4477,6 +4435,7 @@
     if (xmlXPathNodeSetIsEmpty(nodes2))
 	return(nodes1);
 
+    /* TODO: Check memory error. */
     ret = xmlXPathNodeSetCreate(NULL);
     if (xmlXPathNodeSetIsEmpty(nodes1))
 	return(ret);
@@ -4486,6 +4445,7 @@
     for (i = 0; i < l1; i++) {
 	cur = xmlXPathNodeSetItem(nodes1, i);
 	if (!xmlXPathNodeSetContains(nodes2, cur)) {
+            /* TODO: Propagate memory error. */
 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
 	        break;
 	}
@@ -4522,6 +4482,7 @@
     for (i = 0; i < l1; i++) {
 	cur = xmlXPathNodeSetItem(nodes1, i);
 	if (xmlXPathNodeSetContains(nodes2, cur)) {
+            /* TODO: Propagate memory error. */
 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
 	        break;
 	}
@@ -4560,6 +4521,7 @@
 	strval = xmlXPathCastNodeToString(cur);
 	if (xmlHashLookup(hash, strval) == NULL) {
 	    xmlHashAddEntry(hash, strval, strval);
+            /* TODO: Propagate memory error. */
 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
 	        break;
 	} else {
@@ -4653,6 +4615,7 @@
 	cur = xmlXPathNodeSetItem(nodes, i);
 	if (cur == node)
 	    break;
+        /* TODO: Propagate memory error. */
 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
 	    break;
     }
@@ -4758,6 +4721,7 @@
 	cur = xmlXPathNodeSetItem(nodes, i);
 	if (cur == node)
 	    break;
+        /* TODO: Propagate memory error. */
 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
 	    break;
     }
@@ -5457,6 +5421,7 @@
 	    break;
 #endif
 	case XPATH_NODESET:
+            /* TODO: Check memory error. */
 	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
 	    /* Do not deallocate the copied tree value */
 	    ret->boolval = 0;
@@ -5944,7 +5909,7 @@
 	return(NAN);
     switch (val->type) {
     case XPATH_UNDEFINED:
-#ifdef DEGUB_EXPR
+#ifdef DEBUG_EXPR
 	xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
 #endif
 	ret = NAN;
@@ -6153,6 +6118,9 @@
     ret->contextSize = -1;
     ret->proximityPosition = -1;
 
+    ret->maxDepth = INT_MAX;
+    ret->maxParserDepth = INT_MAX;
+
 #ifdef XP_DEFAULT_CACHE_ON
     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
 	xmlXPathFreeContext(ret);
@@ -6643,6 +6611,7 @@
 
     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
     if (values2 == NULL) {
+        /* TODO: Propagate memory error. */
         xmlXPathErrMemory(NULL, "comparing nodesets\n");
 	xmlXPathFreeObject(arg1);
 	xmlXPathFreeObject(arg2);
@@ -6903,11 +6872,13 @@
 
     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
     if (values1 == NULL) {
+        /* TODO: Propagate memory error. */
         xmlXPathErrMemory(NULL, "comparing nodesets\n");
 	return(0);
     }
     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
     if (hashs1 == NULL) {
+        /* TODO: Propagate memory error. */
         xmlXPathErrMemory(NULL, "comparing nodesets\n");
 	xmlFree(values1);
 	return(0);
@@ -6915,6 +6886,7 @@
     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
     if (values2 == NULL) {
+        /* TODO: Propagate memory error. */
         xmlXPathErrMemory(NULL, "comparing nodesets\n");
 	xmlFree(hashs1);
 	xmlFree(values1);
@@ -6922,6 +6894,7 @@
     }
     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
     if (hashs2 == NULL) {
+        /* TODO: Propagate memory error. */
         xmlXPathErrMemory(NULL, "comparing nodesets\n");
 	xmlFree(hashs1);
 	xmlFree(values1);
@@ -7551,6 +7524,7 @@
  * The numeric operators convert their operands to numbers as if
  * by calling the number function.
  */
+ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
 void
 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
     xmlXPathObjectPtr arg;
@@ -7623,7 +7597,7 @@
  * Used for merging node sets in xmlXPathCollectAndTest().
  */
 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
-		    (xmlNodeSetPtr, xmlNodeSetPtr, int);
+		    (xmlNodeSetPtr, xmlNodeSetPtr);
 
 
 /**
@@ -8562,28 +8536,9 @@
 
     if ((cur == NULL) || (cur->nodesetval == NULL))
 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
-    else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
+    else
 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
 	    (double) cur->nodesetval->nodeNr));
-    } else {
-	if ((cur->nodesetval->nodeNr != 1) ||
-	    (cur->nodesetval->nodeTab == NULL)) {
-	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
-	} else {
-	    xmlNodePtr tmp;
-	    int i = 0;
-
-	    tmp = cur->nodesetval->nodeTab[0];
-	    if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
-		tmp = tmp->children;
-		while (tmp != NULL) {
-		    tmp = tmp->next;
-		    i++;
-		}
-	    }
-	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
-	}
-    }
     xmlXPathReleaseObject(ctxt->context, cur);
 }
 
@@ -8621,7 +8576,7 @@
 	     * We used to check the fact that the value passed
 	     * was an NCName, but this generated much troubles for
 	     * me and Aleksey Sanin, people blatantly violated that
-	     * constaint, like Visa3D spec.
+	     * constraint, like Visa3D spec.
 	     * if (xmlValidateNCName(ID, 1) == 0)
 	     */
 	    attr = xmlGetID(doc, ID);
@@ -8632,6 +8587,7 @@
 		    elem = (xmlNodePtr) attr;
 		else
 		    elem = NULL;
+                /* TODO: Check memory error. */
 		if (elem != NULL)
 		    xmlXPathNodeSetAdd(ret, elem);
 	    }
@@ -8675,18 +8631,15 @@
 	xmlNodeSetPtr ns;
 	int i;
 
+        /* TODO: Check memory error. */
 	ret = xmlXPathNodeSetCreate(NULL);
-        /*
-         * FIXME -- in an out-of-memory condition this will behave badly.
-         * The solution is not clear -- we already popped an item from
-         * ctxt, so the object is in a corrupt state.
-         */
 
 	if (obj->nodesetval != NULL) {
 	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
 		tokens =
 		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
 		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
+                /* TODO: Check memory error. */
 		ret = xmlXPathNodeSetMerge(ret, ns);
 		xmlXPathFreeNodeSet(ns);
 		if (tokens != NULL)
@@ -8698,6 +8651,7 @@
 	return;
     }
     obj = xmlXPathCacheConvertString(ctxt->context, obj);
+    if (obj == NULL) return;
     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
     xmlXPathReleaseObject(ctxt->context, obj);
@@ -9135,8 +9089,7 @@
 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
     xmlXPathObjectPtr str, start, len;
     double le=0, in;
-    int i, l, m;
-    xmlChar *ret;
+    int i = 1, j = INT_MAX;
 
     if (nargs < 2) {
 	CHECK_ARITY(2);
@@ -9163,67 +9116,42 @@
     CAST_TO_STRING;
     CHECK_TYPE(XPATH_STRING);
     str = valuePop(ctxt);
-    m = xmlUTF8Strlen((const unsigned char *)str->stringval);
 
-    /*
-     * If last pos not present, calculate last position
-    */
-    if (nargs != 3) {
-	le = (double)m;
-	if (in < 1.0)
-	    in = 1.0;
+    if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
+        i = INT_MAX;
+    } else if (in >= 1.0) {
+        i = (int)in;
+        if (in - floor(in) >= 0.5)
+            i += 1;
     }
 
-    /* Need to check for the special cases where either
-     * the index is NaN, the length is NaN, or both
-     * arguments are infinity (relying on Inf + -Inf = NaN)
-     */
-    if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
-        /*
-         * To meet the requirements of the spec, the arguments
-	 * must be converted to integer format before
-	 * initial index calculations are done
-         *
-         * First we go to integer form, rounding up
-	 * and checking for special cases
-         */
-        i = (int) in;
-        if (((double)i)+0.5 <= in) i++;
+    if (nargs == 3) {
+        double rin, rle, end;
 
-	if (xmlXPathIsInf(le) == 1) {
-	    l = m;
-	    if (i < 1)
-		i = 1;
-	}
-	else if (xmlXPathIsInf(le) == -1 || le < 0.0)
-	    l = 0;
-	else {
-	    l = (int) le;
-	    if (((double)l)+0.5 <= le) l++;
-	}
+        rin = floor(in);
+        if (in - rin >= 0.5)
+            rin += 1.0;
 
-	/* Now we normalize inidices */
-        i -= 1;
-        l += i;
-        if (i < 0)
-            i = 0;
-        if (l > m)
-            l = m;
+        rle = floor(le);
+        if (le - rle >= 0.5)
+            rle += 1.0;
 
-        /* number of chars to copy */
-        l -= i;
-
-        ret = xmlUTF8Strsub(str->stringval, i, l);
+        end = rin + rle;
+        if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
+            j = 1;
+        } else if (end < INT_MAX) {
+            j = (int)end;
+        }
     }
-    else {
-        ret = NULL;
-    }
-    if (ret == NULL)
-	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
-    else {
+
+    if (i < j) {
+        xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);
 	valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
 	xmlFree(ret);
+    } else {
+	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
     }
+
     xmlXPathReleaseObject(ctxt->context, str);
 }
 
@@ -9682,7 +9610,12 @@
     CAST_TO_NUMBER;
     CHECK_TYPE(XPATH_NUMBER);
 
+#ifdef _AIX
+    /* Work around buggy ceil() function on AIX */
+    ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
+#else
     ctxt->value->floatval = ceil(ctxt->value->floatval);
+#endif
 }
 
 /**
@@ -9999,15 +9932,19 @@
 		   (IS_COMBINING(c)) ||
 		   (IS_EXTENDER(c))) {
 		if (len + 10 > max) {
+                    xmlChar *tmp;
                     if (max > XML_MAX_NAME_LENGTH) {
+                        xmlFree(buffer);
                         XP_ERRORNULL(XPATH_EXPR_ERROR);
                     }
 		    max *= 2;
-		    buffer = (xmlChar *) xmlRealloc(buffer,
-			                            max * sizeof(xmlChar));
-		    if (buffer == NULL) {
+		    tmp = (xmlChar *) xmlRealloc(buffer,
+			                         max * sizeof(xmlChar));
+		    if (tmp == NULL) {
+                        xmlFree(buffer);
 			XP_ERRORNULL(XPATH_MEMORY_ERROR);
 		    }
+                    buffer = tmp;
 		}
 		COPY_BUF(l,buffer,len,c);
 		NEXTL(l);
@@ -10149,6 +10086,7 @@
     int ok = 0;
     int exponent = 0;
     int is_exponent_negative = 0;
+    xmlXPathObjectPtr num;
 #ifdef __GNUC__
     unsigned long tmp = 0;
     double temp;
@@ -10221,8 +10159,13 @@
             exponent = -exponent;
         ret *= pow(10.0, (double) exponent);
     }
-    PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
-                   xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
+    num = xmlXPathCacheNewFloat(ctxt->context, ret);
+    if (num == NULL) {
+	ctxt->error = XPATH_MEMORY_ERROR;
+    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
+                              NULL) == -1) {
+        xmlXPathReleaseObject(ctxt->context, num);
+    }
 }
 
 /**
@@ -10284,6 +10227,7 @@
 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
     const xmlChar *q;
     xmlChar *ret = NULL;
+    xmlXPathObjectPtr lit;
 
     if (CUR == '"') {
         NEXT;
@@ -10311,8 +10255,13 @@
 	XP_ERROR(XPATH_START_LITERAL_ERROR);
     }
     if (ret == NULL) return;
-    PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
-	           xmlXPathCacheNewString(ctxt->context, ret), NULL);
+    lit = xmlXPathCacheNewString(ctxt->context, ret);
+    if (lit == NULL) {
+	ctxt->error = XPATH_MEMORY_ERROR;
+    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
+                              NULL) == -1) {
+        xmlXPathReleaseObject(ctxt->context, lit);
+    }
     xmlFree(ret);
 }
 
@@ -10349,8 +10298,10 @@
 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
     }
     ctxt->comp->last = -1;
-    PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
-	           name, prefix);
+    if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
+        xmlFree(prefix);
+        xmlFree(name);
+    }
     SKIP_BLANKS;
     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
 	XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
@@ -10457,8 +10408,10 @@
 	    SKIP_BLANKS;
 	}
     }
-    PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
-	           name, prefix);
+    if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
+        xmlFree(prefix);
+        xmlFree(name);
+    }
     NEXT;
     SKIP_BLANKS;
 }
@@ -10899,10 +10852,7 @@
     xmlXPathCompAdditiveExpr(ctxt);
     CHECK_ERROR;
     SKIP_BLANKS;
-    while ((CUR == '<') ||
-           (CUR == '>') ||
-           ((CUR == '<') && (NXT(1) == '=')) ||
-           ((CUR == '>') && (NXT(1) == '='))) {
+    while ((CUR == '<') || (CUR == '>')) {
 	int inf, strict;
 	int op1 = ctxt->comp->last;
 
@@ -10995,6 +10945,14 @@
  */
 static void
 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
+    xmlXPathContextPtr xpctxt = ctxt->context;
+
+    if (xpctxt != NULL) {
+        if (xpctxt->depth >= xpctxt->maxParserDepth)
+            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
+        xpctxt->depth += 1;
+    }
+
     xmlXPathCompAndExpr(ctxt);
     CHECK_ERROR;
     SKIP_BLANKS;
@@ -11016,6 +10974,9 @@
 	*/
 	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
     }
+
+    if (xpctxt != NULL)
+        xpctxt->depth -= 1;
 }
 
 /**
@@ -11091,7 +11052,7 @@
  */
 static xmlChar *
 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
-	             xmlXPathTypeVal *type, const xmlChar **prefix,
+	             xmlXPathTypeVal *type, xmlChar **prefix,
 		     xmlChar *name) {
     int blanks;
 
@@ -11322,7 +11283,7 @@
 	SKIP_BLANKS;
     } else {
 	xmlChar *name = NULL;
-	const xmlChar *prefix = NULL;
+	xmlChar *prefix = NULL;
 	xmlXPathTestVal test = (xmlXPathTestVal) 0;
 	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
 	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
@@ -11432,9 +11393,11 @@
 	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
 	} else
 #endif
-	    PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
-			   test, type, (void *)prefix, (void *)name);
-
+        if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
+                           test, type, (void *)prefix, (void *)name) == -1) {
+            xmlFree(prefix);
+            xmlFree(name);
+        }
     }
 #ifdef DEBUG_STEP
     xmlGenericError(xmlGenericErrorContext, "Step : ");
@@ -11634,11 +11597,277 @@
 }
 #endif /* DEBUG_STEP */
 
-static int
+/**
+ * xmlXPathNodeSetFilter:
+ * @ctxt:  the XPath Parser context
+ * @set: the node set to filter
+ * @filterOpIndex: the index of the predicate/filter op
+ * @minPos: minimum position in the filtered set (1-based)
+ * @maxPos: maximum position in the filtered set (1-based)
+ * @hasNsNodes: true if the node set may contain namespace nodes
+ *
+ * Filter a node set, keeping only nodes for which the predicate expression
+ * matches. Afterwards, keep only nodes between minPos and maxPos in the
+ * filtered result.
+ */
+static void
+xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
+		      xmlNodeSetPtr set,
+		      int filterOpIndex,
+                      int minPos, int maxPos,
+		      int hasNsNodes)
+{
+    xmlXPathContextPtr xpctxt;
+    xmlNodePtr oldnode;
+    xmlDocPtr olddoc;
+    xmlXPathStepOpPtr filterOp;
+    int oldcs, oldpp;
+    int i, j, pos;
+
+    if ((set == NULL) || (set->nodeNr == 0))
+        return;
+
+    /*
+    * Check if the node set contains a sufficient number of nodes for
+    * the requested range.
+    */
+    if (set->nodeNr < minPos) {
+        xmlXPathNodeSetClear(set, hasNsNodes);
+        return;
+    }
+
+    xpctxt = ctxt->context;
+    oldnode = xpctxt->node;
+    olddoc = xpctxt->doc;
+    oldcs = xpctxt->contextSize;
+    oldpp = xpctxt->proximityPosition;
+    filterOp = &ctxt->comp->steps[filterOpIndex];
+
+    xpctxt->contextSize = set->nodeNr;
+
+    for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
+        xmlNodePtr node = set->nodeTab[i];
+        int res;
+
+        xpctxt->node = node;
+        xpctxt->proximityPosition = i + 1;
+
+        /*
+        * Also set the xpath document in case things like
+        * key() are evaluated in the predicate.
+        *
+        * TODO: Get real doc for namespace nodes.
+        */
+        if ((node->type != XML_NAMESPACE_DECL) &&
+            (node->doc != NULL))
+            xpctxt->doc = node->doc;
+
+        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
+
+        if (ctxt->error != XPATH_EXPRESSION_OK)
+            goto exit;
+        if (res < 0) {
+            /* Shouldn't happen */
+            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
+            goto exit;
+        }
+
+        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
+            if (i != j) {
+                set->nodeTab[j] = node;
+                set->nodeTab[i] = NULL;
+            }
+
+            j += 1;
+        } else {
+            /* Remove the entry from the initial node set. */
+            set->nodeTab[i] = NULL;
+            if (node->type == XML_NAMESPACE_DECL)
+                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
+        }
+
+        if (res != 0) {
+            if (pos == maxPos) {
+                /* Clear remaining nodes and exit loop. */
+                if (hasNsNodes) {
+                    for (i++; i < set->nodeNr; i++) {
+                        node = set->nodeTab[i];
+                        if ((node != NULL) &&
+                            (node->type == XML_NAMESPACE_DECL))
+                            xmlXPathNodeSetFreeNs((xmlNsPtr) node);
+                    }
+                }
+                break;
+            }
+
+            pos += 1;
+        }
+    }
+
+    set->nodeNr = j;
+
+    /* If too many elements were removed, shrink table to preserve memory. */
+    if ((set->nodeMax > XML_NODESET_DEFAULT) &&
+        (set->nodeNr < set->nodeMax / 2)) {
+        xmlNodePtr *tmp;
+        int nodeMax = set->nodeNr;
+
+        if (nodeMax < XML_NODESET_DEFAULT)
+            nodeMax = XML_NODESET_DEFAULT;
+        tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
+                nodeMax * sizeof(xmlNodePtr));
+        if (tmp == NULL) {
+            xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
+        } else {
+            set->nodeTab = tmp;
+            set->nodeMax = nodeMax;
+        }
+    }
+
+exit:
+    xpctxt->node = oldnode;
+    xpctxt->doc = olddoc;
+    xpctxt->contextSize = oldcs;
+    xpctxt->proximityPosition = oldpp;
+}
+
+#ifdef LIBXML_XPTR_ENABLED
+/**
+ * xmlXPathLocationSetFilter:
+ * @ctxt:  the XPath Parser context
+ * @locset: the location set to filter
+ * @filterOpIndex: the index of the predicate/filter op
+ * @minPos: minimum position in the filtered set (1-based)
+ * @maxPos: maximum position in the filtered set (1-based)
+ *
+ * Filter a location set, keeping only nodes for which the predicate
+ * expression matches. Afterwards, keep only nodes between minPos and maxPos
+ * in the filtered result.
+ */
+static void
+xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
+		          xmlLocationSetPtr locset,
+		          int filterOpIndex,
+                          int minPos, int maxPos)
+{
+    xmlXPathContextPtr xpctxt;
+    xmlNodePtr oldnode;
+    xmlDocPtr olddoc;
+    xmlXPathStepOpPtr filterOp;
+    int oldcs, oldpp;
+    int i, j, pos;
+
+    if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
+        return;
+
+    xpctxt = ctxt->context;
+    oldnode = xpctxt->node;
+    olddoc = xpctxt->doc;
+    oldcs = xpctxt->contextSize;
+    oldpp = xpctxt->proximityPosition;
+    filterOp = &ctxt->comp->steps[filterOpIndex];
+
+    xpctxt->contextSize = locset->locNr;
+
+    for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
+        xmlNodePtr contextNode = locset->locTab[i]->user;
+        int res;
+
+        xpctxt->node = contextNode;
+        xpctxt->proximityPosition = i + 1;
+
+        /*
+        * Also set the xpath document in case things like
+        * key() are evaluated in the predicate.
+        *
+        * TODO: Get real doc for namespace nodes.
+        */
+        if ((contextNode->type != XML_NAMESPACE_DECL) &&
+            (contextNode->doc != NULL))
+            xpctxt->doc = contextNode->doc;
+
+        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
+
+        if (ctxt->error != XPATH_EXPRESSION_OK)
+            goto exit;
+        if (res < 0) {
+            /* Shouldn't happen */
+            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
+            goto exit;
+        }
+
+        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
+            if (i != j) {
+                locset->locTab[j] = locset->locTab[i];
+                locset->locTab[i] = NULL;
+            }
+
+            j += 1;
+        } else {
+            /* Remove the entry from the initial location set. */
+            xmlXPathFreeObject(locset->locTab[i]);
+            locset->locTab[i] = NULL;
+        }
+
+        if (res != 0) {
+            if (pos == maxPos) {
+                /* Clear remaining nodes and exit loop. */
+                for (i++; i < locset->locNr; i++) {
+                    xmlXPathFreeObject(locset->locTab[i]);
+                }
+                break;
+            }
+
+            pos += 1;
+        }
+    }
+
+    locset->locNr = j;
+
+    /* If too many elements were removed, shrink table to preserve memory. */
+    if ((locset->locMax > XML_NODESET_DEFAULT) &&
+        (locset->locNr < locset->locMax / 2)) {
+        xmlXPathObjectPtr *tmp;
+        int locMax = locset->locNr;
+
+        if (locMax < XML_NODESET_DEFAULT)
+            locMax = XML_NODESET_DEFAULT;
+        tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
+                locMax * sizeof(xmlXPathObjectPtr));
+        if (tmp == NULL) {
+            xmlXPathPErrMemory(ctxt, "shrinking locset\n");
+        } else {
+            locset->locTab = tmp;
+            locset->locMax = locMax;
+        }
+    }
+
+exit:
+    xpctxt->node = oldnode;
+    xpctxt->doc = olddoc;
+    xpctxt->contextSize = oldcs;
+    xpctxt->proximityPosition = oldpp;
+}
+#endif /* LIBXML_XPTR_ENABLED */
+
+/**
+ * xmlXPathCompOpEvalPredicate:
+ * @ctxt:  the XPath Parser context
+ * @op: the predicate op
+ * @set: the node set to filter
+ * @minPos: minimum position in the filtered set (1-based)
+ * @maxPos: maximum position in the filtered set (1-based)
+ * @hasNsNodes: true if the node set may contain namespace nodes
+ *
+ * Filter a node set, keeping only nodes for which the sequence of predicate
+ * expressions matches. Afterwards, keep only nodes between minPos and maxPos
+ * in the filtered result.
+ */
+static void
 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
 			    xmlXPathStepOpPtr op,
 			    xmlNodeSetPtr set,
-			    int contextSize,
+                            int minPos, int maxPos,
 			    int hasNsNodes)
 {
     if (op->ch1 != -1) {
@@ -11647,353 +11876,21 @@
 	* Process inner predicates first.
 	*/
 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
-	    /*
-	    * TODO: raise an internal error.
-	    */
+            xmlGenericError(xmlGenericErrorContext,
+                "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
+            XP_ERROR(XPATH_INVALID_OPERAND);
 	}
-	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
-	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
-	CHECK_ERROR0;
-	if (contextSize <= 0)
-	    return(0);
+        if (ctxt->context->depth >= ctxt->context->maxDepth)
+            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
+        ctxt->context->depth += 1;
+	xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
+                                    1, set->nodeNr, hasNsNodes);
+        ctxt->context->depth -= 1;
+	CHECK_ERROR;
     }
-    if (op->ch2 != -1) {
-	xmlXPathContextPtr xpctxt = ctxt->context;
-	xmlNodePtr contextNode, oldContextNode;
-	xmlDocPtr oldContextDoc;
-        int oldcs, oldpp;
-	int i, res, contextPos = 0, newContextSize;
-	xmlXPathStepOpPtr exprOp;
-	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
 
-#ifdef LIBXML_XPTR_ENABLED
-	/*
-	* URGENT TODO: Check the following:
-	*  We don't expect location sets if evaluating prediates, right?
-	*  Only filters should expect location sets, right?
-	*/
-#endif
-	/*
-	* SPEC XPath 1.0:
-	*  "For each node in the node-set to be filtered, the
-	*  PredicateExpr is evaluated with that node as the
-	*  context node, with the number of nodes in the
-	*  node-set as the context size, and with the proximity
-	*  position of the node in the node-set with respect to
-	*  the axis as the context position;"
-	* @oldset is the node-set" to be filtered.
-	*
-	* SPEC XPath 1.0:
-	*  "only predicates change the context position and
-	*  context size (see [2.4 Predicates])."
-	* Example:
-	*   node-set  context pos
-	*    nA         1
-	*    nB         2
-	*    nC         3
-	*   After applying predicate [position() > 1] :
-	*   node-set  context pos
-	*    nB         1
-	*    nC         2
-	*/
-	oldContextNode = xpctxt->node;
-	oldContextDoc = xpctxt->doc;
-        oldcs = xpctxt->contextSize;
-        oldpp = xpctxt->proximityPosition;
-	/*
-	* Get the expression of this predicate.
-	*/
-	exprOp = &ctxt->comp->steps[op->ch2];
-	newContextSize = 0;
-	for (i = 0; i < set->nodeNr; i++) {
-	    if (set->nodeTab[i] == NULL)
-		continue;
-
-	    contextNode = set->nodeTab[i];
-	    xpctxt->node = contextNode;
-	    xpctxt->contextSize = contextSize;
-	    xpctxt->proximityPosition = ++contextPos;
-
-	    /*
-	    * Also set the xpath document in case things like
-	    * key() are evaluated in the predicate.
-	    */
-	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
-		(contextNode->doc != NULL))
-		xpctxt->doc = contextNode->doc;
-	    /*
-	    * Evaluate the predicate expression with 1 context node
-	    * at a time; this node is packaged into a node set; this
-	    * node set is handed over to the evaluation mechanism.
-	    */
-	    if (contextObj == NULL)
-		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
-	    else {
-		if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
-		    contextNode) < 0) {
-		    ctxt->error = XPATH_MEMORY_ERROR;
-		    goto evaluation_exit;
-		}
-	    }
-
-	    valuePush(ctxt, contextObj);
-
-	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
-
-	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
-		xmlXPathNodeSetClear(set, hasNsNodes);
-		newContextSize = 0;
-		goto evaluation_exit;
-	    }
-
-	    if (res != 0) {
-		newContextSize++;
-	    } else {
-		/*
-		* Remove the entry from the initial node set.
-		*/
-		set->nodeTab[i] = NULL;
-		if (contextNode->type == XML_NAMESPACE_DECL)
-		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
-	    }
-	    if (ctxt->value == contextObj) {
-		/*
-		* Don't free the temporary XPath object holding the
-		* context node, in order to avoid massive recreation
-		* inside this loop.
-		*/
-		valuePop(ctxt);
-		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
-	    } else {
-		/*
-		* TODO: The object was lost in the evaluation machinery.
-		*  Can this happen? Maybe in internal-error cases.
-		*/
-		contextObj = NULL;
-	    }
-	}
-
-	if (contextObj != NULL) {
-	    if (ctxt->value == contextObj)
-		valuePop(ctxt);
-	    xmlXPathReleaseObject(xpctxt, contextObj);
-	}
-evaluation_exit:
-	if (exprRes != NULL)
-	    xmlXPathReleaseObject(ctxt->context, exprRes);
-	/*
-	* Reset/invalidate the context.
-	*/
-	xpctxt->node = oldContextNode;
-	xpctxt->doc = oldContextDoc;
-	xpctxt->contextSize = oldcs;
-	xpctxt->proximityPosition = oldpp;
-	return(newContextSize);
-    }
-    return(contextSize);
-}
-
-static int
-xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
-				      xmlXPathStepOpPtr op,
-				      xmlNodeSetPtr set,
-				      int contextSize,
-				      int minPos,
-				      int maxPos,
-				      int hasNsNodes)
-{
-    if (op->ch1 != -1) {
-	xmlXPathCompExprPtr comp = ctxt->comp;
-	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
-	    /*
-	    * TODO: raise an internal error.
-	    */
-	}
-	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
-	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
-	CHECK_ERROR0;
-	if (contextSize <= 0)
-	    return(0);
-    }
-    /*
-    * Check if the node set contains a sufficient number of nodes for
-    * the requested range.
-    */
-    if (contextSize < minPos) {
-	xmlXPathNodeSetClear(set, hasNsNodes);
-	return(0);
-    }
-    if (op->ch2 == -1) {
-	/*
-	* TODO: Can this ever happen?
-	*/
-	return (contextSize);
-    } else {
-	xmlDocPtr oldContextDoc;
-        int oldcs, oldpp;
-	int i, pos = 0, newContextSize = 0, contextPos = 0, res;
-	xmlXPathStepOpPtr exprOp;
-	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
-	xmlNodePtr oldContextNode, contextNode = NULL;
-	xmlXPathContextPtr xpctxt = ctxt->context;
-        int frame;
-
-#ifdef LIBXML_XPTR_ENABLED
-	    /*
-	    * URGENT TODO: Check the following:
-	    *  We don't expect location sets if evaluating prediates, right?
-	    *  Only filters should expect location sets, right?
-	*/
-#endif /* LIBXML_XPTR_ENABLED */
-
-	/*
-	* Save old context.
-	*/
-	oldContextNode = xpctxt->node;
-	oldContextDoc = xpctxt->doc;
-        oldcs = xpctxt->contextSize;
-        oldpp = xpctxt->proximityPosition;
-	/*
-	* Get the expression of this predicate.
-	*/
-	exprOp = &ctxt->comp->steps[op->ch2];
-	for (i = 0; i < set->nodeNr; i++) {
-            xmlXPathObjectPtr tmp;
-
-	    if (set->nodeTab[i] == NULL)
-		continue;
-
-	    contextNode = set->nodeTab[i];
-	    xpctxt->node = contextNode;
-	    xpctxt->contextSize = contextSize;
-	    xpctxt->proximityPosition = ++contextPos;
-
-	    /*
-	    * Initialize the new set.
-	    * Also set the xpath document in case things like
-	    * key() evaluation are attempted on the predicate
-	    */
-	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
-		(contextNode->doc != NULL))
-		xpctxt->doc = contextNode->doc;
-	    /*
-	    * Evaluate the predicate expression with 1 context node
-	    * at a time; this node is packaged into a node set; this
-	    * node set is handed over to the evaluation mechanism.
-	    */
-	    if (contextObj == NULL)
-		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
-	    else {
-		if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
-		    contextNode) < 0) {
-		    ctxt->error = XPATH_MEMORY_ERROR;
-		    goto evaluation_exit;
-		}
-	    }
-
-	    valuePush(ctxt, contextObj);
-            frame = xmlXPathSetFrame(ctxt);
-	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
-            xmlXPathPopFrame(ctxt, frame);
-            tmp = valuePop(ctxt);
-
-	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
-                while (tmp != contextObj) {
-                    /*
-                     * Free up the result
-                     * then pop off contextObj, which will be freed later
-                     */
-                    xmlXPathReleaseObject(xpctxt, tmp);
-                    tmp = valuePop(ctxt);
-                }
-		goto evaluation_error;
-	    }
-            /* push the result back onto the stack */
-            valuePush(ctxt, tmp);
-
-	    if (res)
-		pos++;
-
-	    if (res && (pos >= minPos) && (pos <= maxPos)) {
-		/*
-		* Fits in the requested range.
-		*/
-		newContextSize++;
-		if (minPos == maxPos) {
-		    /*
-		    * Only 1 node was requested.
-		    */
-		    if (contextNode->type == XML_NAMESPACE_DECL) {
-			/*
-			* As always: take care of those nasty
-			* namespace nodes.
-			*/
-			set->nodeTab[i] = NULL;
-		    }
-		    xmlXPathNodeSetClear(set, hasNsNodes);
-		    set->nodeNr = 1;
-		    set->nodeTab[0] = contextNode;
-		    goto evaluation_exit;
-		}
-		if (pos == maxPos) {
-		    /*
-		    * We are done.
-		    */
-		    xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
-		    goto evaluation_exit;
-		}
-	    } else {
-		/*
-		* Remove the entry from the initial node set.
-		*/
-		set->nodeTab[i] = NULL;
-		if (contextNode->type == XML_NAMESPACE_DECL)
-		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
-	    }
-	    if (exprRes != NULL) {
-		xmlXPathReleaseObject(ctxt->context, exprRes);
-		exprRes = NULL;
-	    }
-	    if (ctxt->value == contextObj) {
-		/*
-		* Don't free the temporary XPath object holding the
-		* context node, in order to avoid massive recreation
-		* inside this loop.
-		*/
-		valuePop(ctxt);
-		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
-	    } else {
-		/*
-		* The object was lost in the evaluation machinery.
-		* Can this happen? Maybe in case of internal-errors.
-		*/
-		contextObj = NULL;
-	    }
-	}
-	goto evaluation_exit;
-
-evaluation_error:
-	xmlXPathNodeSetClear(set, hasNsNodes);
-	newContextSize = 0;
-
-evaluation_exit:
-	if (contextObj != NULL) {
-	    if (ctxt->value == contextObj)
-		valuePop(ctxt);
-	    xmlXPathReleaseObject(xpctxt, contextObj);
-	}
-	if (exprRes != NULL)
-	    xmlXPathReleaseObject(ctxt->context, exprRes);
-	/*
-	* Reset/invalidate the context.
-	*/
-	xpctxt->node = oldContextNode;
-	xpctxt->doc = oldContextDoc;
-	xpctxt->contextSize = oldcs;
-	xpctxt->proximityPosition = oldpp;
-	return(newContextSize);
-    }
-    return(contextSize);
+    if (op->ch2 != -1)
+        xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
 }
 
 static int
@@ -12013,7 +11910,7 @@
     * 1) For predicates (XPATH_OP_PREDICATE):
     *    - an inner predicate operator
     * 2) For filters (XPATH_OP_FILTER):
-    *    - an inner filter operater OR
+    *    - an inner filter operator OR
     *    - an expression selecting the node set.
     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
     */
@@ -12111,7 +12008,7 @@
     /* First predicate operator */
     xmlXPathStepOpPtr predOp;
     int maxPos; /* The requested position() (when a "[n]" predicate) */
-    int hasPredicateRange, hasAxisRange, pos, size, newSize;
+    int hasPredicateRange, hasAxisRange, pos;
     int breakOnFirstHit;
 
     xmlXPathTraversalFunction next = NULL;
@@ -12304,6 +12201,7 @@
 	if (seq == NULL) {
 	    seq = xmlXPathNodeSetCreate(NULL);
 	    if (seq == NULL) {
+                /* TODO: Propagate memory error. */
 		total = 0;
 		goto error;
 	    }
@@ -12315,6 +12213,9 @@
 	cur = NULL;
 	hasNsNodes = 0;
         do {
+            if (OP_LIMIT_EXCEEDED(ctxt, 1))
+                goto error;
+
             cur = next(ctxt, cur);
             if (cur == NULL)
                 break;
@@ -12522,7 +12423,8 @@
 	    outSeq = seq;
 	    seq = NULL;
 	} else
-	    outSeq = mergeAndClear(outSeq, seq, 0);
+            /* TODO: Check memory error. */
+	    outSeq = mergeAndClear(outSeq, seq);
 	/*
 	* Break if only a true/false result was requested.
 	*/
@@ -12539,7 +12441,8 @@
 	    outSeq = seq;
 	    seq = NULL;
 	} else
-	    outSeq = mergeAndClear(outSeq, seq, 0);
+            /* TODO: Check memory error. */
+	    outSeq = mergeAndClear(outSeq, seq);
 	break;
 
 #ifdef DEBUG_STEP
@@ -12583,51 +12486,20 @@
 	    * For the moment, I'll try to solve this with a recursive
 	    * function: xmlXPathCompOpEvalPredicate().
 	    */
-	    size = seq->nodeNr;
 	    if (hasPredicateRange != 0)
-		newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
-		    predOp, seq, size, maxPos, maxPos, hasNsNodes);
+		xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
+					    hasNsNodes);
 	    else
-		newSize = xmlXPathCompOpEvalPredicate(ctxt,
-		    predOp, seq, size, hasNsNodes);
+		xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
+					    hasNsNodes);
 
 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
 		total = 0;
 		goto error;
 	    }
-	    /*
-	    * Add the filtered set of nodes to the result node set.
-	    */
-	    if (newSize == 0) {
-		/*
-		* The predicates filtered all nodes out.
-		*/
-		xmlXPathNodeSetClear(seq, hasNsNodes);
-	    } else if (seq->nodeNr > 0) {
-		/*
-		* Add to result set.
-		*/
-		if (outSeq == NULL) {
-		    if (size != newSize) {
-			/*
-			* We need to merge and clear here, since
-			* the sequence will contained NULLed entries.
-			*/
-			outSeq = mergeAndClear(NULL, seq, 1);
-		    } else {
-			outSeq = seq;
-			seq = NULL;
-		    }
-		} else
-		    outSeq = mergeAndClear(outSeq, seq,
-			(size != newSize) ? 1: 0);
-		/*
-		* Break if only a true/false result was requested.
-		*/
-		if (toBool)
-		    break;
-	    }
-        } else if (seq->nodeNr > 0) {
+        }
+
+        if (seq->nodeNr > 0) {
 	    /*
 	    * Add to result set.
 	    */
@@ -12635,8 +12507,12 @@
 		outSeq = seq;
 		seq = NULL;
 	    } else {
-		outSeq = mergeAndClear(outSeq, seq, 0);
+                /* TODO: Check memory error. */
+		outSeq = mergeAndClear(outSeq, seq);
 	    }
+
+            if (toBool)
+                break;
 	}
     }
 
@@ -12655,14 +12531,14 @@
     xmlXPathReleaseObject(xpctxt, obj);
 
     /*
-    * Ensure we return at least an emtpy set.
+    * Ensure we return at least an empty set.
     */
     if (outSeq == NULL) {
 	if ((seq != NULL) && (seq->nodeNr == 0))
 	    outSeq = seq;
 	else
+            /* TODO: Check memory error. */
 	    outSeq = xmlXPathNodeSetCreate(NULL);
-        /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
     }
     if ((seq != NULL) && (seq != outSeq)) {
 	 xmlXPathFreeNodeSet(seq);
@@ -12718,10 +12594,15 @@
     xmlXPathObjectPtr arg1, arg2;
 
     CHECK_ERROR0;
+    if (OP_LIMIT_EXCEEDED(ctxt, 1))
+        return(0);
+    if (ctxt->context->depth >= ctxt->context->maxDepth)
+        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
+    ctxt->context->depth += 1;
     comp = ctxt->comp;
     switch (op->op) {
         case XPATH_OP_END:
-            return (0);
+            break;
         case XPATH_OP_UNION:
             total =
                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
@@ -12735,11 +12616,11 @@
                  * limit tree traversing to first node in the result
                  */
 		/*
-		* OPTIMIZE TODO: This implicitely sorts
+		* OPTIMIZE TODO: This implicitly sorts
 		*  the result, even if not needed. E.g. if the argument
 		*  of the count() function, no sorting is needed.
 		* OPTIMIZE TODO: How do we know if the node-list wasn't
-		*  aready sorted?
+		*  already sorted?
 		*/
 		if (ctxt->value->nodesetval->nodeNr > 1)
 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
@@ -12758,7 +12639,19 @@
 	        xmlXPathReleaseObject(ctxt->context, arg2);
                 XP_ERROR0(XPATH_INVALID_TYPE);
             }
+            if ((ctxt->context->opLimit != 0) &&
+                (((arg1->nodesetval != NULL) &&
+                  (xmlXPathCheckOpLimit(ctxt,
+                                        arg1->nodesetval->nodeNr) < 0)) ||
+                 ((arg2->nodesetval != NULL) &&
+                  (xmlXPathCheckOpLimit(ctxt,
+                                        arg2->nodesetval->nodeNr) < 0)))) {
+	        xmlXPathReleaseObject(ctxt->context, arg1);
+	        xmlXPathReleaseObject(ctxt->context, arg2);
+                break;
+            }
 
+            /* TODO: Check memory error. */
             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
                                                     arg2->nodesetval);
             valuePush(ctxt, arg1);
@@ -12766,10 +12659,11 @@
             /* optimizer */
 	    if (total > cur)
 		xmlXPathCompSwap(op);
-            return (total + cur);
+            total += cur;
+            break;
         case XPATH_OP_ROOT:
             xmlXPathRoot(ctxt);
-            return (0);
+            break;
         case XPATH_OP_NODE:
             if (op->ch1 != -1)
                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
@@ -12779,22 +12673,22 @@
 	    CHECK_ERROR0;
 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
 		ctxt->context->node));
-            return (total);
+            break;
         case XPATH_OP_COLLECT:{
                 if (op->ch1 == -1)
-                    return (total);
+                    break;
 
                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
 		CHECK_ERROR0;
 
                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
-                return (total);
+                break;
             }
         case XPATH_OP_VALUE:
             valuePush(ctxt,
                       xmlXPathCacheObjectCopy(ctxt->context,
 			(xmlXPathObjectPtr) op->value4));
-            return (0);
+            break;
         case XPATH_OP_SORT:
             if (op->ch1 != -1)
                 total +=
@@ -12806,15 +12700,19 @@
                 && (ctxt->value->nodesetval != NULL)
 		&& (ctxt->value->nodesetval->nodeNr > 1))
                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
-            return (total);
+            break;
 #ifdef XP_OPTIMIZED_FILTER_FIRST
 	case XPATH_OP_FILTER:
                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
-            return (total);
+            break;
 #endif
         default:
-            return (xmlXPathCompOpEval(ctxt, op));
+            total += xmlXPathCompOpEval(ctxt, op);
+            break;
     }
+
+    ctxt->context->depth -= 1;
+    return(total);
 }
 
 /**
@@ -12837,10 +12735,15 @@
     xmlXPathObjectPtr arg1, arg2;
 
     CHECK_ERROR0;
+    if (OP_LIMIT_EXCEEDED(ctxt, 1))
+        return(0);
+    if (ctxt->context->depth >= ctxt->context->maxDepth)
+        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
+    ctxt->context->depth += 1;
     comp = ctxt->comp;
     switch (op->op) {
         case XPATH_OP_END:
-            return (0);
+            break;
         case XPATH_OP_UNION:
             total =
                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
@@ -12876,7 +12779,19 @@
 	        xmlXPathReleaseObject(ctxt->context, arg2);
                 XP_ERROR0(XPATH_INVALID_TYPE);
             }
+            if ((ctxt->context->opLimit != 0) &&
+                (((arg1->nodesetval != NULL) &&
+                  (xmlXPathCheckOpLimit(ctxt,
+                                        arg1->nodesetval->nodeNr) < 0)) ||
+                 ((arg2->nodesetval != NULL) &&
+                  (xmlXPathCheckOpLimit(ctxt,
+                                        arg2->nodesetval->nodeNr) < 0)))) {
+	        xmlXPathReleaseObject(ctxt->context, arg1);
+	        xmlXPathReleaseObject(ctxt->context, arg2);
+                break;
+            }
 
+            /* TODO: Check memory error. */
             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
                                                     arg2->nodesetval);
             valuePush(ctxt, arg1);
@@ -12884,10 +12799,11 @@
             /* optimizer */
 	    if (total > cur)
 		xmlXPathCompSwap(op);
-            return (total + cur);
+            total += cur;
+            break;
         case XPATH_OP_ROOT:
             xmlXPathRoot(ctxt);
-            return (0);
+            break;
         case XPATH_OP_NODE:
             if (op->ch1 != -1)
                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
@@ -12897,22 +12813,22 @@
 	    CHECK_ERROR0;
 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
 		ctxt->context->node));
-            return (total);
+            break;
         case XPATH_OP_COLLECT:{
                 if (op->ch1 == -1)
-                    return (0);
+                    break;
 
                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
 		CHECK_ERROR0;
 
                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
-                return (total);
+                break;
             }
         case XPATH_OP_VALUE:
             valuePush(ctxt,
                       xmlXPathCacheObjectCopy(ctxt->context,
 			(xmlXPathObjectPtr) op->value4));
-            return (0);
+            break;
         case XPATH_OP_SORT:
             if (op->ch1 != -1)
                 total +=
@@ -12924,10 +12840,14 @@
                 && (ctxt->value->nodesetval != NULL)
 		&& (ctxt->value->nodesetval->nodeNr > 1))
                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
-            return (total);
+            break;
         default:
-            return (xmlXPathCompOpEval(ctxt, op));
+            total += xmlXPathCompOpEval(ctxt, op);
+            break;
     }
+
+    ctxt->context->depth -= 1;
+    return (total);
 }
 
 #ifdef XP_OPTIMIZED_FILTER_FIRST
@@ -12937,13 +12857,7 @@
 {
     int total = 0;
     xmlXPathCompExprPtr comp;
-    xmlXPathObjectPtr res;
-    xmlXPathObjectPtr obj;
-    xmlNodeSetPtr oldset;
-    xmlNodePtr oldnode;
-    xmlDocPtr oldDoc;
-    int oldcs, oldpp;
-    int i;
+    xmlNodeSetPtr set;
 
     CHECK_ERROR0;
     comp = ctxt->comp;
@@ -12998,205 +12912,27 @@
     * Hum are we filtering the result of an XPointer expression
     */
     if (ctxt->value->type == XPATH_LOCATIONSET) {
-	xmlXPathObjectPtr tmp = NULL;
-	xmlLocationSetPtr newlocset = NULL;
-	xmlLocationSetPtr oldlocset;
+        xmlLocationSetPtr locset = ctxt->value->user;
 
-	/*
-	* Extract the old locset, and then evaluate the result of the
-	* expression for all the element in the locset. use it to grow
-	* up a new locset.
-	*/
-	CHECK_TYPE0(XPATH_LOCATIONSET);
+        if (locset != NULL) {
+            xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
+            if (locset->locNr > 0)
+                *first = (xmlNodePtr) locset->locTab[0]->user;
+        }
 
-	if ((ctxt->value->user == NULL) ||
-            (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
-	    return (total);
-
-	obj = valuePop(ctxt);
-	oldlocset = obj->user;
-        oldnode = ctxt->context->node;
-        oldcs = ctxt->context->contextSize;
-        oldpp = ctxt->context->proximityPosition;
-
-	newlocset = xmlXPtrLocationSetCreate(NULL);
-
-	for (i = 0; i < oldlocset->locNr; i++) {
-	    /*
-	    * Run the evaluation with a node list made of a
-	    * single item in the nodelocset.
-	    */
-	    ctxt->context->node = oldlocset->locTab[i]->user;
-	    ctxt->context->contextSize = oldlocset->locNr;
-	    ctxt->context->proximityPosition = i + 1;
-	    if (tmp == NULL) {
-		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
-		    ctxt->context->node);
-	    } else {
-		if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
-		                             ctxt->context->node) < 0) {
-		    ctxt->error = XPATH_MEMORY_ERROR;
-		}
-	    }
-	    valuePush(ctxt, tmp);
-	    if (op->ch2 != -1)
-		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
-	    if (ctxt->error != XPATH_EXPRESSION_OK) {
-                xmlXPtrFreeLocationSet(newlocset);
-                goto xptr_error;
-	    }
-	    /*
-	    * The result of the evaluation need to be tested to
-	    * decided whether the filter succeeded or not
-	    */
-	    res = valuePop(ctxt);
-	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
-		xmlXPtrLocationSetAdd(newlocset,
-		    xmlXPathCacheObjectCopy(ctxt->context,
-			oldlocset->locTab[i]));
-	    }
-	    /*
-	    * Cleanup
-	    */
-	    if (res != NULL) {
-		xmlXPathReleaseObject(ctxt->context, res);
-	    }
-	    if (ctxt->value == tmp) {
-		valuePop(ctxt);
-		xmlXPathNodeSetClear(tmp->nodesetval, 1);
-		/*
-		* REVISIT TODO: Don't create a temporary nodeset
-		* for everly iteration.
-		*/
-		/* OLD: xmlXPathFreeObject(res); */
-	    } else
-		tmp = NULL;
-	    /*
-	    * Only put the first node in the result, then leave.
-	    */
-	    if (newlocset->locNr > 0) {
-		*first = (xmlNodePtr) oldlocset->locTab[i]->user;
-		break;
-	    }
-	}
-	if (tmp != NULL) {
-	    xmlXPathReleaseObject(ctxt->context, tmp);
-	}
-	/*
-	* The result is used as the new evaluation locset.
-	*/
-	valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
-xptr_error:
-	xmlXPathReleaseObject(ctxt->context, obj);
-	ctxt->context->node = oldnode;
-	ctxt->context->contextSize = oldcs;
-	ctxt->context->proximityPosition = oldpp;
 	return (total);
     }
 #endif /* LIBXML_XPTR_ENABLED */
 
-    /*
-    * Extract the old set, and then evaluate the result of the
-    * expression for all the element in the set. use it to grow
-    * up a new set.
-    */
     CHECK_TYPE0(XPATH_NODESET);
-
-    if ((ctxt->value->nodesetval != NULL) &&
-        (ctxt->value->nodesetval->nodeNr != 0)) {
-	xmlNodeSetPtr newset;
-	xmlXPathObjectPtr tmp = NULL;
-
-        obj = valuePop(ctxt);
-        oldset = obj->nodesetval;
-        oldnode = ctxt->context->node;
-        oldDoc = ctxt->context->doc;
-        oldcs = ctxt->context->contextSize;
-        oldpp = ctxt->context->proximityPosition;
-
-	/*
-	* Initialize the new set.
-	* Also set the xpath document in case things like
-	* key() evaluation are attempted on the predicate
-	*/
-	newset = xmlXPathNodeSetCreate(NULL);
-        /* XXX what if xmlXPathNodeSetCreate returned NULL? */
-
-	for (i = 0; i < oldset->nodeNr; i++) {
-	    /*
-	    * Run the evaluation with a node list made of
-	    * a single item in the nodeset.
-	    */
-	    ctxt->context->node = oldset->nodeTab[i];
-	    if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
-		(oldset->nodeTab[i]->doc != NULL))
-		ctxt->context->doc = oldset->nodeTab[i]->doc;
-	    if (tmp == NULL) {
-		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
-		    ctxt->context->node);
-	    } else {
-		if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
-		                             ctxt->context->node) < 0) {
-		    ctxt->error = XPATH_MEMORY_ERROR;
-		}
-	    }
-	    valuePush(ctxt, tmp);
-	    ctxt->context->contextSize = oldset->nodeNr;
-	    ctxt->context->proximityPosition = i + 1;
-	    if (op->ch2 != -1)
-		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
-	    if (ctxt->error != XPATH_EXPRESSION_OK) {
-		xmlXPathFreeNodeSet(newset);
-                goto error;
-	    }
-	    /*
-	    * The result of the evaluation needs to be tested to
-	    * decide whether the filter succeeded or not
-	    */
-	    res = valuePop(ctxt);
-	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
-		if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
-		    ctxt->error = XPATH_MEMORY_ERROR;
-	    }
-	    /*
-	    * Cleanup
-	    */
-	    if (res != NULL) {
-		xmlXPathReleaseObject(ctxt->context, res);
-	    }
-	    if (ctxt->value == tmp) {
-		valuePop(ctxt);
-		/*
-		* Don't free the temporary nodeset
-		* in order to avoid massive recreation inside this
-		* loop.
-		*/
-		xmlXPathNodeSetClear(tmp->nodesetval, 1);
-	    } else
-		tmp = NULL;
-	    /*
-	    * Only put the first node in the result, then leave.
-	    */
-	    if (newset->nodeNr > 0) {
-		*first = *(newset->nodeTab);
-		break;
-	    }
-	}
-	if (tmp != NULL) {
-	    xmlXPathReleaseObject(ctxt->context, tmp);
-	}
-	/*
-	* The result is used as the new evaluation set.
-	*/
-	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
-error:
-	xmlXPathReleaseObject(ctxt->context, obj);
-	ctxt->context->node = oldnode;
-	ctxt->context->doc = oldDoc;
-	ctxt->context->contextSize = oldcs;
-	ctxt->context->proximityPosition = oldpp;
+    set = ctxt->value->nodesetval;
+    if (set != NULL) {
+        xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
+        if (set->nodeNr > 0)
+            *first = set->nodeTab[0];
     }
-    return(total);
+
+    return (total);
 }
 #endif /* XP_OPTIMIZED_FILTER_FIRST */
 
@@ -13217,44 +12953,49 @@
     xmlXPathObjectPtr arg1, arg2;
 
     CHECK_ERROR0;
+    if (OP_LIMIT_EXCEEDED(ctxt, 1))
+        return(0);
+    if (ctxt->context->depth >= ctxt->context->maxDepth)
+        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
+    ctxt->context->depth += 1;
     comp = ctxt->comp;
     switch (op->op) {
         case XPATH_OP_END:
-            return (0);
+            break;
         case XPATH_OP_AND:
             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
 	    CHECK_ERROR0;
             xmlXPathBooleanFunction(ctxt, 1);
             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
-                return (total);
+                break;
             arg2 = valuePop(ctxt);
             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
 	    if (ctxt->error) {
 		xmlXPathFreeObject(arg2);
-		return(0);
+		break;
 	    }
             xmlXPathBooleanFunction(ctxt, 1);
             if (ctxt->value != NULL)
                 ctxt->value->boolval &= arg2->boolval;
 	    xmlXPathReleaseObject(ctxt->context, arg2);
-            return (total);
+            break;
         case XPATH_OP_OR:
             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
 	    CHECK_ERROR0;
             xmlXPathBooleanFunction(ctxt, 1);
             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
-                return (total);
+                break;
             arg2 = valuePop(ctxt);
             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
 	    if (ctxt->error) {
 		xmlXPathFreeObject(arg2);
-		return(0);
+		break;
 	    }
             xmlXPathBooleanFunction(ctxt, 1);
             if (ctxt->value != NULL)
                 ctxt->value->boolval |= arg2->boolval;
 	    xmlXPathReleaseObject(ctxt->context, arg2);
-            return (total);
+            break;
         case XPATH_OP_EQUAL:
             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
 	    CHECK_ERROR0;
@@ -13265,7 +13006,7 @@
 	    else
 		equal = xmlXPathNotEqualValues(ctxt);
 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
-            return (total);
+            break;
         case XPATH_OP_CMP:
             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
 	    CHECK_ERROR0;
@@ -13273,7 +13014,7 @@
 	    CHECK_ERROR0;
             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
-            return (total);
+            break;
         case XPATH_OP_PLUS:
             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
 	    CHECK_ERROR0;
@@ -13291,7 +13032,7 @@
                 CAST_TO_NUMBER;
                 CHECK_TYPE0(XPATH_NUMBER);
             }
-            return (total);
+            break;
         case XPATH_OP_MULT:
             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
 	    CHECK_ERROR0;
@@ -13303,7 +13044,7 @@
                 xmlXPathDivValues(ctxt);
             else if (op->value == 2)
                 xmlXPathModValues(ctxt);
-            return (total);
+            break;
         case XPATH_OP_UNION:
             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
 	    CHECK_ERROR0;
@@ -13318,21 +13059,33 @@
 	        xmlXPathReleaseObject(ctxt->context, arg2);
                 XP_ERROR0(XPATH_INVALID_TYPE);
             }
+            if ((ctxt->context->opLimit != 0) &&
+                (((arg1->nodesetval != NULL) &&
+                  (xmlXPathCheckOpLimit(ctxt,
+                                        arg1->nodesetval->nodeNr) < 0)) ||
+                 ((arg2->nodesetval != NULL) &&
+                  (xmlXPathCheckOpLimit(ctxt,
+                                        arg2->nodesetval->nodeNr) < 0)))) {
+	        xmlXPathReleaseObject(ctxt->context, arg1);
+	        xmlXPathReleaseObject(ctxt->context, arg2);
+                break;
+            }
 
 	    if ((arg1->nodesetval == NULL) ||
 		((arg2->nodesetval != NULL) &&
 		 (arg2->nodesetval->nodeNr != 0)))
 	    {
+                /* TODO: Check memory error. */
 		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
 							arg2->nodesetval);
 	    }
 
             valuePush(ctxt, arg1);
 	    xmlXPathReleaseObject(ctxt->context, arg2);
-            return (total);
+            break;
         case XPATH_OP_ROOT:
             xmlXPathRoot(ctxt);
-            return (total);
+            break;
         case XPATH_OP_NODE:
             if (op->ch1 != -1)
                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
@@ -13342,22 +13095,22 @@
 	    CHECK_ERROR0;
 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
 		ctxt->context->node));
-            return (total);
+            break;
         case XPATH_OP_COLLECT:{
                 if (op->ch1 == -1)
-                    return (total);
+                    break;
 
                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
 		CHECK_ERROR0;
 
                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
-                return (total);
+                break;
             }
         case XPATH_OP_VALUE:
             valuePush(ctxt,
                       xmlXPathCacheObjectCopy(ctxt->context,
 			(xmlXPathObjectPtr) op->value4));
-            return (total);
+            break;
         case XPATH_OP_VARIABLE:{
 		xmlXPathObjectPtr val;
 
@@ -13378,7 +13131,7 @@
             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
                                     (char *) op->value4, (char *)op->value5);
                         ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
-                        return (total);
+                        break;
                     }
 		    val = xmlXPathVariableLookupNS(ctxt->context,
                                                        op->value4, URI);
@@ -13386,7 +13139,7 @@
 			XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
                     valuePush(ctxt, val);
                 }
-                return (total);
+                break;
             }
         case XPATH_OP_FUNCTION:{
                 xmlXPathFunction func;
@@ -13400,7 +13153,7 @@
                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
                     if (ctxt->error != XPATH_EXPRESSION_OK) {
                         xmlXPathPopFrame(ctxt, frame);
-                        return (total);
+                        break;
                     }
                 }
 		if (ctxt->valueNr < ctxt->valueFrame + op->value) {
@@ -13408,7 +13161,7 @@
 			    "xmlXPathCompOpEval: parameter error\n");
 		    ctxt->error = XPATH_INVALID_OPERAND;
                     xmlXPathPopFrame(ctxt, frame);
-		    return (total);
+		    break;
 		}
 		for (i = 0; i < op->value; i++) {
 		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
@@ -13416,7 +13169,7 @@
 				"xmlXPathCompOpEval: parameter error\n");
 			ctxt->error = XPATH_INVALID_OPERAND;
                         xmlXPathPopFrame(ctxt, frame);
-			return (total);
+			break;
 		    }
                 }
                 if (op->cache != NULL)
@@ -13436,7 +13189,7 @@
                                     (char *)op->value4, (char *)op->value5);
                             xmlXPathPopFrame(ctxt, frame);
                             ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
-                            return (total);
+                            break;
                         }
                         func = xmlXPathFunctionLookupNS(ctxt->context,
                                                         op->value4, URI);
@@ -13457,8 +13210,11 @@
                 func(ctxt, op->value);
                 ctxt->context->function = oldFunc;
                 ctxt->context->functionURI = oldFuncURI;
+                if ((ctxt->error == XPATH_EXPRESSION_OK) &&
+                    (ctxt->valueNr != ctxt->valueFrame + 1))
+                    XP_ERROR0(XPATH_STACK_ERROR);
                 xmlXPathPopFrame(ctxt, frame);
-                return (total);
+                break;
             }
         case XPATH_OP_ARG:
             if (op->ch1 != -1) {
@@ -13469,17 +13225,10 @@
                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
 	        CHECK_ERROR0;
 	    }
-            return (total);
+            break;
         case XPATH_OP_PREDICATE:
         case XPATH_OP_FILTER:{
-                xmlXPathObjectPtr res;
-                xmlXPathObjectPtr obj, tmp;
-                xmlNodeSetPtr newset = NULL;
-                xmlNodeSetPtr oldset;
-                xmlNodePtr oldnode;
-		xmlDocPtr oldDoc;
-                int oldcs, oldpp;
-                int i;
+                xmlNodeSetPtr set;
 
                 /*
                  * Optimization for ()[1] selection i.e. the first elem
@@ -13491,7 +13240,7 @@
 		    *  will result in an ordered list if we have an
 		    *  XPATH_OP_FILTER?
 		    *  What about an additional field or flag on
-		    *  xmlXPathObject like @sorted ? This way we wouln'd need
+		    *  xmlXPathObject like @sorted ? This way we wouldn't need
 		    *  to assume anything, so it would be more robust and
 		    *  easier to optimize.
 		    */
@@ -13523,7 +13272,7 @@
                             (ctxt->value->nodesetval->nodeNr > 1))
                             xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
                                                         1, 1);
-                        return (total);
+                        break;
                     }
                 }
                 /*
@@ -13558,7 +13307,7 @@
                             (ctxt->value->nodesetval->nodeTab != NULL) &&
                             (ctxt->value->nodesetval->nodeNr > 1))
                             xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
-                        return (total);
+                        break;
                     }
                 }
 		/*
@@ -13577,224 +13326,28 @@
                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
 		CHECK_ERROR0;
                 if (op->ch2 == -1)
-                    return (total);
+                    break;
                 if (ctxt->value == NULL)
-                    return (total);
+                    break;
 
 #ifdef LIBXML_XPTR_ENABLED
                 /*
                  * Hum are we filtering the result of an XPointer expression
                  */
                 if (ctxt->value->type == XPATH_LOCATIONSET) {
-                    xmlLocationSetPtr newlocset = NULL;
-                    xmlLocationSetPtr oldlocset;
-
-                    /*
-                     * Extract the old locset, and then evaluate the result of the
-                     * expression for all the element in the locset. use it to grow
-                     * up a new locset.
-                     */
-                    CHECK_TYPE0(XPATH_LOCATIONSET);
-
-                    if ((ctxt->value->user == NULL) ||
-                        (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
-                        return (total);
-
-                    obj = valuePop(ctxt);
-                    oldlocset = obj->user;
-                    oldnode = ctxt->context->node;
-                    oldcs = ctxt->context->contextSize;
-                    oldpp = ctxt->context->proximityPosition;
-
-                    newlocset = xmlXPtrLocationSetCreate(NULL);
-
-                    for (i = 0; i < oldlocset->locNr; i++) {
-                        /*
-                         * Run the evaluation with a node list made of a
-                         * single item in the nodelocset.
-                         */
-                        ctxt->context->node = oldlocset->locTab[i]->user;
-                        ctxt->context->contextSize = oldlocset->locNr;
-                        ctxt->context->proximityPosition = i + 1;
-			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
-			    ctxt->context->node);
-                        valuePush(ctxt, tmp);
-
-                        if (op->ch2 != -1)
-                            total +=
-                                xmlXPathCompOpEval(ctxt,
-                                                   &comp->steps[op->ch2]);
-			if (ctxt->error != XPATH_EXPRESSION_OK) {
-                            xmlXPtrFreeLocationSet(newlocset);
-                            goto filter_xptr_error;
-			}
-
-                        /*
-                         * The result of the evaluation need to be tested to
-                         * decided whether the filter succeeded or not
-                         */
-                        res = valuePop(ctxt);
-                        if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
-                            xmlXPtrLocationSetAdd(newlocset,
-                                                  xmlXPathObjectCopy
-                                                  (oldlocset->locTab[i]));
-                        }
-
-                        /*
-                         * Cleanup
-                         */
-                        if (res != NULL) {
-			    xmlXPathReleaseObject(ctxt->context, res);
-			}
-                        if (ctxt->value == tmp) {
-                            res = valuePop(ctxt);
-			    xmlXPathReleaseObject(ctxt->context, res);
-                        }
-                    }
-
-                    /*
-                     * The result is used as the new evaluation locset.
-                     */
-                    valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
-filter_xptr_error:
-		    xmlXPathReleaseObject(ctxt->context, obj);
-                    ctxt->context->node = oldnode;
-                    ctxt->context->contextSize = oldcs;
-                    ctxt->context->proximityPosition = oldpp;
-                    return (total);
+                    xmlLocationSetPtr locset = ctxt->value->user;
+                    xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
+                                              1, locset->locNr);
+                    break;
                 }
 #endif /* LIBXML_XPTR_ENABLED */
 
-                /*
-                 * Extract the old set, and then evaluate the result of the
-                 * expression for all the element in the set. use it to grow
-                 * up a new set.
-                 */
                 CHECK_TYPE0(XPATH_NODESET);
-
-                if ((ctxt->value->nodesetval != NULL) &&
-                    (ctxt->value->nodesetval->nodeNr != 0)) {
-                    obj = valuePop(ctxt);
-                    oldset = obj->nodesetval;
-                    oldnode = ctxt->context->node;
-                    oldDoc = ctxt->context->doc;
-                    oldcs = ctxt->context->contextSize;
-                    oldpp = ctxt->context->proximityPosition;
-		    tmp = NULL;
-                    /*
-                     * Initialize the new set.
-		     * Also set the xpath document in case things like
-		     * key() evaluation are attempted on the predicate
-                     */
-                    newset = xmlXPathNodeSetCreate(NULL);
-		    /*
-		    * SPEC XPath 1.0:
-		    *  "For each node in the node-set to be filtered, the
-		    *  PredicateExpr is evaluated with that node as the
-		    *  context node, with the number of nodes in the
-		    *  node-set as the context size, and with the proximity
-		    *  position of the node in the node-set with respect to
-		    *  the axis as the context position;"
-		    * @oldset is the node-set" to be filtered.
-		    *
-		    * SPEC XPath 1.0:
-		    *  "only predicates change the context position and
-		    *  context size (see [2.4 Predicates])."
-		    * Example:
-		    *   node-set  context pos
-		    *    nA         1
-		    *    nB         2
-		    *    nC         3
-		    *   After applying predicate [position() > 1] :
-		    *   node-set  context pos
-		    *    nB         1
-		    *    nC         2
-		    *
-		    * removed the first node in the node-set, then
-		    * the context position of the
-		    */
-                    for (i = 0; i < oldset->nodeNr; i++) {
-                        /*
-                         * Run the evaluation with a node list made of
-                         * a single item in the nodeset.
-                         */
-                        ctxt->context->node = oldset->nodeTab[i];
-			if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
-			    (oldset->nodeTab[i]->doc != NULL))
-		            ctxt->context->doc = oldset->nodeTab[i]->doc;
-			if (tmp == NULL) {
-			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
-				ctxt->context->node);
-			} else {
-			    if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
-				               ctxt->context->node) < 0) {
-				ctxt->error = XPATH_MEMORY_ERROR;
-			    }
-			}
-                        valuePush(ctxt, tmp);
-                        ctxt->context->contextSize = oldset->nodeNr;
-                        ctxt->context->proximityPosition = i + 1;
-			/*
-			* Evaluate the predicate against the context node.
-			* Can/should we optimize position() predicates
-			* here (e.g. "[1]")?
-			*/
-                        if (op->ch2 != -1)
-                            total +=
-                                xmlXPathCompOpEval(ctxt,
-                                                   &comp->steps[op->ch2]);
-			if (ctxt->error != XPATH_EXPRESSION_OK) {
-			    xmlXPathFreeNodeSet(newset);
-                            goto filter_error;
-			}
-
-                        /*
-                         * The result of the evaluation needs to be tested to
-                         * decide whether the filter succeeded or not
-                         */
-			/*
-			* OPTIMIZE TODO: Can we use
-			* xmlXPathNodeSetAdd*Unique()* instead?
-			*/
-                        res = valuePop(ctxt);
-                        if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
-                            if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i])
-			        < 0)
-				ctxt->error = XPATH_MEMORY_ERROR;
-                        }
-
-                        /*
-                         * Cleanup
-                         */
-                        if (res != NULL) {
-			    xmlXPathReleaseObject(ctxt->context, res);
-			}
-                        if (ctxt->value == tmp) {
-                            valuePop(ctxt);
-			    xmlXPathNodeSetClear(tmp->nodesetval, 1);
-			    /*
-			    * Don't free the temporary nodeset
-			    * in order to avoid massive recreation inside this
-			    * loop.
-			    */
-                        } else
-			    tmp = NULL;
-                    }
-		    if (tmp != NULL)
-			xmlXPathReleaseObject(ctxt->context, tmp);
-                    /*
-                     * The result is used as the new evaluation set.
-                     */
-		    valuePush(ctxt,
-			xmlXPathCacheWrapNodeSet(ctxt->context, newset));
-filter_error:
-		    xmlXPathReleaseObject(ctxt->context, obj);
-		    ctxt->context->node = oldnode;
-		    ctxt->context->doc = oldDoc;
-                    ctxt->context->contextSize = oldcs;
-                    ctxt->context->proximityPosition = oldpp;
-                }
-                return (total);
+                set = ctxt->value->nodesetval;
+                if (set != NULL)
+                    xmlXPathNodeSetFilter(ctxt, set, op->ch2,
+                                          1, set->nodeNr, 1);
+                break;
             }
         case XPATH_OP_SORT:
             if (op->ch1 != -1)
@@ -13807,7 +13360,7 @@
 	    {
                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
 	    }
-            return (total);
+            break;
 #ifdef LIBXML_XPTR_ENABLED
         case XPATH_OP_RANGETO:{
                 xmlXPathObjectPtr range;
@@ -13830,7 +13383,7 @@
                     XP_ERROR0(XPATH_INVALID_OPERAND);
                 }
                 if (op->ch2 == -1)
-                    return (total);
+                    break;
 
                 if (ctxt->value->type == XPATH_LOCATIONSET) {
                     /*
@@ -13842,7 +13395,7 @@
 
                     if ((ctxt->value->user == NULL) ||
                         (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
-                        return (total);
+                        break;
 
                     obj = valuePop(ctxt);
                     oldlocset = obj->user;
@@ -13964,13 +13517,17 @@
                 ctxt->context->node = oldnode;
                 ctxt->context->contextSize = oldcs;
                 ctxt->context->proximityPosition = oldpp;
-                return (total);
+                break;
             }
 #endif /* LIBXML_XPTR_ENABLED */
+        default:
+            xmlGenericError(xmlGenericErrorContext,
+                            "XPath: unknown precompiled operation %d\n", op->op);
+            ctxt->error = XPATH_INVALID_OPERAND;
+            break;
     }
-    xmlGenericError(xmlGenericErrorContext,
-                    "XPath: unknown precompiled operation %d\n", op->op);
-    ctxt->error = XPATH_INVALID_OPERAND;
+
+    ctxt->context->depth -= 1;
     return (total);
 }
 
@@ -13990,6 +13547,8 @@
     xmlXPathObjectPtr resObj = NULL;
 
 start:
+    if (OP_LIMIT_EXCEEDED(ctxt, 1))
+        return(0);
     /* comp = ctxt->comp; */
     switch (op->op) {
         case XPATH_OP_END:
@@ -14116,12 +13675,14 @@
 	    /* Select "/" */
 	    if (toBool)
 		return(1);
+            /* TODO: Check memory error. */
 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
 		                     (xmlNodePtr) ctxt->doc);
 	} else {
 	    /* Select "self::node()" */
 	    if (toBool)
 		return(1);
+            /* TODO: Check memory error. */
 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
 	}
     }
@@ -14182,6 +13743,7 @@
 	} else if (ret == 1) {
 	    if (toBool)
 		goto return_1;
+            /* TODO: Check memory error. */
 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
 	}
     }
@@ -14189,6 +13751,16 @@
     goto scan_children;
 next_node:
     do {
+        if (ctxt->opLimit != 0) {
+            if (ctxt->opCount >= ctxt->opLimit) {
+                xmlGenericError(xmlGenericErrorContext,
+                        "XPath operation limit exceeded\n");
+                xmlFreeStreamCtxt(patstream);
+                return(-1);
+            }
+            ctxt->opCount++;
+        }
+
         nb_nodes++;
 
 	switch (cur->type) {
@@ -14259,7 +13831,8 @@
 	do {
 	    cur = cur->parent;
 	    depth--;
-	    if ((cur == NULL) || (cur == limit))
+	    if ((cur == NULL) || (cur == limit) ||
+                (cur->type == XML_DOCUMENT_NODE))
 	        goto done;
 	    if (cur->type == XML_ELEMENT_NODE) {
 		ret = xmlStreamPop(patstream);
@@ -14312,6 +13885,8 @@
     if ((ctxt == NULL) || (ctxt->comp == NULL))
 	return(-1);
 
+    ctxt->context->depth = 0;
+
     if (ctxt->valueTab == NULL) {
 	/* Allocate the value stack */
 	ctxt->valueTab = (xmlXPathObjectPtr *)
@@ -14498,7 +14073,7 @@
 
 	/*
 	 * We don't try to handle expressions using the verbose axis
-	 * specifiers ("::"), just the simplied form at this point.
+	 * specifiers ("::"), just the simplified form at this point.
 	 * Additionally, if there is no list of namespaces available and
 	 *  there's a ":" in the expression, indicating a prefixed QName,
 	 *  then we won't try to compile either. xmlPatterncompile() needs
@@ -14528,8 +14103,7 @@
 	    }
 	}
 
-	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
-			&namespaces[0]);
+	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
 	if (namespaces != NULL) {
 	    xmlFree((xmlChar **)namespaces);
 	}
@@ -14552,8 +14126,12 @@
 #endif /* XPATH_STREAMING */
 
 static void
-xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
+xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
+                           xmlXPathStepOpPtr op)
 {
+    xmlXPathCompExprPtr comp = pctxt->comp;
+    xmlXPathContextPtr ctxt;
+
     /*
     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
     * internal representation.
@@ -14609,10 +14187,18 @@
         return;
 
     /* Recurse */
+    ctxt = pctxt->context;
+    if (ctxt != NULL) {
+        if (ctxt->depth >= ctxt->maxDepth)
+            return;
+        ctxt->depth += 1;
+    }
     if (op->ch1 != -1)
-        xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
+        xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
     if (op->ch2 != -1)
-	xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
+	xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
+    if (ctxt != NULL)
+        ctxt->depth -= 1;
 }
 
 /**
@@ -14641,6 +14227,8 @@
     pctxt = xmlXPathNewParserContext(str, ctxt);
     if (pctxt == NULL)
         return NULL;
+    if (ctxt != NULL)
+        ctxt->depth = 0;
     xmlXPathCompileExpr(pctxt, 1);
 
     if( pctxt->error != XPATH_EXPRESSION_OK )
@@ -14660,6 +14248,11 @@
 	comp = NULL;
     } else {
 	comp = pctxt->comp;
+	if ((comp->nbStep > 1) && (comp->last >= 0)) {
+            if (ctxt != NULL)
+                ctxt->depth = 0;
+	    xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
+	}
 	pctxt->comp = NULL;
     }
     xmlXPathFreeParserContext(pctxt);
@@ -14670,9 +14263,6 @@
 	comp->string = xmlStrdup(str);
 	comp->nb = 0;
 #endif
-	if ((comp->nbStep > 1) && (comp->last >= 0)) {
-	    xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
-	}
     }
     return(comp);
 }
@@ -14829,6 +14419,8 @@
     } else
 #endif
     {
+        if (ctxt->context != NULL)
+            ctxt->context->depth = 0;
 	xmlXPathCompileExpr(ctxt, 1);
         CHECK_ERROR;
 
@@ -14836,9 +14428,12 @@
         if (*ctxt->cur != 0)
             XP_ERROR(XPATH_EXPR_ERROR);
 
-	if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0))
-	    xmlXPathOptimizeExpression(ctxt->comp,
+	if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
+            if (ctxt->context != NULL)
+                ctxt->context->depth = 0;
+	    xmlXPathOptimizeExpression(ctxt,
 		&ctxt->comp->steps[ctxt->comp->last]);
+        }
     }
 
     xmlXPathRunEval(ctxt, 0);