Skip to content

Commit 20ad12f

Browse files
committed
Remove UB in flat_map implementation when the implementation has a movable std::pair
1 parent 429024c commit 20ad12f

File tree

4 files changed

+241
-134
lines changed

4 files changed

+241
-134
lines changed

.gitignore

Lines changed: 12 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -2,121 +2,17 @@
22
# This .gitignore file was automatically created by Microsoft(R) Visual Studio.
33
################################################################################
44

5-
/proj/vs/.vs
6-
/proj/vs/x64
7-
/proj/vs/Win32
8-
/proj/vs/allocator_traits_test.vcxproj.user
9-
/proj/vs/alloc_basic_test.vcxproj.user
10-
/proj/vs/alloc_full_test.vcxproj.user
11-
/proj/vs/alloc_lib.vcxproj.user
12-
/proj/vs/bench_adaptive_node_pool.vcxproj.user
13-
/proj/vs/bench_alloc.vcxproj.user
14-
/proj/vs/bench_alloc_expand_bwd.vcxproj.user
15-
/proj/vs/bench_alloc_expand_fwd.vcxproj.user
16-
/proj/vs/bench_alloc_shrink_to_fit.vcxproj.user
17-
/proj/vs/bench_alloc_stable_vector_burst.vcxproj.user
18-
/proj/vs/bench_flat_multiset.vcxproj.user
19-
/proj/vs/bench_flat_set.vcxproj.user
20-
/proj/vs/bench_hash_map_string_test.vcxproj
21-
/proj/vs/bench_hash_map_string_test.vcxproj.user
22-
/proj/vs/bench_hash_map_test.vcxproj
23-
/proj/vs/bench_hash_map_test.vcxproj.user
24-
/proj/vs/bench_hash_map_uint32_test.vcxproj
25-
/proj/vs/bench_hash_map_uint32_test.vcxproj.user
26-
/proj/vs/bench_hash_map_uint64_test.vcxproj
27-
/proj/vs/bench_hash_map_uint64_test.vcxproj.user
28-
/proj/vs/bench_hash_set_test.vcxproj
29-
/proj/vs/bench_set.vcxproj.user
30-
/proj/vs/bench_set_adaptive_pool.vcxproj.user
31-
/proj/vs/bench_set_alloc_v2.vcxproj.user
32-
/proj/vs/bench_set_avl.vcxproj.user
33-
/proj/vs/bench_set_multi.vcxproj.user
34-
/proj/vs/bench_set_sg.vcxproj.user
35-
/proj/vs/bench_set_sp.vcxproj.user
36-
/proj/vs/bench_static_vector.vcxproj.user
37-
/proj/vs/bench_vectors.vcxproj.user
38-
/proj/vs/boost_iterator_comp_test.vcxproj.user
39-
/proj/vs/common_iterator_test.vcxproj.user
40-
/proj/vs/container.vcxproj
41-
/proj/vs/container.vcxproj.filters
42-
/proj/vs/container.vcxproj.user
43-
/proj/vs/copy_move_algo_test.vcxproj.user
44-
/proj/vs/deque_options_test.vcxproj.user
45-
/proj/vs/deque_test.vcxproj.user
46-
/proj/vs/devector_options_test.vcxproj.user
47-
/proj/vs/devector_test.vcxproj.user
48-
/proj/vs/doc_custom_deque.vcxproj.user
49-
/proj/vs/doc_custom_devector.vcxproj.user
50-
/proj/vs/doc_custom_small_vector.vcxproj.user
51-
/proj/vs/doc_custom_static_vector.vcxproj.user
52-
/proj/vs/doc_custom_tree.vcxproj.user
53-
/proj/vs/doc_custom_vector.vcxproj.user
54-
/proj/vs/doc_emplace.vcxproj.user
55-
/proj/vs/doc_extended_allocators.vcxproj.user
56-
/proj/vs/doc_move_containers.vcxproj.user
57-
/proj/vs/doc_pmr.vcxproj.user
58-
/proj/vs/doc_recursive_containers.vcxproj.user
59-
/proj/vs/doc_type_erasure.vcxproj.user
60-
/proj/vs/explicit_inst_deque_test.vcxproj.user
61-
/proj/vs/explicit_inst_devector_test.vcxproj.user
62-
/proj/vs/explicit_inst_flat_map_test.vcxproj.user
63-
/proj/vs/explicit_inst_flat_set_test.vcxproj.user
64-
/proj/vs/explicit_inst_list_test.vcxproj.user
65-
/proj/vs/explicit_inst_map_test.vcxproj.user
66-
/proj/vs/explicit_inst_set_test.vcxproj.user
67-
/proj/vs/explicit_inst_slist_test.vcxproj.user
68-
/proj/vs/explicit_inst_small_vector_test.vcxproj.user
69-
/proj/vs/explicit_inst_stable_vector_test.vcxproj.user
70-
/proj/vs/explicit_inst_static_vector_test.vcxproj.user
71-
/proj/vs/explicit_inst_string_test.vcxproj.user
72-
/proj/vs/explicit_inst_vector_test.vcxproj.user
73-
/proj/vs/flat_map_adaptor_test.vcxproj.user
74-
/proj/vs/flat_map_test.vcxproj.user
75-
/proj/vs/flat_set_adaptor_test.vcxproj.user
76-
/proj/vs/flat_set_test.vcxproj.user
77-
/proj/vs/flat_tree_test.vcxproj.user
78-
/proj/vs/global_resource.vcxproj.user
79-
/proj/vs/insert_vs_emplace_test.vcxproj.user
80-
/proj/vs/list_test.vcxproj.user
81-
/proj/vs/map_test.vcxproj.user
82-
/proj/vs/memory_resource_test.vcxproj.user
83-
/proj/vs/monotonic_buffer_resource_test.vcxproj.user
84-
/proj/vs/node_handle_test.vcxproj.user
85-
/proj/vs/null_iterators_test.vcxproj.user
86-
/proj/vs/pair_test.vcxproj.user
87-
/proj/vs/pmr_deque_test.vcxproj.user
88-
/proj/vs/pmr_devector_test.vcxproj.user
89-
/proj/vs/pmr_flat_map_test.vcxproj.user
90-
/proj/vs/pmr_flat_set_test.vcxproj.user
91-
/proj/vs/pmr_list_test.vcxproj.user
92-
/proj/vs/pmr_map_test.vcxproj.user
93-
/proj/vs/pmr_set_test.vcxproj.user
94-
/proj/vs/pmr_slist_test.vcxproj.user
95-
/proj/vs/pmr_small_vector_test.vcxproj.user
96-
/proj/vs/pmr_stable_vector_test.vcxproj.user
97-
/proj/vs/pmr_string_test.vcxproj.user
98-
/proj/vs/pmr_vector_test.vcxproj.user
99-
/proj/vs/polymorphic_allocator_test.vcxproj.user
100-
/proj/vs/resource_adaptor.vcxproj.user
101-
/proj/vs/scoped_allocator_adaptor_test.vcxproj.user
102-
/proj/vs/scoped_allocator_usage_test.vcxproj.user
103-
/proj/vs/set_test.vcxproj.user
104-
/proj/vs/slist_test.vcxproj.user
105-
/proj/vs/small_vector_options_test.vcxproj.user
106-
/proj/vs/small_vector_test.vcxproj.user
107-
/proj/vs/stable_vector_test.vcxproj.user
108-
/proj/vs/static_vector_options_test.vcxproj.user
109-
/proj/vs/static_vector_test.vcxproj.user
110-
/proj/vs/string_test.vcxproj.user
111-
/proj/vs/string_view_compat_test.vcxproj.user
112-
/proj/vs/synchronized_pool_resource_test.vcxproj.user
113-
/proj/vs/throw_exception_test.vcxproj.user
114-
/proj/vs/tree_test.vcxproj.user
115-
/proj/vs/unsynchronized_pool_resource_test.vcxproj.user
116-
/proj/vs/uses_allocator_test.vcxproj.user
117-
/proj/vs/vector_options_test.vcxproj.user
118-
/proj/vs/vector_test.vcxproj.user
5+
/proj/
1196
/doc/html
1207
/doc/autodoc.xml
121-
/proj/vs/deque_test.vcxproj
122-
/proj/vs/stable_vector_test.vcxproj
8+
/bench/bench_hash_common.hpp
9+
/bench/bench_hash_map_test.cpp.disabled
10+
/bench/bench_hash_string.cpp.disabled
11+
/bench/bench_hash_uint32.cpp.disabled
12+
/bench/bench_hash_uint64.cpp.disabled
13+
/bench/fca_simple_unordered.hpp
14+
/bench/fca_unordered.hpp
15+
/bench/fxa_common.hpp
16+
/bench/hash_map.hpp
17+
/bench/hash_set.hpp
18+
/bench/detail/hash_table.hpp

include/boost/container/allocator_traits.hpp

Lines changed: 142 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
#include <boost/container/detail/mpl.hpp>
3333
#include <boost/container/detail/type_traits.hpp> //is_empty
3434
#include <boost/container/detail/placement_new.hpp>
35+
#include <boost/container/detail/is_pair.hpp>
36+
#include <boost/container/detail/addressof.hpp>
3537
#ifndef BOOST_CONTAINER_DETAIL_STD_FWD_HPP
3638
#include <boost/container/detail/std_fwd.hpp>
3739
#endif
@@ -81,6 +83,144 @@
8183

8284
namespace boost {
8385
namespace container {
86+
namespace dtl {
87+
88+
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
89+
90+
template<class T, class ...Args>
91+
BOOST_CONTAINER_FORCEINLINE void construct_type(T *p, BOOST_FWD_REF(Args) ...args)
92+
{
93+
::new((void*)p, boost_container_new_t()) T(::boost::forward<Args>(args)...);
94+
}
95+
96+
template < class Pair, class KeyType, class ... Args>
97+
typename dtl::enable_if< dtl::is_pair<Pair>, void >::type
98+
construct_type
99+
(Pair* p, try_emplace_t, BOOST_FWD_REF(KeyType) k, BOOST_FWD_REF(Args) ...args)
100+
{
101+
construct_type(dtl::addressof(p->first), ::boost::forward<KeyType>(k));
102+
BOOST_CONTAINER_TRY{
103+
construct_type(dtl::addressof(p->second), ::boost::forward<Args>(args)...);
104+
}
105+
BOOST_CONTAINER_CATCH(...) {
106+
typedef typename Pair::first_type first_type;
107+
dtl::addressof(p->first)->~first_type();
108+
BOOST_CONTAINER_RETHROW
109+
}
110+
BOOST_CONTAINER_CATCH_END
111+
}
112+
113+
#else
114+
115+
#define BOOST_CONTAINER_ALLOCATOR_TRAITS_CONSTRUCT_TYPEJ(N) \
116+
template<class T BOOST_MOVE_I##N BOOST_MOVE_CLASS##N>\
117+
BOOST_CONTAINER_FORCEINLINE \
118+
typename dtl::disable_if_c<dtl::is_pair<T>::value, void >::type \
119+
construct_type(T *p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\
120+
{\
121+
::new((void*)p, boost_container_new_t()) T( BOOST_MOVE_FWD##N );\
122+
}\
123+
//
124+
BOOST_MOVE_ITERATE_0TO8(BOOST_CONTAINER_ALLOCATOR_TRAITS_CONSTRUCT_TYPEJ)
125+
#undef BOOST_CONTAINER_ALLOCATOR_TRAITS_CONSTRUCT_TYPEJ
126+
127+
#define BOOST_CONTAINER_ALLOCATOR_TRAITS_CONSTRUCT_TYPE(N) \
128+
template < class Pair, class KeyType BOOST_MOVE_I##N BOOST_MOVE_CLASS##N>\
129+
typename dtl::enable_if< dtl::is_pair<Pair>, void >::type construct_type\
130+
(Pair* p, try_emplace_t, BOOST_FWD_REF(KeyType) k BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\
131+
{\
132+
construct_type(dtl::addressof(p->first), ::boost::forward<KeyType>(k));\
133+
BOOST_CONTAINER_TRY{\
134+
construct_type(dtl::addressof(p->second) BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\
135+
}\
136+
BOOST_CONTAINER_CATCH(...) {\
137+
typedef typename Pair::first_type first_type;\
138+
dtl::addressof(p->first)->~first_type();\
139+
BOOST_CONTAINER_RETHROW\
140+
}\
141+
BOOST_CONTAINER_CATCH_END\
142+
}\
143+
//
144+
BOOST_MOVE_ITERATE_0TO8(BOOST_CONTAINER_ALLOCATOR_TRAITS_CONSTRUCT_TYPE)
145+
#undef BOOST_CONTAINER_ALLOCATOR_TRAITS_CONSTRUCT_TYPE
146+
147+
#endif
148+
149+
template<class T>
150+
inline
151+
typename dtl::enable_if<dtl::is_pair<T>, void >::type
152+
construct_type(T* p)
153+
{
154+
dtl::construct_type(dtl::addressof(p->first));
155+
BOOST_CONTAINER_TRY{
156+
dtl::construct_type(dtl::addressof(p->second));
157+
}
158+
BOOST_CONTAINER_CATCH(...) {
159+
typedef typename T::first_type first_type;
160+
dtl::addressof(p->first)->~first_type();
161+
BOOST_CONTAINER_RETHROW
162+
}
163+
BOOST_CONTAINER_CATCH_END
164+
}
165+
166+
167+
template<class T, class U>
168+
inline
169+
typename dtl::enable_if_c
170+
< dtl::is_pair<T>::value
171+
, void >::type
172+
construct_type(T* p, U &u)
173+
{
174+
dtl::construct_type(dtl::addressof(p->first), u.first);
175+
BOOST_CONTAINER_TRY{
176+
dtl::construct_type(dtl::addressof(p->second), u.second);
177+
}
178+
BOOST_CONTAINER_CATCH(...) {
179+
typedef typename T::first_type first_type;
180+
dtl::addressof(p->first)->~first_type();
181+
BOOST_CONTAINER_RETHROW
182+
}
183+
BOOST_CONTAINER_CATCH_END
184+
}
185+
186+
template<class T, class U>
187+
inline
188+
typename dtl::enable_if_c
189+
< dtl::is_pair<typename dtl::remove_reference<T>::type>::value &&
190+
!boost::move_detail::is_reference<U>::value //This is needed for MSVC10 and ambiguous overloads
191+
, void >::type
192+
construct_type(T* p, BOOST_RV_REF(U) u)
193+
{
194+
dtl::construct_type(dtl::addressof(p->first), ::boost::move(u.first));
195+
BOOST_CONTAINER_TRY{
196+
dtl::construct_type(dtl::addressof(p->second), ::boost::move(u.second));
197+
}
198+
BOOST_CONTAINER_CATCH(...) {
199+
typedef typename T::first_type first_type;
200+
dtl::addressof(p->first)->~first_type();
201+
BOOST_CONTAINER_RETHROW
202+
}
203+
BOOST_CONTAINER_CATCH_END
204+
}
205+
206+
template<class T, class U, class V>
207+
inline
208+
typename dtl::enable_if<dtl::is_pair<T>, void >::type
209+
construct_type(T* p, BOOST_FWD_REF(U) x, BOOST_FWD_REF(V) y)
210+
{
211+
dtl::construct_type(dtl::addressof(p->first), ::boost::forward<U>(x));
212+
BOOST_CONTAINER_TRY{
213+
dtl::construct_type(dtl::addressof(p->second), ::boost::forward<V>(y));
214+
}
215+
BOOST_CONTAINER_CATCH(...) {
216+
typedef typename T::first_type first_type;
217+
dtl::addressof(p->first)->~first_type();
218+
BOOST_CONTAINER_RETHROW
219+
}
220+
BOOST_CONTAINER_CATCH_END
221+
}
222+
223+
} //namespace dtl
84224

85225
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
86226

@@ -419,7 +559,7 @@ struct allocator_traits
419559

420560
template<class T, class ...Args>
421561
inline static void priv_construct(dtl::false_type, Allocator &, T *p, BOOST_FWD_REF(Args) ...args)
422-
{ ::new((void*)p, boost_container_new_t()) T(::boost::forward<Args>(args)...); }
562+
{ dtl::construct_type(p, ::boost::forward<Args>(args)...); }
423563
#else // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
424564
public:
425565

@@ -450,7 +590,7 @@ struct allocator_traits
450590
\
451591
template<class T BOOST_MOVE_I##N BOOST_MOVE_CLASS##N >\
452592
inline static void priv_construct(dtl::false_type, Allocator &, T *p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\
453-
{ ::new((void*)p, boost_container_new_t()) T(BOOST_MOVE_FWD##N); }\
593+
{ dtl::construct_type(p BOOST_MOVE_I##N BOOST_MOVE_FWD##N); }\
454594
//
455595
BOOST_MOVE_ITERATE_0TO8(BOOST_CONTAINER_ALLOCATOR_TRAITS_PRIV_CONSTRUCT_IMPL)
456596
#undef BOOST_CONTAINER_ALLOCATOR_TRAITS_PRIV_CONSTRUCT_IMPL

include/boost/container/detail/construct_in_place.hpp

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <boost/container/allocator_traits.hpp>
2525
#include <boost/container/detail/iterators.hpp>
2626
#include <boost/container/detail/value_init.hpp>
27+
#include <boost/container/detail/is_pair.hpp>
2728

2829
namespace boost {
2930
namespace container {
@@ -62,9 +63,42 @@ BOOST_CONTAINER_FORCEINLINE void construct_in_place(Allocator &a, T *dest, empla
6263

6364
//Assignment
6465

66+
template<class T, class U>
67+
BOOST_CONTAINER_FORCEINLINE
68+
typename dtl::disable_if_c
69+
< dtl::is_pair<typename dtl::remove_reference<T>::type>::value
70+
&& dtl::is_pair<typename dtl::remove_reference<U>::type>::value
71+
, void>::type
72+
assign_in_place_ref(T &t, BOOST_FWD_REF(U) u)
73+
{ t = ::boost::forward<U>(u); }
74+
75+
template<class T, class U>
76+
BOOST_CONTAINER_FORCEINLINE
77+
typename dtl::enable_if_c
78+
< dtl::is_pair<typename dtl::remove_reference<T>::type>::value
79+
&& dtl::is_pair<typename dtl::remove_reference<U>::type>::value
80+
, void>::type
81+
assign_in_place_ref(T &t, const U &u)
82+
{
83+
assign_in_place_ref(t.first, u.first);
84+
assign_in_place_ref(t.second, u.second);
85+
}
86+
87+
template<class T, class U>
88+
BOOST_CONTAINER_FORCEINLINE
89+
typename dtl::enable_if_c
90+
< dtl::is_pair<typename dtl::remove_reference<T>::type>::value
91+
&& dtl::is_pair<typename dtl::remove_reference<U>::type>::value
92+
, void>::type
93+
assign_in_place_ref(T &t, BOOST_RV_REF(U) u)
94+
{
95+
assign_in_place_ref(t.first, ::boost::move(u.first));
96+
assign_in_place_ref(t.second, ::boost::move(u.second));
97+
}
98+
6599
template<class DstIt, class InpIt>
66100
BOOST_CONTAINER_FORCEINLINE void assign_in_place(DstIt dest, InpIt source)
67-
{ *dest = *source; }
101+
{ assign_in_place_ref(*dest, *source); }
68102

69103
template<class DstIt, class U>
70104
BOOST_CONTAINER_FORCEINLINE void assign_in_place(DstIt dest, value_init_construct_iterator<U>)

0 commit comments

Comments
 (0)