Skip to content

Commit ad2761f

Browse files
committed
fix: node invariant at exception
Fixes: #1399
1 parent 0ba089b commit ad2761f

1 file changed

Lines changed: 46 additions & 22 deletions

File tree

  • include/boost/geometry/index/detail/rtree/rstar

include/boost/geometry/index/detail/rtree/rstar/insert.hpp

Lines changed: 46 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -125,32 +125,56 @@ class remove_elements_to_reinsert
125125
// If constructor is used instead of resize() MS implementation leaks here
126126
sorted_elements.reserve(elements_count); // MAY THROW, STRONG (V, E: alloc, copy)
127127

128-
for ( typename elements_type::const_iterator it = elements.begin() ;
129-
it != elements.end() ; ++it )
128+
BOOST_TRY
130129
{
131-
point_type element_center;
132-
geometry::centroid(rtree::element_indexable(*it, translator), element_center,
133-
strategy);
134-
sorted_elements.push_back(std::make_pair(
135-
comparable_distance_pp::call(node_center, element_center, strategy),
136-
*it)); // MAY THROW (V, E: copy)
137-
}
130+
for ( typename elements_type::const_iterator it = elements.begin() ;
131+
it != elements.end() ; ++it )
132+
{
133+
point_type element_center;
134+
geometry::centroid(rtree::element_indexable(*it, translator), element_center,
135+
strategy);
136+
sorted_elements.push_back(std::make_pair(
137+
comparable_distance_pp::call(node_center, element_center, strategy),
138+
*it)); // MAY THROW (V, E: copy)
139+
}
138140

139-
// sort elements by distances from center
140-
std::partial_sort(
141-
sorted_elements.begin(),
142-
sorted_elements.begin() + reinserted_elements_count,
143-
sorted_elements.end(),
144-
distances_dsc<comparable_distance_type, element_type>); // MAY THROW, BASIC (V, E: copy)
145-
146-
// copy elements which will be reinserted
147-
result_elements.clear();
148-
result_elements.reserve(reinserted_elements_count); // MAY THROW, STRONG (V, E: alloc, copy)
149-
for ( typename sorted_elements_type::const_iterator it = sorted_elements.begin() ;
150-
it != sorted_elements.begin() + reinserted_elements_count ; ++it )
141+
// sort elements by distances from center
142+
std::partial_sort(
143+
sorted_elements.begin(),
144+
sorted_elements.begin() + reinserted_elements_count,
145+
sorted_elements.end(),
146+
distances_dsc<comparable_distance_type, element_type>); // MAY THROW, BASIC (V, E: copy)
147+
148+
// copy elements which will be reinserted
149+
result_elements.clear();
150+
result_elements.reserve(reinserted_elements_count); // MAY THROW, STRONG (V, E: alloc, copy)
151+
for ( typename sorted_elements_type::const_iterator it = sorted_elements.begin() ;
152+
it != sorted_elements.begin() + reinserted_elements_count ; ++it )
153+
{
154+
result_elements.push_back(it->second); // MAY THROW (V, E: copy)
155+
}
156+
}
157+
BOOST_CATCH(...)
151158
{
152-
result_elements.push_back(it->second); // MAY THROW (V, E: copy)
159+
// NOTE: This code is here to prevent leaving the node in overflow state
160+
// (with more than max elements) after an exception is thrown during the
161+
// preparation of elements for reinsertion (#1399). At this point the node
162+
// has not been modified yet and still contains exactly max+1 elements
163+
// (one push_back triggered the overflow handling).
164+
// Remove the overflow element to restore the node invariant, matching
165+
// the behavior of the split exception handler.
166+
result_elements.clear();
167+
168+
auto & elems = rtree::elements(n);
169+
if (elems.size() > parameters.get_max_elements())
170+
{
171+
destroy_element<MembersHolder>::apply(elems.back(), allocators);
172+
elems.pop_back();
173+
}
174+
175+
BOOST_RETHROW
153176
}
177+
BOOST_CATCH_END
154178

155179
BOOST_TRY
156180
{

0 commit comments

Comments
 (0)