[libcxx-commits] [libcxx] [libc++] Use __wrap_iter in string_view and array in the unstable ABI (PR #74482)

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Mon Jan 8 14:06:17 PST 2024


https://github.com/ldionne updated https://github.com/llvm/llvm-project/pull/74482

>From a58530a713c88cc6c2f10f50eb5f14bb2b422a43 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
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 082c73e672c7492..81a712e41b72b40 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -168,6 +168,12 @@
 // pointer from 16 to 8. This changes the output of std::string::max_size,
 // which makes it ABI breaking
 #    define _LIBCPP_ABI_STRING_8_BYTE_ALIGNMENT
+// 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 3827241e5fe4761..3124826189ad7c0 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 <class _CharT, class _Traits, class _Alloc>
   friend class basic_string;
+  template <class _CharT, class _Traits>
+  friend class basic_string_view;
   template <class _Tp, class _Alloc>
   friend class _LIBCPP_TEMPLATE_VIS vector;
   template <class _Tp, size_t>
   friend class _LIBCPP_TEMPLATE_VIS span;
+  template <class _Tp, size_t _Size>
+  friend struct array;
 };
 
 template <class _Iter1>
diff --git a/libcxx/include/array b/libcxx/include/array
index dcb419f536dc503..0e65b683e49dd28 100644
--- a/libcxx/include/array
+++ b/libcxx/include/array
@@ -120,6 +120,7 @@ template <size_t I, class T, size_t N> const T&& get(const array<T, N>&&) 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>
@@ -164,14 +165,19 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 template <class _Tp, size_t _Size>
 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<pointer>;
+  using const_iterator = __wrap_iter<const_pointer>;
+#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<iterator>;
diff --git a/libcxx/include/string_view b/libcxx/include/string_view
index 909224fe7e3d034..ac0869478cda221 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<const_pointer>;
+#elif defined(_LIBCPP_ABI_USE_WRAP_ITER_IN_STD_STRING_VIEW)
+  using const_iterator = __wrap_iter<const_pointer>;
 #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<const_iterator>;
@@ -350,7 +353,7 @@ public:
 #ifdef _LIBCPP_ABI_BOUNDED_ITERATORS
     return std::__make_bounded_iter(data(), data(), data() + size());
 #else
-    return __data_;
+    return const_iterator(__data_);
 #endif
   }
 
@@ -358,7 +361,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
   }
 



More information about the libcxx-commits mailing list