Skip to content

Commit 0a8c111

Browse files
committed
fix: avoid stack overflow in traverse
1 parent 69df6f8 commit 0a8c111

File tree

1 file changed

+63
-47
lines changed

1 file changed

+63
-47
lines changed

include/boost/geometry/algorithms/detail/overlay/graph/traverse_graph.hpp

Lines changed: 63 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -178,73 +178,89 @@ struct traverse_graph
178178
bool continue_traverse(Ring& ring,
179179
signed_size_type component_id,
180180
signed_size_type start_node_id,
181-
signed_size_type current_node_id)
181+
signed_size_type target_node_id)
182182
{
183-
auto const current_turn_indices = get_turn_indices_by_node_id(m_turns, m_clusters,
184-
current_node_id, allow_closed);
185-
186-
// Any valid node should always deliver at least one turn
187-
BOOST_ASSERT(! current_turn_indices.empty());
183+
signed_size_type current_node_id = target_node_id;
188184

189-
auto const next_target_nodes = get_target_nodes<target_operation>(m_turns, m_clusters,
190-
current_turn_indices, component_id);
185+
std::size_t iteration_count = 0;
191186

192-
if (next_target_nodes.empty())
187+
// Keep traversing until it finds the start (successful finish), or it is stuck,
188+
// or it find an already visited node during traversal.
189+
// The iteration count is a defensive check to prevent endless loops and not iterate
190+
// more than times there are turns (this should not happen).
191+
while (iteration_count < m_turns.size())
193192
{
193+
auto const current_turn_indices = get_turn_indices_by_node_id(m_turns, m_clusters,
194+
current_node_id, allow_closed);
195+
196+
// Any valid node should always deliver at least one turn
197+
BOOST_ASSERT(! current_turn_indices.empty());
198+
199+
auto const next_target_nodes = get_target_nodes<target_operation>(m_turns, m_clusters,
200+
current_turn_indices, component_id);
201+
202+
if (next_target_nodes.empty())
203+
{
194204
#if defined(BOOST_GEOMETRY_DEBUG_TRAVERSE_GRAPH)
195-
std::cout << "Stuck, start: " << start_node_id
196-
<< " stuck: " << current_node_id
197-
<< " (no targets) " << std::endl;
205+
std::cout << "Stuck, start: " << start_node_id
206+
<< " stuck: " << current_node_id
207+
<< " (no targets) " << std::endl;
198208
#endif
199-
return false;
200-
}
209+
return false;
210+
}
201211

202-
auto const tois = get_tois<target_operation>(m_turns, m_clusters,
203-
current_node_id, next_target_nodes);
212+
auto const tois = get_tois<target_operation>(m_turns, m_clusters,
213+
current_node_id, next_target_nodes);
204214

205-
if (tois.empty())
206-
{
207-
return false;
208-
}
215+
if (tois.empty())
216+
{
217+
return false;
218+
}
209219

210-
auto const& turn_point = m_turns[*current_turn_indices.begin()].point;
220+
auto const& turn_point = m_turns[*current_turn_indices.begin()].point;
211221

212-
auto toi = *tois.begin();
222+
auto toi = *tois.begin();
213223

214-
if (tois.size() > 1)
215-
{
216-
// Select the best target edge, using the last point of the ring and the turn point
217-
// for side calculations (if any).
218-
toi = m_edge_selector.select_target_edge(tois, ring.back(), turn_point);
219-
}
224+
if (tois.size() > 1)
225+
{
226+
// Select the best target edge, using the last point of the ring and the turn point
227+
// for side calculations (if any).
228+
toi = m_edge_selector.select_target_edge(tois, ring.back(), turn_point);
229+
}
220230

221-
if (m_visited_tois.count(toi) > 0 || m_finished_tois.count(toi) > 0)
222-
{
231+
if (m_visited_tois.count(toi) > 0 || m_finished_tois.count(toi) > 0)
232+
{
223233
#if defined(BOOST_GEOMETRY_DEBUG_TRAVERSE_GRAPH)
224-
std::cout << "ALREADY visited, turn " << toi
225-
<< " in {" << current_node_id
226-
<< " -> size " << next_target_nodes.size() << "}" << std::endl;
234+
std::cout << "ALREADY visited, turn " << toi
235+
<< " in {" << current_node_id
236+
<< " -> size " << next_target_nodes.size() << "}" << std::endl;
227237
#endif
228-
return false;
229-
}
238+
return false;
239+
}
230240

231-
detail::overlay::append_no_collinear(ring, turn_point, m_strategy);
241+
detail::overlay::append_no_collinear(ring, turn_point, m_strategy);
232242

233-
set_visited(toi);
234-
use_vertices(ring, toi);
243+
set_visited(toi);
244+
use_vertices(ring, toi);
235245

236-
auto const& selected_op = m_turns[toi.turn_index].operations[toi.operation_index];
237-
auto const next_target_node_id = get_node_id(m_turns,
238-
selected_op.enriched.travels_to_ip_index);
239-
if (next_target_node_id == start_node_id)
240-
{
246+
auto const& selected_op = m_turns[toi.turn_index].operations[toi.operation_index];
247+
auto const next_target_node_id = get_node_id(m_turns,
248+
selected_op.enriched.travels_to_ip_index);
249+
if (next_target_node_id == start_node_id)
250+
{
241251
#if defined(BOOST_GEOMETRY_DEBUG_TRAVERSE_GRAPH)
242-
std::cout << "Finished at: " << next_target_node_id << std::endl;
252+
std::cout << "Finished at: " << next_target_node_id << std::endl;
243253
#endif
244-
return true;
245-
}
254+
return true;
255+
}
246256

247-
return continue_traverse(ring, component_id, start_node_id, next_target_node_id);
257+
current_node_id = next_target_node_id;
258+
++iteration_count;
259+
}
260+
#if defined(BOOST_GEOMETRY_DEBUG_TRAVERSE_GRAPH)
261+
std::cout << "Cancelled at: " << iteration_count << std::endl;
262+
#endif
263+
return false;
248264
}
249265

250266
template <typename Rings>

0 commit comments

Comments
 (0)