From ba38951fea24d1fe121b01759b9e8a3989477595 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Tue, 5 Dec 2023 09:57:07 -0500 Subject: [PATCH] [libc++] Use __wrap_iter in string_view and array in the unstable ABI std::string_view and std::array iterators don't have to be raw pointers, and in fact other implementations don't represent them as raw pointers. Them being raw pointers in libc++ makes it easier for users to write non-portable code. This is bad in itself, but this is even worse when considering efforts like hardening where we want an easy ability to swap for a different iterator type. If users depend on iterators being raw pointers, this becomes a build break. Hence, this patch enables the use of __wrap_iter in the unstable ABI, creating a long term path towards making this the default. This patch may break code that assumes these iterators are raw pointers for people compiling with the unstable ABI. --- libcxx/include/__config | 6 ++++++ libcxx/include/__iterator/wrap_iter.h | 4 ++++ libcxx/include/array | 22 ++++++++++++++-------- libcxx/include/string_view | 11 +++++++---- 4 files changed, 31 insertions(+), 12 deletions(-) diff --git a/libcxx/include/__config b/libcxx/include/__config index 8d4d17378b2973..3a438e85a7b819 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -174,6 +174,12 @@ // The implementation moved to the header, but we still export the symbols from // the dylib for backwards compatibility. # define _LIBCPP_ABI_DO_NOT_EXPORT_TO_CHARS_BASE_10 +// Define std::array/std::string_view iterators to be __wrap_iters instead of raw +// pointers, which prevents people from relying on a non-portable implementation +// detail. This is especially useful because enabling bounded iterators hardening +// requires code not to make these assumptions. +# define _LIBCPP_ABI_USE_WRAP_ITER_IN_STD_ARRAY +# define _LIBCPP_ABI_USE_WRAP_ITER_IN_STD_STRING_VIEW # elif _LIBCPP_ABI_VERSION == 1 # if !(defined(_LIBCPP_OBJECT_FORMAT_COFF) || defined(_LIBCPP_OBJECT_FORMAT_XCOFF)) // Enable compiling copies of now inline methods into the dylib to support diff --git a/libcxx/include/__iterator/wrap_iter.h b/libcxx/include/__iterator/wrap_iter.h index 3827241e5fe476..3124826189ad7c 100644 --- a/libcxx/include/__iterator/wrap_iter.h +++ b/libcxx/include/__iterator/wrap_iter.h @@ -97,10 +97,14 @@ class __wrap_iter { friend class __wrap_iter; template friend class basic_string; + template + friend class basic_string_view; template friend class _LIBCPP_TEMPLATE_VIS vector; template friend class _LIBCPP_TEMPLATE_VIS span; + template + friend struct array; }; template diff --git a/libcxx/include/array b/libcxx/include/array index 961b620efb9357..7fa5dc1479349e 100644 --- a/libcxx/include/array +++ b/libcxx/include/array @@ -120,6 +120,7 @@ template const T&& get(const array&&) noexce #include <__config> #include <__fwd/array.h> #include <__iterator/reverse_iterator.h> +#include <__iterator/wrap_iter.h> #include <__tuple/sfinae_helpers.h> #include <__type_traits/conditional.h> #include <__type_traits/is_array.h> @@ -167,14 +168,19 @@ _LIBCPP_BEGIN_NAMESPACE_STD template struct _LIBCPP_TEMPLATE_VIS array { // types: - using __self = array; - using value_type = _Tp; - using reference = value_type&; - using const_reference = const value_type&; - using iterator = value_type*; - using const_iterator = const value_type*; - using pointer = value_type*; - using const_pointer = const value_type*; + using __self = array; + using value_type = _Tp; + using reference = value_type&; + using const_reference = const value_type&; + using pointer = value_type*; + using const_pointer = const value_type*; +#if defined(_LIBCPP_ABI_USE_WRAP_ITER_IN_STD_ARRAY) + using iterator = __wrap_iter; + using const_iterator = __wrap_iter; +#else + using iterator = pointer; + using const_iterator = const_pointer; +#endif using size_type = size_t; using difference_type = ptrdiff_t; using reverse_iterator = std::reverse_iterator; diff --git a/libcxx/include/string_view b/libcxx/include/string_view index 48bbcd80021670..e0dd5c5b19ace0 100644 --- a/libcxx/include/string_view +++ b/libcxx/include/string_view @@ -215,6 +215,7 @@ namespace std { #include <__iterator/concepts.h> #include <__iterator/iterator_traits.h> #include <__iterator/reverse_iterator.h> +#include <__iterator/wrap_iter.h> #include <__memory/pointer_traits.h> #include <__ranges/concepts.h> #include <__ranges/data.h> @@ -278,10 +279,12 @@ public: using const_pointer = const _CharT*; using reference = _CharT&; using const_reference = const _CharT&; -#ifdef _LIBCPP_ABI_BOUNDED_ITERATORS +#if defined(_LIBCPP_ABI_BOUNDED_ITERATORS) using const_iterator = __bounded_iter; +#elif defined(_LIBCPP_ABI_USE_WRAP_ITER_IN_STD_STRING_VIEW) + using const_iterator = __wrap_iter; #else - using const_iterator = const_pointer; // See [string.view.iterators] + using const_iterator = const_pointer; #endif using iterator = const_iterator; using const_reverse_iterator = std::reverse_iterator; @@ -353,7 +356,7 @@ public: #ifdef _LIBCPP_ABI_BOUNDED_ITERATORS return std::__make_bounded_iter(data(), data(), data() + size()); #else - return __data_; + return const_iterator(__data_); #endif } @@ -361,7 +364,7 @@ public: #ifdef _LIBCPP_ABI_BOUNDED_ITERATORS return std::__make_bounded_iter(data() + size(), data(), data() + size()); #else - return __data_ + __size_; + return const_iterator(__data_ + __size_); #endif }