Skip to content

Conversation

philnik777
Copy link
Contributor

No description provided.

@philnik777 philnik777 requested a review from a team as a code owner September 4, 2025 08:25
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Sep 4, 2025
@llvmbot
Copy link
Member

llvmbot commented Sep 4, 2025

@llvm/pr-subscribers-libcxx

Author: Nikolas Klauser (philnik777)

Changes

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

4 Files Affected:

  • (modified) libcxx/include/__cxx03/string (+15-7)
  • (modified) libcxx/test/libcxx-03/strings/basic.string/string.capacity/max_size.pass.cpp (-2)
  • (modified) libcxx/test/std/strings/basic.string/string.capacity/max_size.pass.cpp (-2)
  • (modified) libcxx/test/std/strings/basic.string/string.modifiers/string_append/pointer_size.pass.cpp (-2)
diff --git a/libcxx/include/__cxx03/string b/libcxx/include/__cxx03/string
index 7d54030d0b660..178140486105e 100644
--- a/libcxx/include/__cxx03/string
+++ b/libcxx/include/__cxx03/string
@@ -1101,12 +1101,20 @@ public:
   _LIBCPP_HIDE_FROM_ABI size_type length() const _NOEXCEPT { return size(); }
 
   _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT {
-    size_type __m = __alloc_traits::max_size(__alloc());
-    if (__m <= std::numeric_limits<size_type>::max() / 2) {
-      return __m - __alignment;
+    if (size_type __m = __alloc_traits::max_size(__alloc()); __m <= std::numeric_limits<size_type>::max() / 2) {
+      size_type __res = __m - __alignment;
+
+      // When the __endian_factor == 2, our string representation assumes that the capacity
+      // (including the null terminator) is always even, so we have to make sure the lowest bit isn't set when the
+      // string grows to max_size()
+      if (__endian_factor == 2)
+        __res &= ~size_type(1);
+
+      // We have to allocate space for the null terminator, but max_size() doesn't include it.
+      return __res - 1;
     } else {
       bool __uses_lsb = __endian_factor == 2;
-      return __uses_lsb ? __m - __alignment : (__m / 2) - __alignment;
+      return __uses_lsb ? __m - __alignment - 1 : (__m / 2) - __alignment - 1;
     }
   }
 
@@ -1970,11 +1978,11 @@ void basic_string<_CharT, _Traits, _Allocator>::__grow_by_and_replace(
     size_type __n_add,
     const value_type* __p_new_stuff) {
   size_type __ms = max_size();
-  if (__delta_cap > __ms - __old_cap - 1)
+  if (__delta_cap > __ms - __old_cap)
     __throw_length_error();
   pointer __old_p = __get_pointer();
   size_type __cap =
-      __old_cap < __ms / 2 - __alignment ? __recommend(std::max(__old_cap + __delta_cap, 2 * __old_cap)) : __ms - 1;
+      __old_cap < __ms / 2 - __alignment ? __recommend(std::max(__old_cap + __delta_cap, 2 * __old_cap)) : __ms;
   __annotate_delete();
   auto __allocation = std::__allocate_at_least(__alloc(), __cap + 1);
   pointer __p       = __allocation.ptr;
@@ -2017,7 +2025,7 @@ void
     __throw_length_error();
   pointer __old_p = __get_pointer();
   size_type __cap =
-      __old_cap < __ms / 2 - __alignment ? __recommend(std::max(__old_cap + __delta_cap, 2 * __old_cap)) : __ms - 1;
+      __old_cap < __ms / 2 - __alignment ? __recommend(std::max(__old_cap + __delta_cap, 2 * __old_cap)) : __ms;
   __annotate_delete();
   auto __allocation = std::__allocate_at_least(__alloc(), __cap + 1);
   pointer __p       = __allocation.ptr;
diff --git a/libcxx/test/libcxx-03/strings/basic.string/string.capacity/max_size.pass.cpp b/libcxx/test/libcxx-03/strings/basic.string/string.capacity/max_size.pass.cpp
index 7b3f81e21d8a8..6bfcb5d4bfcd8 100644
--- a/libcxx/test/libcxx-03/strings/basic.string/string.capacity/max_size.pass.cpp
+++ b/libcxx/test/libcxx-03/strings/basic.string/string.capacity/max_size.pass.cpp
@@ -6,8 +6,6 @@
 //
 //===----------------------------------------------------------------------===//
 
-// XFAIL: FROZEN-CXX03-HEADERS-FIXME
-
 // <string>
 
 // This test ensures that the correct max_size() is returned depending on the platform.
diff --git a/libcxx/test/std/strings/basic.string/string.capacity/max_size.pass.cpp b/libcxx/test/std/strings/basic.string/string.capacity/max_size.pass.cpp
index ac660d8fe9941..45a52acab464e 100644
--- a/libcxx/test/std/strings/basic.string/string.capacity/max_size.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.capacity/max_size.pass.cpp
@@ -8,8 +8,6 @@
 
 // UNSUPPORTED: no-exceptions
 
-// XFAIL: FROZEN-CXX03-HEADERS-FIXME
-
 // <string>
 
 // size_type max_size() const; // constexpr since C++20
diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_append/pointer_size.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_append/pointer_size.pass.cpp
index 425a481b71639..8a13f11cf156f 100644
--- a/libcxx/test/std/strings/basic.string/string.modifiers/string_append/pointer_size.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_append/pointer_size.pass.cpp
@@ -6,8 +6,6 @@
 //
 //===----------------------------------------------------------------------===//
 
-// XFAIL: FROZEN-CXX03-HEADERS-FIXME
-
 // <string>
 
 // basic_string<charT,traits,Allocator>&

@philnik777 philnik777 changed the title [libc++][C++03] Cherry-pick #125423 [libc++][C++03] cherry-pick #125423 Sep 4, 2025
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 but CI is broken (edit: it doesn't seem related to this patch)

@ldionne ldionne merged commit 2e6685c into llvm:main Sep 5, 2025
70 of 80 checks passed
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.

3 participants