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::max() / 2) { - return __m - __alignment; + if (size_type __m = __alloc_traits::max_size(__alloc()); __m <= std::numeric_limits::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 - // // 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 - // // 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 - // // basic_string&