[libcxx-commits] [libcxx] [libc++] Fix the long/short flag position of basic_string for a narrow size_type (PR #236867)

via libcxx-commits libcxx-commits at lists.llvm.org
Fri Oct 30 20:41:34 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

Author: Himadhith

<details>
<summary>Changes</summary>

This patch fixes `basic_string` for allocators with a `size_type` narrower than 4 bytes under `_LIBCPP_ABI_ALTERNATE_STRING_LAYOUT`.

In that layout `__is_long()` reads the flag from the last byte of the object through `__short`. `__long` stores its flag in the last bitfield after `__size_`. 
On a 64-bit:
For a `uint8_t` `size_type` that is byte 9 while `alignof(pointer)` pads the struct to 16 bytes. The flag is written at byte 9 and read at byte 15, which is never written, so every long string looks short.

This change inserts a `__padding` member between `__size_` and `__cap_` in `__long`. Its size is the gap between `2 * sizeof(size_type)` and the next multiple of `alignof(pointer)`, which pushes `__cap_` and `__is_long_` to the last bytes of the object so the `__long` flag aliases the `__short` flag again. 

The member is `_LIBCPP_NO_UNIQUE_ADDRESS`, so when the gap is 0 it occupies no space.




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


1 Files Affected:

- (modified) libcxx/include/string (+9-1) 


``````````diff
diff --git a/libcxx/include/string b/libcxx/include/string
index 33175c115fd10c..25bf9e158f5d6b 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -797,12 +797,20 @@ private:
     __long() = default;
 
     _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __long(__alloc_result __alloc, size_type __size)
-        : __data_(__alloc.ptr), __size_(__size), __cap_(__alloc.count / __endian_factor), __is_long_(true) {
+        : __data_(__alloc.ptr),
+          __size_(__size),
+          __padding_(),
+          __cap_(__alloc.count / __endian_factor),
+          __is_long_(true) {
       _LIBCPP_ASSERT_INTERNAL(!__fits_in_sso(__alloc.count), "Long capacity should always be larger than the SSO");
     }
 
     pointer __data_;
     size_type __size_;
+    _LIBCPP_NO_UNIQUE_ADDRESS
+    __padding<((2 * sizeof(size_type) + _LIBCPP_ALIGNOF(pointer) - 1) & ~(_LIBCPP_ALIGNOF(pointer) - 1)) -
+              2 * sizeof(size_type)>
+        __padding_;
     size_type __cap_ : sizeof(size_type) * CHAR_BIT - 1;
     size_type __is_long_ : 1;
   };

``````````

</details>


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


More information about the libcxx-commits mailing list