Commit message: Fix some case of pattern parsing errors

We could accidentally hit an off by one string array access
due to improper loop exit when parsing patterns
CVE: CVE-2011-3970
CWE: CWE-125
Vulnerability description: libxslt, as used in Google Chrome before 17.0.963.46, allows remote attackers to cause a denial of service (out-of-bounds read) via unspecified vectors.

Project: libxslt
File: pattern.c

xsltFreeTemplateHashes(xsltStylesheetPtr style) {
    if (style->templatesHash != NULL)
	xmlHashFree((xmlHashTablePtr) style->templatesHash,
		    (xmlHashDeallocator) xsltFreeCompMatchList);
    if (style->rootMatch != NULL)
        xsltFreeCompMatchList(style->rootMatch);
    if (style->keyMatch != NULL)
        xsltFreeCompMatchList(style->keyMatch);
    if (style->elemMatch != NULL)
        xsltFreeCompMatchList(style->elemMatch);
    if (style->attrMatch != NULL)
        xsltFreeCompMatchList(style->attrMatch);
    if (style->parentMatch != NULL)
        xsltFreeCompMatchList(style->parentMatch);
    if (style->textMatch != NULL)
        xsltFreeCompMatchList(style->textMatch);
    if (style->piMatch != NULL)
        xsltFreeCompMatchList(style->piMatch);
    if (style->commentMatch != NULL)
        xsltFreeCompMatchList(style->commentMatch);
}

Project: libxslt
File: pattern.c

xsltTestCompMatchDirect(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp,
	                xmlNodePtr node, xmlNsPtr *nsList, int nsNr) {
    xsltStepOpPtr sel = NULL;
    xmlDocPtr prevdoc;
    xmlDocPtr doc;
    xmlXPathObjectPtr list;
    int ix, j;
    int nocache = 0;
    int isRVT;

    doc = node->doc;
    if (XSLT_IS_RES_TREE_FRAG(doc))
	isRVT = 1;
    else
	isRVT = 0;
    sel = &comp->steps[0]; /* store extra in first step arbitrarily */

    prevdoc = (xmlDocPtr)
	XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr);
    ix = XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival);
    list = (xmlXPathObjectPtr)
	XSLT_RUNTIME_EXTRA_LST(ctxt, sel->lenExtra);
    
    if ((list == NULL) || (prevdoc != doc)) {
	xmlXPathObjectPtr newlist;
	xmlNodePtr parent = node->parent;
	xmlDocPtr olddoc;
	xmlNodePtr oldnode;
	int oldNsNr, oldContextSize, oldProximityPosition;
	xmlNsPtr *oldNamespaces;

	oldnode = ctxt->xpathCtxt->node;
	olddoc = ctxt->xpathCtxt->doc;
	oldNsNr = ctxt->xpathCtxt->nsNr;
	oldNamespaces = ctxt->xpathCtxt->namespaces;
	oldContextSize = ctxt->xpathCtxt->contextSize;
	oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
	ctxt->xpathCtxt->node = node;
	ctxt->xpathCtxt->doc = doc;
	ctxt->xpathCtxt->namespaces = nsList;
	ctxt->xpathCtxt->nsNr = nsNr;
	newlist = xmlXPathEval(comp->pattern, ctxt->xpathCtxt);
	ctxt->xpathCtxt->node = oldnode;
	ctxt->xpathCtxt->doc = olddoc;
	ctxt->xpathCtxt->namespaces = oldNamespaces;
	ctxt->xpathCtxt->nsNr = oldNsNr;
	ctxt->xpathCtxt->contextSize = oldContextSize;
	ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
	if (newlist == NULL)
	    return(-1);
	if (newlist->type != XPATH_NODESET) {
	    xmlXPathFreeObject(newlist);
	    return(-1);
	}
	ix = 0;

	if ((parent == NULL) || (node->doc == NULL) || isRVT)
	    nocache = 1;
	
	if (nocache == 0) {
	    if (list != NULL)
		xmlXPathFreeObject(list);
	    list = newlist;

	    XSLT_RUNTIME_EXTRA_LST(ctxt, sel->lenExtra) =
		(void *) list;
	    XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) =
		(void *) doc;
	    XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) =
		0;
	    XSLT_RUNTIME_EXTRA_FREE(ctxt, sel->lenExtra) =
		(xmlFreeFunc) xmlXPathFreeObject;
	} else
	    list = newlist;
    }
    if ((list->nodesetval == NULL) ||
	(list->nodesetval->nodeNr <= 0)) {
	if (nocache == 1)
	    xmlXPathFreeObject(list);
	return(0);
    }
    /* TODO: store the index and use it for the scan */
    if (ix == 0) {
	for (j = 0;j < list->nodesetval->nodeNr;j++) {
	    if (list->nodesetval->nodeTab[j] == node) {
		if (nocache == 1)
		    xmlXPathFreeObject(list);
		return(1);
	    }
	}
    } else {
    }
    if (nocache == 1)
	xmlXPathFreeObject(list);
    return(0);
}

Project: libxslt
File: pattern.c

xsltReverseCompMatch(xsltParserContextPtr ctxt, xsltCompMatchPtr comp) {
    int i = 0;
    int j = comp->nbStep - 1;

    while (j > i) {
	register xmlChar *tmp;
	register xsltOp op;
	register xmlXPathCompExprPtr expr;
	register int t;

	tmp = comp->steps[i].value;
	comp->steps[i].value = comp->steps[j].value;
	comp->steps[j].value = tmp;
	tmp = comp->steps[i].value2;
	comp->steps[i].value2 = comp->steps[j].value2;
	comp->steps[j].value2 = tmp;
	tmp = comp->steps[i].value3;
	comp->steps[i].value3 = comp->steps[j].value3;
	comp->steps[j].value3 = tmp;
	op = comp->steps[i].op;
	comp->steps[i].op = comp->steps[j].op;
	comp->steps[j].op = op;
	expr = comp->steps[i].comp;
	comp->steps[i].comp = comp->steps[j].comp;
	comp->steps[j].comp = expr;
	t = comp->steps[i].previousExtra;
	comp->steps[i].previousExtra = comp->steps[j].previousExtra;
	comp->steps[j].previousExtra = t;
	t = comp->steps[i].indexExtra;
	comp->steps[i].indexExtra = comp->steps[j].indexExtra;
	comp->steps[j].indexExtra = t;
	t = comp->steps[i].lenExtra;
	comp->steps[i].lenExtra = comp->steps[j].lenExtra;
	comp->steps[j].lenExtra = t;
	j--;
	i++;
    }
    xsltCompMatchAdd(ctxt, comp, XSLT_OP_END, NULL, NULL, 0);

    /*
     * detect consecutive XSLT_OP_PREDICATE indicating a direct
     * matching should be done.
     */
    for (i = 0;i < comp->nbStep - 1;i++) {
        if ((comp->steps[i].op == XSLT_OP_PREDICATE) &&
	    (comp->steps[i + 1].op == XSLT_OP_PREDICATE)) {

	    comp->direct = 1;
	    if (comp->pattern[0] != '/') {
		xmlChar *query;

		query = xmlStrdup((const xmlChar *)"//");
		query = xmlStrcat(query, comp->pattern);

		xmlFree((xmlChar *) comp->pattern);
		comp->pattern = query;
	    }
	    break;
	}
    }
}

Project: libxslt
File: pattern.c

xsltTestCompMatch(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp,
	          xmlNodePtr node, const xmlChar *mode,
		  const xmlChar *modeURI) {
    int i;
    xsltStepOpPtr step, sel = NULL;
    xsltStepStates states = {0, 0, NULL}; /* // may require backtrack */

    if ((comp == NULL) || (node == NULL) || (ctxt == NULL)) {
	xsltTransformError(ctxt, NULL, node,
		"xsltTestCompMatch: null arg\n");
        return(-1);
    }
    if (mode != NULL) {
	if (comp->mode == NULL)
	    return(0);
	/*
	 * both mode strings must be interned on the stylesheet dictionary
	 */
	if (comp->mode != mode)
	    return(0);
    } else {
	if (comp->mode != NULL)
	    return(0);
    }
    if (modeURI != NULL) {
	if (comp->modeURI == NULL)
	    return(0);
	/*
	 * both modeURI strings must be interned on the stylesheet dictionary
	 */
	if (comp->modeURI != modeURI)
	    return(0);
    } else {
	if (comp->modeURI != NULL)
	    return(0);
    }

    i = 0;
restart:
    for (;i < comp->nbStep;i++) {
	step = &comp->steps[i];
	if (step->op != XSLT_OP_PREDICATE)
	    sel = step;
	switch (step->op) {
            case XSLT_OP_END:
		goto found;
            case XSLT_OP_ROOT:
		if ((node->type == XML_DOCUMENT_NODE) ||
#ifdef LIBXML_DOCB_ENABLED
		    (node->type == XML_DOCB_DOCUMENT_NODE) ||
#endif
		    (node->type == XML_HTML_DOCUMENT_NODE))
		    continue;
		if ((node->type == XML_ELEMENT_NODE) && (node->name[0] == ' '))
		    continue;
		goto rollback;
            case XSLT_OP_ELEM:
		if (node->type != XML_ELEMENT_NODE)
		    goto rollback;
		if (step->value == NULL)
		    continue;
		if (step->value[0] != node->name[0])
		    goto rollback;
		if (!xmlStrEqual(step->value, node->name))
		    goto rollback;

		/* Namespace test */
		if (node->ns == NULL) {
		    if (step->value2 != NULL)
			goto rollback;
		} else if (node->ns->href != NULL) {
		    if (step->value2 == NULL)
			goto rollback;
		    if (!xmlStrEqual(step->value2, node->ns->href))
			goto rollback;
		}
		continue;
            case XSLT_OP_ATTR:
		if (node->type != XML_ATTRIBUTE_NODE)
		    goto rollback;
		if (step->value != NULL) {
		    if (step->value[0] != node->name[0])
			goto rollback;
		    if (!xmlStrEqual(step->value, node->name))
			goto rollback;
		}
		/* Namespace test */
		if (node->ns == NULL) {
		    if (step->value2 != NULL)
			goto rollback;
		} else if (step->value2 != NULL) {
		    if (!xmlStrEqual(step->value2, node->ns->href))
			goto rollback;
		}
		continue;
            case XSLT_OP_PARENT:
		if ((node->type == XML_DOCUMENT_NODE) ||
		    (node->type == XML_HTML_DOCUMENT_NODE) ||
#ifdef LIBXML_DOCB_ENABLED
		    (node->type == XML_DOCB_DOCUMENT_NODE) ||
#endif
		    (node->type == XML_NAMESPACE_DECL))
		    goto rollback;
		node = node->parent;
		if (node == NULL)
		    goto rollback;
		if (step->value == NULL)
		    continue;
		if (step->value[0] != node->name[0])
		    goto rollback;
		if (!xmlStrEqual(step->value, node->name))
		    goto rollback;
		/* Namespace test */
		if (node->ns == NULL) {
		    if (step->value2 != NULL)
			goto rollback;
		} else if (node->ns->href != NULL) {
		    if (step->value2 == NULL)
			goto rollback;
		    if (!xmlStrEqual(step->value2, node->ns->href))
			goto rollback;
		}
		continue;
            case XSLT_OP_ANCESTOR:
		/* TODO: implement coalescing of ANCESTOR/NODE ops */
		if (step->value == NULL) {
		    step = &comp->steps[i+1];
		    if (step->op == XSLT_OP_ROOT)
			goto found;
		    /* added NS, ID and KEY as a result of bug 168208 */
		    if ((step->op != XSLT_OP_ELEM) && 
			(step->op != XSLT_OP_ALL) && 
			(step->op != XSLT_OP_NS) &&
			(step->op != XSLT_OP_ID) &&
			(step->op != XSLT_OP_KEY))
			goto rollback;
		}
		if (node == NULL)
		    goto rollback;
		if ((node->type == XML_DOCUMENT_NODE) ||
		    (node->type == XML_HTML_DOCUMENT_NODE) ||
#ifdef LIBXML_DOCB_ENABLED
		    (node->type == XML_DOCB_DOCUMENT_NODE) ||
#endif
		    (node->type == XML_NAMESPACE_DECL))
		    goto rollback;
		node = node->parent;
		if ((step->op != XSLT_OP_ELEM) && step->op != XSLT_OP_ALL) {
		    xsltPatPushState(ctxt, &states, i, node);
		    continue;
		}
		i++;
		if (step->value == NULL) {
		    xsltPatPushState(ctxt, &states, i - 1, node);
		    continue;
		}
		while (node != NULL) {
		    if ((node->type == XML_ELEMENT_NODE) &&
			(step->value[0] == node->name[0]) &&
			(xmlStrEqual(step->value, node->name))) {
			/* Namespace test */
			if (node->ns == NULL) {
			    if (step->value2 == NULL)
				break;
			} else if (node->ns->href != NULL) {
			    if ((step->value2 != NULL) &&
			        (xmlStrEqual(step->value2, node->ns->href)))
				break;
			}
		    }
		    node = node->parent;
		}
		if (node == NULL)
		    goto rollback;
		xsltPatPushState(ctxt, &states, i - 1, node);
		continue;
            case XSLT_OP_ID: {
		/* TODO Handle IDs decently, must be done differently */
		xmlAttrPtr id;

		if (node->type != XML_ELEMENT_NODE)
		    goto rollback;

		id = xmlGetID(node->doc, step->value);
		if ((id == NULL) || (id->parent != node))
		    goto rollback;
		break;
	    }
            case XSLT_OP_KEY: {
		xmlNodeSetPtr list;
		int indx;

		list = xsltGetKey(ctxt, step->value,
			          step->value3, step->value2);
		if (list == NULL)
		    goto rollback;
		for (indx = 0;indx < list->nodeNr;indx++)
		    if (list->nodeTab[indx] == node)
			break;
		if (indx >= list->nodeNr)
		    goto rollback;
		break;
	    }
            case XSLT_OP_NS:
		if (node->type != XML_ELEMENT_NODE)
		    goto rollback;
		if (node->ns == NULL) {
		    if (step->value != NULL)
			goto rollback;
		} else if (node->ns->href != NULL) {
		    if (step->value == NULL)
			goto rollback;
		    if (!xmlStrEqual(step->value, node->ns->href))
			goto rollback;
		}
		break;
            case XSLT_OP_ALL:
		if (node->type != XML_ELEMENT_NODE)
		    goto rollback;
		break;
	    case XSLT_OP_PREDICATE: {
		xmlNodePtr oldNode;
		xmlDocPtr doc;
		int oldCS, oldCP;
		int pos = 0, len = 0;
		int isRVT;

		/*
		 * when there is cascading XSLT_OP_PREDICATE, then use a
		 * direct computation approach. It's not done directly
		 * at the beginning of the routine to filter out as much
		 * as possible this costly computation.
		 */
		if (comp->direct) {
		    if (states.states != NULL) {
			/* Free the rollback states */
			xmlFree(states.states);
		    }
		    return(xsltTestCompMatchDirect(ctxt, comp, node,
		    				   comp->nsList, comp->nsNr));
		}

		doc = node->doc;
		if (XSLT_IS_RES_TREE_FRAG(doc))
		    isRVT = 1;
		else
		    isRVT = 0;

		/*
		 * Depending on the last selection, one may need to
		 * recompute contextSize and proximityPosition.
		 */
		oldCS = ctxt->xpathCtxt->contextSize;
		oldCP = ctxt->xpathCtxt->proximityPosition;
		if ((sel != NULL) &&
		    (sel->op == XSLT_OP_ELEM) &&
		    (sel->value != NULL) &&
		    (node->type == XML_ELEMENT_NODE) &&
		    (node->parent != NULL)) {
		    xmlNodePtr previous;
		    int nocache = 0;

		    previous = (xmlNodePtr)
			XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr);
		    if ((previous != NULL) &&
			(previous->parent == node->parent)) {
			/*
			 * just walk back to adjust the index
			 */
			int indx = 0;
			xmlNodePtr sibling = node;

			while (sibling != NULL) {
			    if (sibling == previous)
				break;
			    if ((sibling->type == XML_ELEMENT_NODE) &&
				(previous->name != NULL) &&
				(sibling->name != NULL) &&
				(previous->name[0] == sibling->name[0]) &&
				(xmlStrEqual(previous->name, sibling->name)))
			    {
				if ((sel->value2 == NULL) ||
				    ((sibling->ns != NULL) &&
				     (xmlStrEqual(sel->value2,
						  sibling->ns->href))))
				    indx++;
			    }
			    sibling = sibling->prev;
			}
			if (sibling == NULL) {
			    /* hum going backward in document order ... */
			    indx = 0;
			    sibling = node;
			    while (sibling != NULL) {
				if (sibling == previous)
				    break;
				if ((sibling->type == XML_ELEMENT_NODE) &&
				    (previous->name != NULL) &&
				    (sibling->name != NULL) &&
				    (previous->name[0] == sibling->name[0]) &&
				    (xmlStrEqual(previous->name, sibling->name)))
				{
				    if ((sel->value2 == NULL) ||
					((sibling->ns != NULL) &&
					(xmlStrEqual(sel->value2,
					sibling->ns->href))))
				    {
					indx--;
				    }
				}
				sibling = sibling->next;
			    }
			}
			if (sibling != NULL) {
		            pos = XSLT_RUNTIME_EXTRA(ctxt,
                                sel->indexExtra, ival) + indx;
			    /*
			     * If the node is in a Value Tree we need to
			     * save len, but cannot cache the node!
			     * (bugs 153137 and 158840)
			     */
			    if (node->doc != NULL) {
				len = XSLT_RUNTIME_EXTRA(ctxt,
				        sel->lenExtra, ival);
				if (!isRVT) {
				    XSLT_RUNTIME_EXTRA(ctxt,
					sel->previousExtra, ptr) = node;
				    XSLT_RUNTIME_EXTRA(ctxt,
				        sel->indexExtra, ival) = pos;
				}
			    }
			} else
			    pos = 0;
		    } else {
			/*
			 * recompute the index
			 */
			xmlNodePtr parent = node->parent;
			xmlNodePtr siblings = NULL;

                        if (parent) siblings = parent->children;

			while (siblings != NULL) {
			    if (siblings->type == XML_ELEMENT_NODE) {
				if (siblings == node) {
				    len++;
				    pos = len;
				} else if ((node->name != NULL) &&
					   (siblings->name != NULL) &&
				    (node->name[0] == siblings->name[0]) &&
				    (xmlStrEqual(node->name, siblings->name))) {
				    if ((sel->value2 == NULL) ||
					((siblings->ns != NULL) &&
					 (xmlStrEqual(sel->value2,
						      siblings->ns->href))))
					len++;
				}
			    }
			    siblings = siblings->next;
			}
			if ((parent == NULL) || (node->doc == NULL))
			    nocache = 1;
			else {
			    while (parent->parent != NULL)
				parent = parent->parent;
			    if (((parent->type != XML_DOCUMENT_NODE) &&
				 (parent->type != XML_HTML_DOCUMENT_NODE)) ||
				 (parent != (xmlNodePtr) node->doc))
				nocache = 1;
			}
		    }
		    if (pos != 0) {
			ctxt->xpathCtxt->contextSize = len;
			ctxt->xpathCtxt->proximityPosition = pos;
			/*
			 * If the node is in a Value Tree we cannot
			 * cache it !
			 */
			if ((!isRVT) && (node->doc != NULL) &&
			    (nocache == 0)) {
			    XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) =
				node;
			    XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) =
				pos;
			    XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival) =
				len;
			}
		    }
		} else if ((sel != NULL) && (sel->op == XSLT_OP_ALL) &&
			   (node->type == XML_ELEMENT_NODE)) {
		    xmlNodePtr previous;
		    int nocache = 0;

		    previous = (xmlNodePtr)
			XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr);
		    if ((previous != NULL) &&
			(previous->parent == node->parent)) {
			/*
			 * just walk back to adjust the index
			 */
			int indx = 0;
			xmlNodePtr sibling = node;

			while (sibling != NULL) {
			    if (sibling == previous)
				break;
			    if (sibling->type == XML_ELEMENT_NODE)
				indx++;
			    sibling = sibling->prev;
			}
			if (sibling == NULL) {
			    /* hum going backward in document order ... */
			    indx = 0;
			    sibling = node;
			    while (sibling != NULL) {
				if (sibling == previous)
				    break;
				if (sibling->type == XML_ELEMENT_NODE)
				    indx--;
				sibling = sibling->next;
			    }
			}
			if (sibling != NULL) {
			    pos = XSLT_RUNTIME_EXTRA(ctxt,
                                sel->indexExtra, ival) + indx;
			    /*
			     * If the node is in a Value Tree we cannot
			     * cache it !
			     */
			    if ((node->doc != NULL) && !isRVT) {
				len = XSLT_RUNTIME_EXTRA(ctxt,
				        sel->lenExtra, ival);
				XSLT_RUNTIME_EXTRA(ctxt,
					sel->previousExtra, ptr) = node;
				XSLT_RUNTIME_EXTRA(ctxt,
					sel->indexExtra, ival) = pos;
			    }
			} else
			    pos = 0;
		    } else {
			/*
			 * recompute the index
			 */
			xmlNodePtr parent = node->parent;
			xmlNodePtr siblings = NULL;

                        if (parent) siblings = parent->children;

			while (siblings != NULL) {
			    if (siblings->type == XML_ELEMENT_NODE) {
				len++;
				if (siblings == node) {
				    pos = len;
				}
			    }
			    siblings = siblings->next;
			}
			if ((parent == NULL) || (node->doc == NULL))
			    nocache = 1;
			else {
			    while (parent->parent != NULL)
				parent = parent->parent;
			    if (((parent->type != XML_DOCUMENT_NODE) &&
				 (parent->type != XML_HTML_DOCUMENT_NODE)) ||
				 (parent != (xmlNodePtr) node->doc))
				nocache = 1;
			}
		    }
		    if (pos != 0) {
			ctxt->xpathCtxt->contextSize = len;
			ctxt->xpathCtxt->proximityPosition = pos;
			/*
			 * If the node is in a Value Tree we cannot
			 * cache it !
			 */
			if ((node->doc != NULL) && (nocache == 0) && !isRVT) {
			    XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) =
				node;
			    XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) =
				pos;
			    XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival) =
				len;
			}
		    }
		}
		oldNode = ctxt->node;
		ctxt->node = node;

		if (step->value == NULL)
		    goto wrong_index;
		if (step->comp == NULL)
		    goto wrong_index;

		if (!xsltEvalXPathPredicate(ctxt, step->comp, comp->nsList,
			                    comp->nsNr))
		    goto wrong_index;

		if (pos != 0) {
		    ctxt->xpathCtxt->contextSize = oldCS;
		    ctxt->xpathCtxt->proximityPosition = oldCP;
		}
		ctxt->node = oldNode;
		break;
wrong_index:
		if (pos != 0) {
		    ctxt->xpathCtxt->contextSize = oldCS;
		    ctxt->xpathCtxt->proximityPosition = oldCP;
		}
		ctxt->node = oldNode;
		goto rollback;
	    }
            case XSLT_OP_PI:
		if (node->type != XML_PI_NODE)
		    goto rollback;
		if (step->value != NULL) {
		    if (!xmlStrEqual(step->value, node->name))
			goto rollback;
		}
		break;
            case XSLT_OP_COMMENT:
		if (node->type != XML_COMMENT_NODE)
		    goto rollback;
		break;
            case XSLT_OP_TEXT:
		if ((node->type != XML_TEXT_NODE) &&
		    (node->type != XML_CDATA_SECTION_NODE))
		    goto rollback;
		break;
            case XSLT_OP_NODE:
		switch (node->type) {
		    case XML_ELEMENT_NODE:
		    case XML_CDATA_SECTION_NODE:
		    case XML_PI_NODE:
		    case XML_COMMENT_NODE:
		    case XML_TEXT_NODE:
			break;
		    default:
			goto rollback;
		}
		break;
	}
    }
found:
    if (states.states != NULL) {
        /* Free the rollback states */
	xmlFree(states.states);
    }
    return(1);
rollback:
    /* got an error try to rollback */
    if (states.states == NULL)
	return(0);
    if (states.nbstates <= 0) {
	xmlFree(states.states);
	return(0);
    }
    states.nbstates--;
    i = states.states[states.nbstates].step;
    node = states.states[states.nbstates].node;
#if 0
    fprintf(stderr, "Pop: %d, %s\n", i, node->name);
#endif
    goto restart;
}

Project: libxslt
File: pattern.c

xsltAddTemplate(xsltStylesheetPtr style, xsltTemplatePtr cur,
	        const xmlChar *mode, const xmlChar *modeURI) {
    xsltCompMatchPtr pat, list, next;
    /*
     * 'top' will point to style->xxxMatch ptr - declaring as 'void'
     *  avoids gcc 'type-punned pointer' warning.
     */
    void **top = NULL;
    const xmlChar *name = NULL;
    float priority;              /* the priority */

    if ((style == NULL) || (cur == NULL) || (cur->match == NULL))
	return(-1);

    priority = cur->priority;
    pat = xsltCompilePatternInternal(cur->match, style->doc, cur->elem,
		    style, NULL, 1);
    if (pat == NULL)
    	return(-1);
    while (pat) {
	next = pat->next;
	pat->next = NULL;
	name = NULL;
	
	pat->template = cur;
	if (mode != NULL)
	    pat->mode = xmlDictLookup(style->dict, mode, -1);
	if (modeURI != NULL)
	    pat->modeURI = xmlDictLookup(style->dict, modeURI, -1);
	if (priority != XSLT_PAT_NO_PRIORITY)
	    pat->priority = priority;

	/*
	 * insert it in the hash table list corresponding to its lookup name
	 */
	switch (pat->steps[0].op) {
        case XSLT_OP_ATTR:
	    if (pat->steps[0].value != NULL)
		name = pat->steps[0].value;
	    else
		top = &(style->attrMatch);
	    break;
        case XSLT_OP_PARENT:
        case XSLT_OP_ANCESTOR:
	    top = &(style->elemMatch);
	    break;
        case XSLT_OP_ROOT:
	    top = &(style->rootMatch);
	    break;
        case XSLT_OP_KEY:
	    top = &(style->keyMatch);
	    break;
        case XSLT_OP_ID:
	    /* TODO optimize ID !!! */
        case XSLT_OP_NS:
        case XSLT_OP_ALL:
	    top = &(style->elemMatch);
	    break;
        case XSLT_OP_END:
	case XSLT_OP_PREDICATE:
	    xsltTransformError(NULL, style, NULL,
			     "xsltAddTemplate: invalid compiled pattern\n");
	    xsltFreeCompMatch(pat);
	    return(-1);
	    /*
	     * TODO: some flags at the top level about type based patterns
	     *       would be faster than inclusion in the hash table.
	     */
	case XSLT_OP_PI:
	    if (pat->steps[0].value != NULL)
		name = pat->steps[0].value;
	    else
		top = &(style->piMatch);
	    break;
	case XSLT_OP_COMMENT:
	    top = &(style->commentMatch);
	    break;
	case XSLT_OP_TEXT:
	    top = &(style->textMatch);
	    break;
        case XSLT_OP_ELEM:
	case XSLT_OP_NODE:
	    if (pat->steps[0].value != NULL)
		name = pat->steps[0].value;
	    else
		top = &(style->elemMatch);
	    break;
	}
	if (name != NULL) {
	    if (style->templatesHash == NULL) {
		style->templatesHash = xmlHashCreate(1024);
		if (style->templatesHash == NULL) {
		    xsltFreeCompMatch(pat);
		    return(-1);
		}
		xmlHashAddEntry3(style->templatesHash, name, mode, modeURI, pat);
	    } else {
		list = (xsltCompMatchPtr) xmlHashLookup3(style->templatesHash,
							 name, mode, modeURI);
		if (list == NULL) {
		    xmlHashAddEntry3(style->templatesHash, name,
				     mode, modeURI, pat);
		} else {
		    /*
		     * Note '<=' since one must choose among the matching
		     * template rules that are left, the one that occurs
		     * last in the stylesheet
		     */
		    if (list->priority <= pat->priority) {
			pat->next = list;
			xmlHashUpdateEntry3(style->templatesHash, name,
					    mode, modeURI, pat, NULL);
		    } else {
			while (list->next != NULL) {
			    if (list->next->priority <= pat->priority)
				break;
			    list = list->next;
			}
			pat->next = list->next;
			list->next = pat;
		    }
		}
	    }
	} else if (top != NULL) {
	    list = *top;
	    if (list == NULL) {
		*top = pat;
		pat->next = NULL;
	    } else if (list->priority <= pat->priority) {
		pat->next = list;
		*top = pat;
	    } else {
		while (list->next != NULL) {
		    if (list->next->priority <= pat->priority)
			break;
		    list = list->next;
		}
		pat->next = list->next;
		list->next = pat;
	    }
	} else {
	    xsltTransformError(NULL, style, NULL,
			     "xsltAddTemplate: invalid compiled pattern\n");
	    xsltFreeCompMatch(pat);
	    return(-1);
	}
#ifdef WITH_XSLT_DEBUG_PATTERN
	if (mode)
	    xsltGenericDebug(xsltGenericDebugContext,
			 "added pattern : '%s' mode '%s' priority %f\n",
			     pat->pattern, pat->mode, pat->priority);
	else
	    xsltGenericDebug(xsltGenericDebugContext,
			 "added pattern : '%s' priority %f\n",
			     pat->pattern, pat->priority);
#endif

	pat = next;
    }
    return(0);
}