From dbb6ef424f6b6dd66a59176bb1205a0d6aacaf6f Mon Sep 17 00:00:00 2001 From: "code@jendruk.com" Date: Tue, 7 May 2019 12:06:05 +0200 Subject: [PATCH] Fix any_range with non-reference references can cause UB --- .../range/detail/any_iterator_interface.hpp | 26 ++++---- test/Jamfile.v2 | 1 + test/adaptor_test/type_erased_transformed.cpp | 66 +++++++++++++++++++ 3 files changed, 80 insertions(+), 13 deletions(-) create mode 100644 test/adaptor_test/type_erased_transformed.cpp diff --git a/include/boost/range/detail/any_iterator_interface.hpp b/include/boost/range/detail/any_iterator_interface.hpp index cd56714..9310038 100644 --- a/include/boost/range/detail/any_iterator_interface.hpp +++ b/include/boost/range/detail/any_iterator_interface.hpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -35,15 +36,18 @@ namespace boost }; template - struct mutable_reference_type_generator + struct reference_as_value_type_generator { typedef typename mpl::if_< - typename mpl::and_< - typename is_const::type, - typename mpl::not_::type>::type + typename is_copy_constructible< + typename remove_const< + typename remove_reference::type + >::type >::type, - T, - typename add_reference::type + typename remove_const< + typename remove_reference::type + >::type, + T >::type type; }; @@ -53,16 +57,12 @@ namespace boost > struct any_incrementable_iterator_interface { - typedef typename mutable_reference_type_generator< - Reference - >::type reference; - + typedef Reference reference; typedef typename const_reference_type_generator< Reference >::type const_reference; - - typedef typename remove_const< - typename remove_reference::type + typedef typename reference_as_value_type_generator< + Reference >::type reference_as_value_type; typedef Buffer buffer_type; diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index b195926..cd2774e 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -81,6 +81,7 @@ test-suite range : [ range-test adaptor_test/type_erased_forward ] [ range-test adaptor_test/type_erased_bidirectional ] [ range-test adaptor_test/type_erased_random_access ] + [ range-test adaptor_test/type_erased_transformed ] [ range-test adaptor_test/uniqued ] [ range-test adaptor_test/adjacent_filtered_example ] [ range-test adaptor_test/copied_example ] diff --git a/test/adaptor_test/type_erased_transformed.cpp b/test/adaptor_test/type_erased_transformed.cpp new file mode 100644 index 0000000..936d432 --- /dev/null +++ b/test/adaptor_test/type_erased_transformed.cpp @@ -0,0 +1,66 @@ +// Boost.Range library +// +// Copyright Neil Groves 2014. Use, modification and +// distribution is subject to the Boost Software License, Version +// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +#include +#include +#include +#include "type_erased_test.hpp" + +#include + +#include + +namespace boost_range_adaptor_type_erased_test +{ + namespace + { + +typedef boost::any_range< + int, + boost::random_access_traversal_tag, + int, + std::ptrdiff_t +> any_integer_value_range; + +struct get_fn +{ + boost::int32_t operator()(const MockType& val) const + { + return val.get(); + } +}; + +int accumulate_any_integer_value_range(any_integer_value_range rng) +{ + return boost::accumulate(rng, 0); +} + +void test_type_erased_transformed() +{ + std::vector v{1,2,3,4,5}; + + const int sum = accumulate_any_integer_value_range( + v | boost::adaptors::transformed(get_fn())); + + BOOST_CHECK_EQUAL(15, sum); +} + + } // anonymous namespace +} // namespace boost_range_adaptor_type_erased_test + +boost::unit_test::test_suite* +init_unit_test_suite(int, char*[]) +{ + boost::unit_test::test_suite* test + = BOOST_TEST_SUITE("RangeTestSuite.adaptor.type_erased_transformed"); + + test->add( + BOOST_TEST_CASE( + &boost_range_adaptor_type_erased_test::test_type_erased_transformed)); + + return test; +}