<html>
    <head>
      <base href="https://bugs.llvm.org/">
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - std::basic_string loses the bottom bit of capacity for regular ABI little-endian and alternate ABI big-endian strings"
   href="https://bugs.llvm.org/show_bug.cgi?id=43096">43096</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>std::basic_string loses the bottom bit of capacity for regular ABI little-endian and alternate ABI big-endian strings
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>libc++
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>unspecified
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>PC
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>Linux
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>enhancement
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>All Bugs
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>unassignedclangbugs@nondot.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>richard-llvm@metafoo.co.uk
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>llvm-bugs@lists.llvm.org, mclow.lists@gmail.com
          </td>
        </tr></table>
      <p>
        <div>
        <pre>libc++'s std::basic_string reuses the low-order bit of its capacity field as an
'is long' marker when in regular ABI little-endian or alternate ABI big-endian
mode.

When sizeof(_CharT) <= 8, this is OK: all allocations are always of a multiple
of 16 bytes, so capacity is always even, so we don't actually lose any data.
But when sizeof(_CharT) is 16, things go wrong:


#include <string>
#include <iostream>

struct big_character {
    char data[16];
};

int main() {
    for (int n = 0; n != 20; ++n) {
        std::basic_string<big_character> s;
        s.reserve(n);
        std::cout << "asked for " << n << " got " << s.capacity() << "\n";
    }
}


produces:


asked for 0 got 1
asked for 1 got 1
asked for 2 got 3
asked for 3 got 3
asked for 4 got 3
asked for 5 got 5
asked for 6 got 5
asked for 7 got 7
asked for 8 got 7
asked for 9 got 9
asked for 10 got 9
asked for 11 got 11
asked for 12 got 11
asked for 13 got 13
asked for 14 got 13
asked for 15 got 15
asked for 16 got 15
asked for 17 got 17
asked for 18 got 17
asked for 19 got 19


Note that for even sizes greater than 2, reserve(n) fails to result in a
capacity() >= n. Similarly:

    std::basic_string<big_character> s(6, big_character{});
    std::cout << "size is " << s.size() << ", capacity is " << s.capacity() <<
"\n";

prints:

size is 6, capacity is 5


If we want to avoid breaking ABI, it looks like we need to ensure that we
always allocate an even number of elements (including the terminator) in the
affected cases.</pre>
        </div>
      </p>


      <hr>
      <span>You are receiving this mail because:</span>

      <ul>
          <li>You are on the CC list for the bug.</li>
      </ul>
    </body>
</html>