[libcxx-commits] [libcxx] Suppress a redundant hardening check in basic_string_view::substr (PR #91804)

Konstantin Varlamov via libcxx-commits libcxx-commits at lists.llvm.org
Mon Jul 22 17:45:55 PDT 2024


https://github.com/var-const updated https://github.com/llvm/llvm-project/pull/91804

>From f71a3d95657673fa0353b955dc20dca000c16ea7 Mon Sep 17 00:00:00 2001
From: David Benjamin <davidben at google.com>
Date: Fri, 10 May 2024 16:31:11 -0400
Subject: [PATCH 1/3] Suppress a redundant hardening check in
 basic_string_view::substr

Fixes #91634.

This could alternatively be done with an _LIBCPP_ASSUME, after
https://github.com/llvm/llvm-project/pull/91801 lands, but would also
require https://github.com/llvm/llvm-project/issues/91619 be fixed
first. Given the dependencies, it seemed simplest to just make a private
ctor.
---
 libcxx/include/string_view | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/libcxx/include/string_view b/libcxx/include/string_view
index 5c4bec742bafa..2c9703cedfd2a 100644
--- a/libcxx/include/string_view
+++ b/libcxx/include/string_view
@@ -449,8 +449,11 @@ public:
   }
 
   _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI basic_string_view substr(size_type __pos = 0, size_type __n = npos) const {
+    // Use the `__assume_valid` form of the constructor to avoid an unnecessary check. Any substring of a view is a
+    // valid view. In particular, `size()` is known to be smaller than `numeric_limits<difference_type>::max()`, so the
+    // new size is also smaller. See also https://github.com/llvm/llvm-project/issues/91634.
     return __pos > size() ? (__throw_out_of_range("string_view::substr"), basic_string_view())
-                          : basic_string_view(data() + __pos, std::min(__n, size() - __pos));
+                          : basic_string_view(data() + __pos, std::min(__n, size() - __pos), __assume_valid{});
   }
 
   _LIBCPP_CONSTEXPR_SINCE_CXX14 int compare(basic_string_view __sv) const _NOEXCEPT {
@@ -675,6 +678,16 @@ public:
 #endif
 
 private:
+  struct __assume_valid {};
+
+  // This is the same as the pointer and length constructor, but it does not include additionally hardening checks. It
+  // is intended for use within the class, when the class invariants already imply the resulting object is valid. The
+  // compiler usually cannot apply this optimization itself, because it does not know class invariants.
+  _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI
+  basic_string_view(const _CharT* __s, size_type __len, __assume_valid) _NOEXCEPT
+      : __data_(__s),
+        __size_(__len) {}
+
   const value_type* __data_;
   size_type __size_;
 };

>From 350b01e242e7540c7b170920a43294ea51e24fb9 Mon Sep 17 00:00:00 2001
From: Konstantin Varlamov <varconst at apple.com>
Date: Mon, 22 Jul 2024 17:43:13 -0700
Subject: [PATCH 2/3] Slightly tweak a comment

---
 libcxx/include/string_view | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/libcxx/include/string_view b/libcxx/include/string_view
index 2c9703cedfd2a..590271a002bf5 100644
--- a/libcxx/include/string_view
+++ b/libcxx/include/string_view
@@ -680,9 +680,9 @@ public:
 private:
   struct __assume_valid {};
 
-  // This is the same as the pointer and length constructor, but it does not include additionally hardening checks. It
-  // is intended for use within the class, when the class invariants already imply the resulting object is valid. The
-  // compiler usually cannot apply this optimization itself, because it does not know class invariants.
+  // This is the same as the pointer and length constructor, but without the additional hardening checks. It is intended
+  // for use within the class, when the class invariants already guarantee the resulting object is valid. The compiler
+  // usually cannot eliminate the redundant checks because it does not know class invariants.
   _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI
   basic_string_view(const _CharT* __s, size_type __len, __assume_valid) _NOEXCEPT
       : __data_(__s),

>From aafa186173db7e82e2c370ad321cfc7bca0f5db1 Mon Sep 17 00:00:00 2001
From: Konstantin Varlamov <varconst at apple.com>
Date: Mon, 22 Jul 2024 17:44:55 -0700
Subject: [PATCH 3/3] Don't use list initialization to hopefully fix the C++03
 mode

---
 libcxx/include/string_view | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/include/string_view b/libcxx/include/string_view
index 590271a002bf5..2c2898c170986 100644
--- a/libcxx/include/string_view
+++ b/libcxx/include/string_view
@@ -453,7 +453,7 @@ public:
     // valid view. In particular, `size()` is known to be smaller than `numeric_limits<difference_type>::max()`, so the
     // new size is also smaller. See also https://github.com/llvm/llvm-project/issues/91634.
     return __pos > size() ? (__throw_out_of_range("string_view::substr"), basic_string_view())
-                          : basic_string_view(data() + __pos, std::min(__n, size() - __pos), __assume_valid{});
+                          : basic_string_view(data() + __pos, std::min(__n, size() - __pos), __assume_valid());
   }
 
   _LIBCPP_CONSTEXPR_SINCE_CXX14 int compare(basic_string_view __sv) const _NOEXCEPT {



More information about the libcxx-commits mailing list