[libcxx-commits] [libcxx] [libc++] Add a few _LIBCPP_ASSERT_INTERNALs to make sure internal invariants are kept (PR #114575)

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Fri Nov 1 10:06:40 PDT 2024


https://github.com/philnik777 created https://github.com/llvm/llvm-project/pull/114575

This can make it significanly easier to find bugs when working on string.


>From 28ce387e3e928973db865511accfb356facfddc4 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Fri, 1 Nov 2024 17:53:09 +0100
Subject: [PATCH] [libc++] Add a few _LIBCPP_ASSERT_INTERNALs to make sure
 internal invariants are kept

---
 libcxx/include/__utility/is_pointer_in_range.h |  6 ++++++
 libcxx/include/string                          | 11 +++++++++++
 2 files changed, 17 insertions(+)

diff --git a/libcxx/include/__utility/is_pointer_in_range.h b/libcxx/include/__utility/is_pointer_in_range.h
index 4130b4ac707000..efee11bfe55519 100644
--- a/libcxx/include/__utility/is_pointer_in_range.h
+++ b/libcxx/include/__utility/is_pointer_in_range.h
@@ -57,6 +57,12 @@ __is_pointer_in_range(const _Tp* __begin, const _Tp* __end, const _Up* __ptr) {
          reinterpret_cast<const char*>(__ptr) < reinterpret_cast<const char*>(__end);
 }
 
+template <class _Tp, class _Up>
+_LIBCPP_CONSTEXPR_SINCE_CXX14 bool __is_overlapping_range(const _Tp* __begin, const _Tp* __end, const _Up* __begin2) {
+  return std::__is_pointer_in_range(__begin, __end, __begin2) ||
+         std::__is_pointer_in_range(__begin2, __begin2 + (__end - __begin), __begin);
+}
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // _LIBCPP___UTILITY_IS_POINTER_IN_RANGE_H
diff --git a/libcxx/include/string b/libcxx/include/string
index 4b5017f5e7753f..20e44eaca2ac7a 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -1912,6 +1912,9 @@ private:
 #ifndef _LIBCPP_CXX03_LANG
     if constexpr (__libcpp_is_contiguous_iterator<_ForwardIter>::value &&
                   is_same<value_type, __iter_value_type<_ForwardIter>>::value && is_same<_ForwardIter, _Sent>::value) {
+      _LIBCPP_ASSERT_INTERNAL(
+          !std::__is_overlapping_range(std::__to_address(__first), std::__to_address(__last), __dest),
+          "__copy_non_overlapping_range called with an overlapping range!");
       traits_type::copy(__dest, std::__to_address(__first), __last - __first);
       return __dest + (__last - __first);
     }
@@ -1966,9 +1969,12 @@ private:
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __set_long_size(size_type __s) _NOEXCEPT {
     __rep_.__l.__size_ = __s;
   }
+
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type __get_long_size() const _NOEXCEPT {
+    _LIBCPP_ASSERT_INTERNAL(__rep_.__l.__is_long_, "String has to be long when trying to get the long size");
     return __rep_.__l.__size_;
   }
+
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __set_size(size_type __s) _NOEXCEPT {
     if (__is_long())
       __set_long_size(__s);
@@ -1977,11 +1983,13 @@ private:
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __set_long_cap(size_type __s) _NOEXCEPT {
+    _LIBCPP_ASSERT_INTERNAL(!__fits_in_sso(__s), "Long capacity should always be larger than the SSO");
     __rep_.__l.__cap_     = __s / __endian_factor;
     __rep_.__l.__is_long_ = true;
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type __get_long_cap() const _NOEXCEPT {
+    _LIBCPP_ASSERT_INTERNAL(__rep_.__l.__is_long_, "String has to be long when trying to get the long capacity");
     return __rep_.__l.__cap_ * __endian_factor;
   }
 
@@ -1990,10 +1998,12 @@ private:
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pointer __get_long_pointer() _NOEXCEPT {
+    _LIBCPP_ASSERT_INTERNAL(__rep_.__l.__is_long_, "String has to be long when trying to get the long pointer");
     return _LIBCPP_ASAN_VOLATILE_WRAPPER(__rep_.__l.__data_);
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_pointer __get_long_pointer() const _NOEXCEPT {
+    _LIBCPP_ASSERT_INTERNAL(__rep_.__l.__is_long_, "String has to be long when trying to get the long pointer");
     return _LIBCPP_ASAN_VOLATILE_WRAPPER(__rep_.__l.__data_);
   }
 
@@ -2137,6 +2147,7 @@ private:
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_NOINLINE basic_string& __assign_no_alias(const value_type* __s, size_type __n);
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __erase_to_end(size_type __pos) {
+    _LIBCPP_ASSERT_INTERNAL(__pos <= capacity(), "Trying to erase at position outside the strings capacity!");
     __null_terminate_at(std::__to_address(__get_pointer()), __pos);
   }
 



More information about the libcxx-commits mailing list