[libcxx-commits] [libcxx] [libc++] Fix basic_string not allowing max_size() elements to be stored (PR #125423)

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Thu Feb 20 07:20:05 PST 2025


================
@@ -1302,10 +1302,10 @@ public:
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 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;
+      return ((__m - __alignment) & ~size_type(__endian_factor - 1)) - 1;
----------------
ldionne wrote:

Here's the little table I did for my understanding:
```
endian factor = 1
-----------------
factor-1 = 0000000000000000000000
~        = 1111111111111111111111
m-align  = xxxxxxxxxxxxxxxxxxxxxx
&        = xxxxxxxxxxxxxxxxxxxxxx
So the result is unchanged

endian factor = 2
-----------------
factor-1 = 0000000000000000000001
~        = 1111111111111111111110
m-align  = xxxxxxxxxxxxxxxxxxxxxx
&        = xxxxxxxxxxxxxxxxxxxxx0
So the bitand is always even, and the end result is always odd because we subtract 1
```

Since `__endian_factor` is a compile-time constant we should be able to rewrite like this without impacting codegen (IMO this is easier to follow):

```c++
if (__m <= std::numeric_limits<size_type>::max() / 2) {
  size_type __res = __m - __alignment;
  if (__endian_factor == 2)
    __res &= ~size_type(1); // make even, explain why in a short comment
  __res -= 1; // max_size() doesn't include the null terminator
}
```

WDYT?

https://github.com/llvm/llvm-project/pull/125423


More information about the libcxx-commits mailing list