[geos-commits] [SCM] GEOS branch main updated. cd6b251809cc60f1d05684b324eaac1635ab04d9
git at osgeo.org
git at osgeo.org
Thu Oct 1 06:05:33 PDT 2026
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, main has been updated
via cd6b251809cc60f1d05684b324eaac1635ab04d9 (commit)
from 2e9e1b5bdeb2af6cd4b4e0161bc810e5e273235e (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 cd6b251809cc60f1d05684b324eaac1635ab04d9
Author: Daniel Baston <dbaston at gmail.com>
Date: Thu Oct 1 09:05:15 2026 -0400
TopologyPreservingSimplifier: Avoid stack overflow (#1519)
References https://github.com/libgeos/geos/issues/1515
diff --git a/src/simplify/TaggedLineStringSimplifier.cpp b/src/simplify/TaggedLineStringSimplifier.cpp
index 842710ae8..69e88f904 100644
--- a/src/simplify/TaggedLineStringSimplifier.cpp
+++ b/src/simplify/TaggedLineStringSimplifier.cpp
@@ -89,101 +89,112 @@ TaggedLineStringSimplifier::simplify(TaggedLineString* nLine, double distanceTol
}
}
+struct Section {
+std::size_t i;
+std::size_t j;
+std::size_t depth;
+};
+
/*private*/
void
-TaggedLineStringSimplifier::simplifySection(std::size_t i,
- std::size_t j, std::size_t depth, double distanceTolerance)
+TaggedLineStringSimplifier::simplifySection(std::size_t init_i,
+ std::size_t init_j, std::size_t init_depth, double distanceTolerance)
{
- depth += 1;
+ std::stack<Section> stack;
+ stack.push({init_i, init_j, init_depth + 1});
-#if GEOS_DEBUG
- std::cerr << "TaggedLineStringSimplifier[" << this << "] "
- << " simplifying section " << i << "-" << j
- << std::endl;
-#endif
+ while (!stack.empty()) {
+ const auto [i, j, depth] = stack.top();
+ stack.pop();
- if((i + 1) == j) {
-
-#if GEOS_DEBUG
- std::cerr << "single segment, no flattening"
+ #if GEOS_DEBUG
+ std::cerr << "TaggedLineStringSimplifier[" << this << "] "
+ << " simplifying section " << i << "-" << j
<< std::endl;
-#endif
- std::unique_ptr<TaggedLineSegment> newSeg(new
- TaggedLineSegment(*(line->getSegment(i))));
+ #endif
- line->addToResult(std::move(newSeg));
- // leave this segment in the input index, for efficiency
- return;
- }
+ if((i + 1) == j) {
- bool isValidToSimplify = true;
+ #if GEOS_DEBUG
+ std::cerr << "single segment, no flattening"
+ << std::endl;
+ #endif
+ auto newSeg = std::make_unique<TaggedLineSegment>(*(line->getSegment(i)));
- /*
- * Following logic ensures that there is enough points in the
- * output line.
- * If there is already more points than the minimum, there's
- * nothing to check.
- * Otherwise, if in the worst case there wouldn't be enough points,
- * don't flatten this segment (which avoids the worst case scenario)
- */
- if(line->getResultSize() < line->getMinimumSize()) {
- std::size_t worstCaseSize = depth + 1;
- if(worstCaseSize < line->getMinimumSize()) {
+ line->addToResult(std::move(newSeg));
+ // leave this segment in the input index, for efficiency
+ continue;
+ }
+
+ bool isValidToSimplify = true;
+
+ /*
+ * Following logic ensures that there is enough points in the
+ * output line.
+ * If there is already more points than the minimum, there's
+ * nothing to check.
+ * Otherwise, if in the worst case there wouldn't be enough points,
+ * don't flatten this segment (which avoids the worst case scenario)
+ */
+ if(line->getResultSize() < line->getMinimumSize()) {
+ std::size_t worstCaseSize = depth + 1;
+ if(worstCaseSize < line->getMinimumSize()) {
+ isValidToSimplify = false;
+ }
+ }
+
+ double distance;
+
+ // pass distance by ref
+ std::size_t furthestPtIndex = findFurthestPoint(linePts, i, j, distance);
+
+ #if GEOS_DEBUG
+ std::cerr << "furthest point " << furthestPtIndex
+ << " at distance " << distance
+ << std::endl;
+ #endif
+
+ if (distance < 0) {
+ // negative distance indicates that we could not compute distance to the
+ // farthest point, probably because of infinite or large-magnitude coordinates.
+ // avoid trying to simplify this section.
+ for (std::size_t k = i; k < j; k++) {
+ auto newSeg = std::make_unique<TaggedLineSegment>(*(line->getSegment(k)));
+ line->addToResult(std::move(newSeg));
+ }
+
+ continue;
+ }
+
+ // flattening must be less than distanceTolerance
+ if(distance > distanceTolerance) {
isValidToSimplify = false;
}
- }
- double distance;
-
- // pass distance by ref
- std::size_t furthestPtIndex = findFurthestPoint(linePts, i, j, distance);
-
-#if GEOS_DEBUG
- std::cerr << "furthest point " << furthestPtIndex
- << " at distance " << distance
- << std::endl;
-#endif
-
- if (distance < 0) {
- // negative distance indicates that we could not compute distance to the
- // farthest point, probably because of infinite or large-magnitude coordinates.
- // avoid trying to simplify this section.
- for (std::size_t k = i; k < j; k++) {
- auto newSeg = std::make_unique<TaggedLineSegment>(*(line->getSegment(k)));
- line->addToResult(std::move(newSeg));
+ if (isValidToSimplify) {
+ // test if flattened section would cause intersection or jump
+ LineSegment flatSeg(linePts->getAt(i), linePts->getAt(j));
+ isValidToSimplify = isTopologyValid(line, i, j, flatSeg);
}
- return;
+ if(isValidToSimplify) {
+
+ std::unique_ptr<TaggedLineSegment> newSeg = flatten(i, j);
+
+ #if GEOS_DEBUG
+ std::cerr << "isValidToSimplify, adding seg "
+ << newSeg->p0 << ", " << newSeg->p1
+ << " to TaggedLineSegment[" << line << "] result "
+ << std::endl;
+ #endif
+
+ line->addToResult(std::move(newSeg));
+ continue;
+ }
+
+ stack.push({furthestPtIndex, j, depth+1});
+ stack.push({i, furthestPtIndex, depth+1});
}
-
- // flattening must be less than distanceTolerance
- if(distance > distanceTolerance) {
- isValidToSimplify = false;
- }
-
- if (isValidToSimplify) {
- // test if flattened section would cause intersection or jump
- LineSegment flatSeg(linePts->getAt(i), linePts->getAt(j));
- isValidToSimplify = isTopologyValid(line, i, j, flatSeg);
- }
-
- if(isValidToSimplify) {
-
- std::unique_ptr<TaggedLineSegment> newSeg = flatten(i, j);
-
-#if GEOS_DEBUG
- std::cerr << "isValidToSimplify, adding seg "
- << newSeg->p0 << ", " << newSeg->p1
- << " to TaggedLineSegment[" << line << "] result "
- << std::endl;
-#endif
-
- line->addToResult(std::move(newSeg));
- return;
- }
-
- simplifySection(i, furthestPtIndex, depth, distanceTolerance);
- simplifySection(furthestPtIndex, j, depth, distanceTolerance);
}
/*private*/
diff --git a/src/simplify/TopologyPreservingSimplifier.cpp b/src/simplify/TopologyPreservingSimplifier.cpp
index b796610e0..e798a47f1 100644
--- a/src/simplify/TopologyPreservingSimplifier.cpp
+++ b/src/simplify/TopologyPreservingSimplifier.cpp
@@ -186,14 +186,13 @@ LineStringMapBuilderFilter::filter_ro(const Geometry* geom)
auto ls = static_cast<const LineString*>(geom);
std::size_t minSize = ls->isClosed() ? 4 : 2;
- TaggedLineString* taggedLine = new TaggedLineString(ls, minSize, isRing);
+ auto taggedLine = std::make_unique<TaggedLineString>(ls, minSize, isRing);
// Duplicated Geometry pointers shouldn't happen
- if(! linestringMap.insert(std::make_pair(geom, taggedLine)).second) {
- delete taggedLine;
+ if(! linestringMap.insert(std::make_pair(geom, taggedLine.get())).second) {
throw util::GEOSException("Duplicated Geometry components detected");
}
- tlsVector.push_back(taggedLine);
+ tlsVector.push_back(taggedLine.release());
}
diff --git a/tests/unit/simplify/TopologyPreservingSimplifierTest.cpp b/tests/unit/simplify/TopologyPreservingSimplifierTest.cpp
index 651627b05..48a178ce5 100644
--- a/tests/unit/simplify/TopologyPreservingSimplifierTest.cpp
+++ b/tests/unit/simplify/TopologyPreservingSimplifierTest.cpp
@@ -473,4 +473,23 @@ void object::test<36>()
}
}
+template<>
+template<>
+void object::test<37>()
+{
+ set_test_name("no stack overflow with large number of repeated vertices");
+
+ const std::size_t n = 10000;
+ auto seq = std::make_shared<CoordinateSequence>(n, false, false);
+ for (std::size_t i = 0; i < n; i++) {
+ seq->setAt(geos::geom::CoordinateXY{1, 1}, i);
+ }
+
+ auto input = gf->createLineString(seq);
+
+ auto simplified = TopologyPreservingSimplifier::simplify(input.get(), 1e-3);
+
+ // No crash
+}
+
} // namespace tut
-----------------------------------------------------------------------
Summary of changes:
src/simplify/TaggedLineStringSimplifier.cpp | 157 +++++++++++----------
src/simplify/TopologyPreservingSimplifier.cpp | 7 +-
.../simplify/TopologyPreservingSimplifierTest.cpp | 19 +++
3 files changed, 106 insertions(+), 77 deletions(-)
hooks/post-receive
--
GEOS
More information about the geos-commits
mailing list