<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/95161>95161</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            [libc++] `shrink_to_fit` can increase capacity if `allocate_at_least` returns a bigger allocation
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          MitalAshok
      </td>
    </tr>
</table>

<pre>
    https://eel.is/c++draft/vector.capacity#9.sentence-3

> `constexpr void shrink_to_fit();`  
> *Effects*: [...] It does not increase `capacity()`, but may reduce `capacity()` by causing reallocation.

https://godbolt.org/z/hP63rn661

```c++
#include <vector>
#include <memory>
#include <algorithm>

std::size_t min_bytes = 1000;

template<typename T>
struct increasing_allocator {
    using value_type = T;
    increasing_allocator() = default;
 template<typename U>
    constexpr increasing_allocator(const increasing_allocator<U>&) noexcept {}
    std::allocation_result<T*> allocate_at_least(std::size_t n) {
        std::size_t allocation_amount = n * sizeof(T);
        if (allocation_amount < min_bytes) allocation_amount = min_bytes;
        min_bytes += 1000;
 return { static_cast<T*>(::operator new(allocation_amount)), allocation_amount };
    }
    T* allocate(std::size_t n) {
 return allocate_at_least(n).ptr;
    }
    void deallocate(T* p, std::size_t n) noexcept {
        ::operator delete(static_cast<void*>(p));
    }
};

template<typename T, typename U>
constexpr bool operator==(increasing_allocator<T>, increasing_allocator<U>) { return true; }

int main() {
 std::vector<int, increasing_allocator<int>> x;
    x.push_back(1);
 __builtin_printf("Before shrink cap: %zu\n", x.capacity());
 x.shrink_to_fit();
    __builtin_printf("After  shrink cap: %zu\n", x.capacity());
}
```

```
Before shrink cap: 1000
After shrink cap: 2000
```

The new capacity isn't checked before the elements are moved to the new allocation:

https://github.com/llvm/llvm-project/blob/a13bc9714a6bfb766693aa7900217f6f9be6f25d/libcxx/include/vector#L1438-L1440

This came up when using an arena allocator and the smaller arenas filled up and `shrink_to_fit` didn't help
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJykVk-P46gT_TTkgsayISbOIYf86Ug_aX7SHnrPFsblmG0CFuCeZD79CuLYSY8zq9VKFq1OFfVePaoouHPypAE2KN-h_LDgvW-N3fxfeq62rjUfi8rU103rfecQ3SJyROQIoBLpEDkKRHaI7GrLG4_I8ROENzYRvONC-isidJ040B60gG8UpQeUboeVvmHEUmG083DpLP40ssautVJ_lN6UjfSIFIisEd0hlmL8sI1s35oGhHeIbBHdYpTvkiRB-QH_z-PagMPaeCy1sMAdRJiRUAzJUkT2uOo9PvMrtlD3Yt4NV1cseO-kPmELXCkjuJdGJ4-pPEtzMnVllE-MPSFy_InIsf2DUasZy57yZ-ntGxQcfiVUaqH6GjCi-5uaiL7NGc9wNvb6wsjVyVjp2_Nkj6vzdSBKt07-hNLjs9RldfXgMKIHnKVpGuR-2ODh3CnuAdG9v3ag-Rnw-xjUeduLUWmpT-UgkbEYrYZAGGN8U_CTqx7KECfCvY9YwWUuyO0conMNDe-Vn7bMMftzZBYiTrX1InZ0mDfSfYxFWMDXBi4COh9zWh0mhFHOqTJKCy7y3L_H6nzDgw1K7ksF3IW6_noOOqb5qNhT-MHrAYWfTa99VEaHhsDBxTSIFO9DzzxFkg1GpJjbv59qIHCYh5hcvgZ-KCCy-6WGsAXfWx0yw85zL0UpggCjOOGAY4amAxvLRsOPOaYhqfDt5xiuDk-8no4oAI1H8M_KD4Tnzix4Jp23r7HiFVbDA1pE7wLtWdynwnrS9YsqNSgY6D-qGABHIbtBo1l6jxr9rrPJHs9009RJlTEK32kheggfKV60ULwoyP73HRbVv-vubQ-I7h54x1XqcFNLfb8PRrVGVe9X5V6GWnkJGaz0LXTl5UmnS9L1ri0rLj4QKbInGcuy6qXyUpedldo3kQTZQWMsDAMLC97FQUTynz3K9xoRElhcki8T5THuJXkx7UZW88jbxoPF_wF5Evc-g2YH0-3f2Txjk0fzjcyzlYzWWYD3FkKX4ztBLJ1GZOWxaEF8QI2rG6RvAYOCM2jvMLeAz-YTauxNtIQI01UQiuD1RJa-7atEmDMiR6U-73--ddb8BSK8WyplKkSOPKOVWK-yJWdVU60YY2vK-WqdpiRbNaxZV8AaktchgKzE5YLIcZi64-MHEfo9W9Li2_dsufySuHRYhM7qO_yjBT2MRa5DeprjaXhyXccs3ZkrBfZmd7iRSkEdtgcHxNLnCmIprmV9E7MF1S3qDa3XdM0XsMlWWZHRtMiLRbtZsrxmvMqzHBikrCDFkuU0WxU142uaFwu5ISlZpizLsoIusyJZClpDVvOiaEhe8CVapnDmUiVByPDWWUjnetis84xlC8UrUO7-orSbqHbVnxxapko676ZtXnoV355B0OEplB9mcxNcT4-6qXqa4Pzrhc3S4VJxmONKnk5BxrFgFr1Vm39dJjHH8Oy9pfm5IX8HAAD__9NtaLk">