[libxml2] Fix axis traversal from attribute and namespace nodes



commit 40f58521493e6a5429ea92964dec7bc09168224f
Author: Nick Wellnhofer <wellnhofer aevum de>
Date:   Fri May 26 20:16:35 2017 +0200

    Fix axis traversal from attribute and namespace nodes
    
    When traversing the "preceding" axis from an attribute node, we must
    first go up to the attribute's containing element. Otherwise, text
    children of other attributes could be returned. This made it possible
    to hit a code path in xmlXPathNextAncestor which contained another bug:
    The attribute node was initialized with the context node instead of the
    current node. Normally, this code path is only hit via
    xmlXPathNextAncestorOrSelf in which case the current and context node
    are the same.
    
    The combination of the two bugs could result in an infinite loop, found
    with libFuzzer.
    
    Traversing the "following" and the "preceding" axis from namespace nodes
    should be handled similarly. This wasn't supported at all previously.

 result/XPath/tests/nssimple   |   18 +++++++++++++++-
 result/XPath/tests/simplebase |    5 ++++
 test/XPath/docs/ns            |    2 +
 test/XPath/tests/nssimple     |    2 +
 test/XPath/tests/simplebase   |    1 +
 xpath.c                       |   42 ++++++++++++++++++++++++++++++----------
 6 files changed, 57 insertions(+), 13 deletions(-)
---
diff --git a/result/XPath/tests/nssimple b/result/XPath/tests/nssimple
index 8f0dd0e..cd09a17 100644
--- a/result/XPath/tests/nssimple
+++ b/result/XPath/tests/nssimple
@@ -17,8 +17,22 @@ Set contains 3 nodes:
 ========================
 Expression: //*[namespace::ns1]
 Object is a Node Set :
-Set contains 2 nodes:
+Set contains 4 nodes:
 1  ELEMENT doc
     namespace ns1 href=nsuri1
-2  ELEMENT elem
+2  ELEMENT preceding
+3  ELEMENT elem
     namespace ns2 href=nsuri2
+4  ELEMENT following
+
+========================
+Expression: /doc/elem/namespace::ns2/following::*
+Object is a Node Set :
+Set contains 1 nodes:
+1  ELEMENT following
+
+========================
+Expression: /doc/elem/namespace::ns2/preceding::*
+Object is a Node Set :
+Set contains 1 nodes:
+1  ELEMENT preceding
diff --git a/result/XPath/tests/simplebase b/result/XPath/tests/simplebase
index 3c32d17..6d4b347 100644
--- a/result/XPath/tests/simplebase
+++ b/result/XPath/tests/simplebase
@@ -125,3 +125,8 @@ Expression: /descendant::p/ancestor::chapter
 Object is a Node Set :
 Set contains 1 nodes:
 1  ELEMENT chapter
+
+========================
+Expression: /child::EXAMPLE/attribute::prop2/preceding::text()
+Object is a Node Set :
+Set contains 0 nodes:
diff --git a/test/XPath/docs/ns b/test/XPath/docs/ns
index 88f4575..2338a6f 100644
--- a/test/XPath/docs/ns
+++ b/test/XPath/docs/ns
@@ -1,3 +1,5 @@
 <doc xmlns:ns1="nsuri1">
+  <preceding/>
   <elem xmlns:ns2="nsuri2"/>
+  <following/>
 </doc>
diff --git a/test/XPath/tests/nssimple b/test/XPath/tests/nssimple
index d2a9528..8b343a3 100644
--- a/test/XPath/tests/nssimple
+++ b/test/XPath/tests/nssimple
@@ -1,3 +1,5 @@
 /doc/elem/namespace::node()/..
 /doc/elem/namespace::*/self::node()[true()]
 //*[namespace::ns1]
+/doc/elem/namespace::ns2/following::*
+/doc/elem/namespace::ns2/preceding::*
diff --git a/test/XPath/tests/simplebase b/test/XPath/tests/simplebase
index 8b2c7d1..7b302af 100644
--- a/test/XPath/tests/simplebase
+++ b/test/XPath/tests/simplebase
@@ -13,3 +13,4 @@
 /child::EXAMPLE/attribute::prop1/ancestor-or-self::*
 /descendant::title
 /descendant::p/ancestor::chapter
+/child::EXAMPLE/attribute::prop2/preceding::text()
diff --git a/xpath.c b/xpath.c
index 6f4da78..dce1107 100644
--- a/xpath.c
+++ b/xpath.c
@@ -8135,12 +8135,12 @@ xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
                return(NULL);
            return(cur->parent);
        case XML_ATTRIBUTE_NODE: {
-           xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
+           xmlAttrPtr att = (xmlAttrPtr) cur;
 
            return(att->parent);
        }
        case XML_NAMESPACE_DECL: {
-           xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
+           xmlNsPtr ns = (xmlNsPtr) cur;
 
            if ((ns->next != NULL) &&
                (ns->next->type != XML_NAMESPACE_DECL))
@@ -8257,10 +8257,16 @@ xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 
     if (cur == NULL) {
         cur = ctxt->context->node;
-        if (cur->type == XML_NAMESPACE_DECL)
-            return(NULL);
-        if (cur->type == XML_ATTRIBUTE_NODE)
+        if (cur->type == XML_ATTRIBUTE_NODE) {
             cur = cur->parent;
+        } else if (cur->type == XML_NAMESPACE_DECL) {
+            xmlNsPtr ns = (xmlNsPtr) cur;
+
+            if ((ns->next == NULL) ||
+                (ns->next->type == XML_NAMESPACE_DECL))
+                return (NULL);
+            cur = (xmlNodePtr) ns->next;
+        }
     }
     if (cur == NULL) return(NULL) ; /* ERROR */
     if (cur->next != NULL) return(cur->next) ;
@@ -8321,10 +8327,16 @@ xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
     if (cur == NULL) {
         cur = ctxt->context->node;
-        if (cur->type == XML_NAMESPACE_DECL)
-            return(NULL);
-        if (cur->type == XML_ATTRIBUTE_NODE)
-            return(cur->parent);
+        if (cur->type == XML_ATTRIBUTE_NODE) {
+            cur = cur->parent;
+        } else if (cur->type == XML_NAMESPACE_DECL) {
+            xmlNsPtr ns = (xmlNsPtr) cur;
+
+            if ((ns->next == NULL) ||
+                (ns->next->type == XML_NAMESPACE_DECL))
+                return (NULL);
+            cur = (xmlNodePtr) ns->next;
+        }
     }
     if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
        return (NULL);
@@ -8369,8 +8381,16 @@ xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
         cur = ctxt->context->node;
         if (cur == NULL)
             return (NULL);
-        if (cur->type == XML_NAMESPACE_DECL)
-            return (NULL);
+        if (cur->type == XML_ATTRIBUTE_NODE) {
+            cur = cur->parent;
+        } else if (cur->type == XML_NAMESPACE_DECL) {
+            xmlNsPtr ns = (xmlNsPtr) cur;
+
+            if ((ns->next == NULL) ||
+                (ns->next->type == XML_NAMESPACE_DECL))
+                return (NULL);
+            cur = (xmlNodePtr) ns->next;
+        }
         ctxt->ancestor = cur->parent;
     }
     if (cur->type == XML_NAMESPACE_DECL)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]