[geos-commits] [SCM] GEOS branch 3.9 updated. 1f727025ec8c19f2d540c902580862ef4c670b11

git at osgeo.org git at osgeo.org
Thu Sep 23 17:33:12 PDT 2021


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GEOS".

The branch, 3.9 has been updated
       via  1f727025ec8c19f2d540c902580862ef4c670b11 (commit)
      from  4e0008c232831d95c909982b2981e3556111760b (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 1f727025ec8c19f2d540c902580862ef4c670b11
Author: Paul Ramsey <pramsey at cleverelephant.ca>
Date:   Thu Sep 23 17:32:57 2021 -0700

    Avoid stack overflow in KdTree::queryNode (from Even Roualt)

diff --git a/NEWS b/NEWS
index 8a066d0..db42c61 100644
--- a/NEWS
+++ b/NEWS
@@ -11,6 +11,8 @@ Changes in 3.9.2
   - Performance improvement in SegmentNodeList (Even Rouault)
   - Catch memory leaks on createPolygon failure (#1111, Paul Ramsey)
   - Fix DiscreteFrechetDistance to use initial points of input lines (#1128, Martin Davis)
+  - Avoid stack overflow in KdTree::queryNode (Even Roualt)
+
 
 Changes in 3.9.1
 2021-02-10
diff --git a/src/index/kdtree/KdTree.cpp b/src/index/kdtree/KdTree.cpp
index 1df6e48..75530fb 100644
--- a/src/index/kdtree/KdTree.cpp
+++ b/src/index/kdtree/KdTree.cpp
@@ -17,6 +17,7 @@
 
 #include <vector>
 #include <algorithm>
+#include <stack>
 
 using namespace geos::geom;
 
@@ -152,34 +153,76 @@ KdTree::insertExact(const geom::Coordinate& p, void* data)
 void
 KdTree::queryNode(KdNode* currentNode, const geom::Envelope& queryEnv, bool odd, KdNodeVisitor& visitor)
 {
-    if (currentNode == nullptr)
-        return;
-
-    double min;
-    double max;
-    double discriminant;
-
-    if (odd) {
-        min = queryEnv.getMinX();
-        max = queryEnv.getMaxX();
-        discriminant = currentNode->getX();
-    } else {
-        min = queryEnv.getMinY();
-        max = queryEnv.getMaxY();
-        discriminant = currentNode->getY();
-    }
-    bool searchLeft = min < discriminant;
-    bool searchRight = discriminant <= max;
-
-    // search is computed via in-order traversal
-    if (searchLeft) {
-        queryNode(currentNode->getLeft(), queryEnv, !odd, visitor);
-    }
-    if (queryEnv.contains(currentNode->getCoordinate())) {
-        visitor.visit(currentNode);
-    }
-    if (searchRight) {
-        queryNode(currentNode->getRight(), queryEnv, !odd, visitor);
+    // Non recursive formulation of in-order traversal from
+    // http://web.cs.wpi.edu/~cs2005/common/iterative.inorder
+    // Otherwise we may blow up the stack
+    // See https://github.com/qgis/QGIS/issues/45226
+    typedef std::pair<KdNode*, bool> Pair;
+    std::stack<Pair> activeNodes;
+    while(true)
+    {
+        if( currentNode != nullptr )
+        {
+            double min;
+            double discriminant;
+
+            if (odd) {
+                min = queryEnv.getMinX();
+                discriminant = currentNode->getX();
+            } else {
+                min = queryEnv.getMinY();
+                discriminant = currentNode->getY();
+            }
+            bool searchLeft = min < discriminant;
+
+            activeNodes.emplace(Pair(currentNode, odd));
+
+            // search is computed via in-order traversal
+            KdNode* leftNode = nullptr;
+            if (searchLeft ) {
+                leftNode = currentNode->getLeft();
+            }
+            if( leftNode ) {
+                currentNode = leftNode;
+                odd = !odd;
+            } else {
+                currentNode = nullptr;
+            }
+        }
+        else if( !activeNodes.empty() )
+        {
+            currentNode = activeNodes.top().first;
+            odd = activeNodes.top().second;
+            activeNodes.pop();
+
+            if (queryEnv.contains(currentNode->getCoordinate())) {
+                visitor.visit(currentNode);
+            }
+
+            double max;
+            double discriminant;
+
+            if (odd) {
+                max = queryEnv.getMaxX();
+                discriminant = currentNode->getX();
+            } else {
+                max = queryEnv.getMaxY();
+                discriminant = currentNode->getY();
+            }
+            bool searchRight = discriminant <= max;
+
+            if (searchRight) {
+                currentNode = currentNode->getRight();
+                if( currentNode )
+                    odd = !odd;
+            } else {
+                currentNode = nullptr;
+            }
+        }
+        else
+        {
+            break;
+        }
     }
 }
 
@@ -187,29 +230,32 @@ KdTree::queryNode(KdNode* currentNode, const geom::Envelope& queryEnv, bool odd,
 KdNode*
 KdTree::queryNodePoint(KdNode* currentNode, const geom::Coordinate& queryPt, bool odd)
 {
-    if (currentNode == nullptr)
-        return nullptr;
-    if (currentNode->getCoordinate().equals2D(queryPt))
-        return currentNode;
-
-    double ord;
-    double discriminant;
-    if (odd) {
-        ord = queryPt.x;
-        discriminant = currentNode->getX();
-    }
-    else {
-        ord = queryPt.y;
-        discriminant = currentNode->getY();
-    }
+    while (currentNode != nullptr)
+    {
+        if (currentNode->getCoordinate().equals2D(queryPt))
+            return currentNode;
 
-    bool searchLeft = (ord < discriminant);
-    if (searchLeft) {
-        return queryNodePoint(currentNode->getLeft(), queryPt, !odd);
-    }
-    else {
-        return queryNodePoint(currentNode->getRight(), queryPt, !odd);
+        double ord;
+        double discriminant;
+        if (odd) {
+            ord = queryPt.x;
+            discriminant = currentNode->getX();
+        }
+        else {
+            ord = queryPt.y;
+            discriminant = currentNode->getY();
+        }
+
+        bool searchLeft = (ord < discriminant);
+        odd = !odd;
+        if (searchLeft) {
+            currentNode = currentNode->getLeft();
+        }
+        else {
+            currentNode = currentNode->getRight();
+        }
     }
+    return nullptr;
 }
 
 

-----------------------------------------------------------------------

Summary of changes:
 NEWS                        |   2 +
 src/index/kdtree/KdTree.cpp | 144 +++++++++++++++++++++++++++++---------------
 2 files changed, 97 insertions(+), 49 deletions(-)


hooks/post-receive
-- 
GEOS


More information about the geos-commits mailing list