[libcxx] Align `__recommend() + 1` by __endian_factor (#90292)release/18.xllvmorg-18.1.8
commit3b5b5c1ec4a3095ab096dd780e84d7ab81f3d7ff
authorVitaly Buka <vitalybuka@google.com>
Thu, 2 May 2024 21:26:38 +0000 (2 14:26 -0700)
committerllvmbot <60944935+llvmbot@users.noreply.github.com>
Sat, 15 Jun 2024 17:21:32 +0000 (15 10:21 -0700)
tree157e69d5386f911eaba3ed8b03abccadb65cdf38
parent72c9425a79fda8e9001fcde091e8703f9fb2a43a
[libcxx] Align `__recommend() + 1`  by __endian_factor (#90292)

This is detected by asan after #83774

Allocation size will be divided by `__endian_factor` before storing. If
it's not aligned,
we will not be able to recover allocation size to pass into
`__alloc_traits::deallocate`.

we have code like this
```
 auto __allocation = std::__allocate_at_least(__alloc(), __recommend(__sz) + 1);
    __p               = __allocation.ptr;
    __set_long_cap(__allocation.count);

void __set_long_cap(size_type __s) _NOEXCEPT {
    __r_.first().__l.__cap_     = __s / __endian_factor;
    __r_.first().__l.__is_long_ = true;
  }

size_type __get_long_cap() const _NOEXCEPT {
    return __r_.first().__l.__cap_ * __endian_factor;
  }

inline ~basic_string() {
    __annotate_delete();
    if (__is_long())
      __alloc_traits::deallocate(__alloc(), __get_long_pointer(), __get_long_cap());
  }
```
1. __recommend() -> even size
2. `std::__allocate_at_least(__alloc(), __recommend(__sz) + 1)` - > not
even size
3. ` __set_long_cap() `- > lose one bit of size for __endian_factor == 2
(see `/ __endian_factor`)
4. `__alloc_traits::deallocate(__alloc(), __get_long_pointer(),
__get_long_cap())` -> uses even size (see `__get_long_cap`)

(cherry picked from commit d129ea8d2fa347e63deec0791faf389b84f20ce1)
libcxx/include/string