Skip to content

Commit cfcac15

Browse files
committed
fix: node invariant at exception
Fixes: #1399
1 parent 2b47156 commit cfcac15

1 file changed

Lines changed: 48 additions & 24 deletions

File tree

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

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

Lines changed: 48 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -122,35 +122,59 @@ class remove_elements_to_reinsert
122122
>::type sorted_elements_type;
123123

124124
sorted_elements_type sorted_elements;
125-
// If constructor is used instead of resize() MS implementation leaks here
126-
sorted_elements.reserve(elements_count); // MAY THROW, STRONG (V, E: alloc, copy)
127125

128-
for ( typename elements_type::const_iterator it = elements.begin() ;
129-
it != elements.end() ; ++it )
126+
BOOST_TRY
130127
{
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-
}
128+
// If constructor is used instead of resize() MS implementation leaks here
129+
sorted_elements.reserve(elements_count); // MAY THROW, STRONG (alloc)
138130

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

155179
BOOST_TRY
156180
{

0 commit comments

Comments
 (0)