Skip to content

[libc++] Add a few _LIBCPP_ASSERT_INTERNALs to make sure internal invariants are kept #114575

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 3, 2024

Conversation

philnik777
Copy link
Contributor

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

@philnik777 philnik777 requested a review from a team as a code owner November 1, 2024 17:06
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Nov 1, 2024
@llvmbot
Copy link
Member

llvmbot commented Nov 1, 2024

@llvm/pr-subscribers-libcxx

Author: Nikolas Klauser (philnik777)

Changes

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


Full diff: https://github.com/llvm/llvm-project/pull/114575.diff

2 Files Affected:

  • (modified) libcxx/include/__utility/is_pointer_in_range.h (+6)
  • (modified) libcxx/include/string (+11)
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);
   }
 

Copy link
Member

@ldionne ldionne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with small comments. I like this!

Copy link
Member

@var-const var-const left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

@philnik777 philnik777 merged commit 33af68a into llvm:main Nov 3, 2024
62 checks passed
@philnik777 philnik777 deleted the string_add_asserts branch November 3, 2024 14:58
PhilippRados pushed a commit to PhilippRados/llvm-project that referenced this pull request Nov 6, 2024
…ariants are kept (llvm#114575)

This can make it significanly easier to find bugs when working on
string.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants