diff options
author | Vitaly Buka <vitalybuka@google.com> | 2024-05-02 14:26:38 -0700 |
---|---|---|
committer | llvmbot <60944935+llvmbot@users.noreply.github.com> | 2024-06-15 10:21:32 -0700 |
commit | 3b5b5c1ec4a3095ab096dd780e84d7ab81f3d7ff (patch) | |
tree | 157e69d5386f911eaba3ed8b03abccadb65cdf38 | |
parent | 72c9425a79fda8e9001fcde091e8703f9fb2a43a (diff) | |
download | llvm-release/18.x.zip llvm-release/18.x.tar.gz llvm-release/18.x.tar.bz2 |
[libcxx] Align `__recommend() + 1` by __endian_factor (#90292)llvmorg-18.1.8release/18.x
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)
-rw-r--r-- | libcxx/include/string | 4 |
1 files changed, 2 insertions, 2 deletions
diff --git a/libcxx/include/string b/libcxx/include/string index 618ceb7..56e2ef0 100644 --- a/libcxx/include/string +++ b/libcxx/include/string @@ -1943,10 +1943,10 @@ private: if (__s < __min_cap) { return static_cast<size_type>(__min_cap) - 1; } - const size_type __boundary = sizeof(value_type) < __alignment ? __alignment / sizeof(value_type) : 1; + const size_type __boundary = sizeof(value_type) < __alignment ? __alignment / sizeof(value_type) : __endian_factor; size_type __guess = __align_it<__boundary>(__s + 1) - 1; if (__guess == __min_cap) - ++__guess; + __guess += __endian_factor; return __guess; } |