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

    <tr>
        <th>Summary</th>
        <td>
            asan container-overflow false positive on std::vector assignment with custom allocator
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            libc++,
            compiler-rt:asan
      </td>
    </tr>

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

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

<pre>
    https://reviews.llvm.org/rG490555026821db47d1cf4bf08c219b3e56ec6b45 made `__sanitizer_annotate_contiguous_container` apply to `std::vector` also when using custom allocators.

This can cause false container-overflow errors if the custom allocator touches the memory it manages.

Reproducer (reduced from https://crbug.com/1410719#c6):

```
$ cat /tmp/a.cc
#include <stdlib.h>
#include <string.h>
#include <vector>

template <typename T>
struct ZeroAlloc {
  using value_type = T;
 ZeroAlloc() noexcept {}
  template <typename U> ZeroAlloc(const ZeroAlloc<U>&) noexcept {}
  template <typename U> bool operator==(const ZeroAlloc<U>&) const noexcept { return true; }
  template <typename U> bool operator!=(const ZeroAlloc<U>&) const noexcept { return false; }

 T* allocate(size_t n) const {
    return (T*)malloc(sizeof(T) * n);
 }
  void deallocate(T* p, size_t n) const noexcept {
    memset(p, 0, sizeof(T) * n);
    free(p);
  }
};

int main() {
  using Vector = std::vector<int, ZeroAlloc<int>>;

  Vector v;
 v.resize(100);

  Vector w;
  w.push_back(0);
 w.reserve(10);

  w = v; // Goes boom when deallocating w's storage.

  return 0;
}
```

In the assignment, `w`'s storage will get deallocated, causing `memset` to touch memory outside of `w`'s current size:

```
$ build2/bin/clang++ -g -fsanitize=address -stdlib=libc++ /tmp/a.cc && ASAN_SYMBOLIZER_PATH=/work/llvm-project/build2/bin/llvm-symbolizer LD_LIBRARY_PATH=build2/lib/x86_64-unknown-linux-gnu/ ./a.out
=================================================================
==1559804==ERROR: AddressSanitizer: container-overflow on address 0x604000000050 at pc 0x5628a2ee5f38 bp 0x7ffde290e7b0 sp 0x7ffde290df78
WRITE of size 40 at 0x604000000050 thread T0
    #0 0x5628a2ee5f37 in __asan_memset /work/llvm-project/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp:26:3
 #1 0x5628a2f269b6 in ZeroAlloc<int>::deallocate(int*, unsigned long) const /tmp/a.cc:17:5
    #2 0x5628a2f266d4 in std::__1::allocator_traits<ZeroAlloc<int>>::deallocate[abi:v170000](ZeroAlloc<int>&, int*, unsigned long) /work/llvm-project/build2/bin/../include/c++/v1/__memory/allocator_traits.h:288:13
 #3 0x5628a2f2e022 in std::__1::vector<int, ZeroAlloc<int>>::__vdeallocate() /work/llvm-project/build2/bin/../include/c++/v1/vector:974:9
    #4 0x5628a2f2d9e0 in void std::__1::vector<int, ZeroAlloc<int>>::assign<int*, 0>(int*, int*) /work/llvm-project/build2/bin/../include/c++/v1/vector:1404:9
    #5 0x5628a2f26175 in std::__1::vector<int, ZeroAlloc<int>>::operator=[abi:v170000](std::__1::vector<int, ZeroAlloc<int>> const&) /work/llvm-project/build2/bin/../include/c++/v1/vector:1361:9
 #6 0x5628a2f258f3 in main /tmp/a.cc:32:5
    #7 0x7fa4d2cb1189 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
 #8 0x7fa4d2cb1244 in __libc_start_main csu/../csu/libc-start.c:381:3
 #9 0x5628a2e4c340 in _start (/work/llvm-project/a.out+0x1e340)

0x604000000050 is located 0 bytes inside of 40-byte region [0x604000000050,0x604000000078)
allocated by thread T0 here:
    #0 0x5628a2ee69be in __interceptor_malloc /work/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:69:3
    #1 0x5628a2f28fbc in ZeroAlloc<int>::allocate(unsigned long) const /tmp/a.cc:14:16
    #2 0x5628a2f28e20 in std::__1::__allocation_result<std::__1::allocator_traits<ZeroAlloc<int>>::pointer> std::__1::__allocate_at_least[abi:v170000]<ZeroAlloc<int>>(ZeroAlloc<int>&, unsigned long) /work/llvm-project/build2/bin/../include/c++/v1/__memory/allocate_at_least.h:55:19
 #3 0x5628a2f27559 in std::__1::__split_buffer<int, ZeroAlloc<int>&>::__split_buffer(unsigned long, unsigned long, ZeroAlloc<int>&) /work/llvm-project/build2/bin/../include/c++/v1/__split_buffer:323:29
 #4 0x5628a2f25fae in std::__1::vector<int, ZeroAlloc<int>>::reserve(unsigned long) /work/llvm-project/build2/bin/../include/c++/v1/vector:1520:53
 #5 0x5628a2f258e1 in main /tmp/a.cc:30:5
    #6 0x7fa4d2cb1189 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
```

The reallocation logic in the assignment code looks like this:

```
 __vdeallocate(); 
        __vallocate(__recommend(__new_size));
 __construct_at_end(__first, __last, __new_size);
```

Perhaps annotations should be added around the `__vdeallocate` call to avoid the false positive.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzUWUtv4zgS_jXMpWCDIvU85OA8PNvA7M4gk93FzEWgpJLNbUkUSMpO-tcvSPkhxU6m0d07wAaGWxZZ76qvimxhjNx0iLckuiPRw40Y7Fbp2y-tqrC9KVT1eru1tjeErwhbE7bWuJO4N8um2bVLpTfu1U9hRqMooixOWVAVYVIFZR0WNU1LFmQFxyjGMi7CCFpRIZCY5rkRnbTyC-pcdJ2ywmJeqs7KzaAG4x-F7FCTmILo--YVrHKExlZOFb7aYWnVuNwYBfstdjAY2W2gHIxVLYimUaWwSpsloQ-Ersbv5600UIoOSjEYhFo0BuEkbqF2qOtG7QG1VtqArMFu8YInWDWUWzR-scVW6VeQFlrRiQ3OBT5hr1U1lKiBsFSje6yg1qqFuWdLXQybZalawtZBGNAkyAjjZUxY5vZMWJKYHj7jTxZCKSwQtrZtT9haLMvyuMRlVzaD8zq_N7ZqZLHcEv54fVnLbvPu8sHjp0X_bbHtG2H9BvvaYydahOfTJmP1UFr4A7VaOd8BSe7GFThEayeaAXNHCoQ_ONLjhhMRYSlhGXQKX0rsreeRPBzZXNXgn4Q_zhiUqjMTPQi_d1sIi7-Jc6FUA6pHLbxHHtznT2SMi1NJoNEOugOrByT8Dr5BMgu-S7JP_pnogwLPhK2OyY6EpUZ-wdxCd2Y3iSMc2RGWOkLCslYc3O4IVT0uZOC4dj6dj8QTm3dKVlDhRKrXoifsHi7lz0J2UqTF1qAlLPVU9Ej6kQYAUGvEkWb6_uyT5OH0evyWnSt12R0S8yKn_-UrxefzW7zi97KzTq9psNwr_ug_Mzlw5LQ767VbanQ2EZYGlE5VfkOzn9iyX_aD2eaFKD8Tls6oYO8Yot6NHK8x3HtLdj5RPFLBTwqNS8V2xN1T1Jzxe8ISA8YqLTa4nHM6JAo9izg5-Q2k-e9PncfXsUe1ODqOxHTv9k2kwF42DWzQTvKncnsdxjudSEwPqRFT10g8eh9xWw3WyApB1TPe5aA1dtYn0J_jbzHIpmKErQuXFuuyEd2GsDvC7mCxgUV9bHeEP4iq0mgMLEY4JvyhkUV52DzDcPAVHMPqt9U_8t9-__vdLz9_-uPxKf919fw3X_jrvdKfCVu7ZrzotfoPltbpMFfGr5rXtlCNa7jw80P-86e7p9XT70dOJwKnD1u_pHEeh4uh-9ypfbdoZDe8LDbd4EK_9LqpwR5sH8Hv__ozMSSIoiyl4fjj8enplyfCV7AaI_bbcWRx766MDKqDY2zpS0xDOv5FFISFvgT6EsUsFQwxqnkKRQ_0JanrCllGMSkomOmbqk7SUbV_P316fnTp6VIRQs_ujQC71SgqeKZnVCOM07nIBGQHeS6M6PKxHODdFCpV28sG9ULbU1o4wsM_uewsagfAShvHTHZueDCyNMuy7wlfsZjwFT_CPOPBSZeaxVkRO12uYaDDylkX8Hi5ctU8dH5WraBRrrhOrWg29vBVkBC-imaOYFPhcRU64SdkzvNgfDhNd7nVQlpD-P07KP1GyehOFNJhfJC4eJDI9eQrpK6a7-EDg762opeuCg-jmQvWCB6ErXcBYes8H5HNueSNSW64W7E0dW6aBIdP_IOUsev--coWNtLsZkH8ccYdlVhlSei-Z3EOJ3ZUGVJnh58rvsuYsf8ct67G0cKFc5Kbx6cfbmYQ0ks7o2k-B0n03fGazrJXs_kbuY8lehhEf7RneBxMPEMYjyduidKaO7e4Oe0CIji7gIjEQ68IK1YWQZBmI1a6zpwbK7TNS9E0uedWmuGopXk1FfaGsHXX22ZEygsCX3SRr7n4rGw6FcjC8ELgW1njo9uw8BuW3pI0mONsdsb8sOShL4GRIfg6fCcEY0tnd_QlQB76MXAy8LzpNtLAYcgCCsWrRQMO-8cZKqQL9wo0bqTqgER3c2rC7qcvkvQk6zS6QfF67miwRX0ewK50tjgrcHTepCnl4xHk2xvcSJ_72efQ0uJs4upRj2lXS-ui_KirTeDwaztZOM2Zy1aWIqPXSz_PjxO56nKNZmjseP7_rpbXK-9hV9cfiMRc2LxBYew1KHlPwAcN8y9rk2fNx5KNnPuz620yiaLsPd-bvpE2L4a6xo8B0g1Jj1epLnLkwg3vMfyB_pnbseKMu-lh4pBpv41qgd_dh85H0f9R0M_dI2LUxXgCndGsfWDwfvugF-0j_ivbx9XD8vPWYe657KFRG-kBaX6GhlJVCI1Snw008jOC3Urz8QEXroxz_jbg5AH3l-e7yZY811iqtsWu8r863OfjvUU2u37Ic499eiitq77j9lpq45MlzxtxfJryON0gXPPFr6i3ojdwuFqWqjNgtmpoKijQHdKwAqHV0FXeOf5CemphTMG5H6wC4edHt2u8Ku6VkVbucHlT3fIq45m4wdsgTiKa0pQmN9vbEDOKaRKwqOBVGlZVSJFhLNK0EhgzfiNvGWWcBpwGLOAsWSZFwrMqqcMyjAOahiSk2ArZnC7Zb6QxA97GlKfhTSMKbIy_sGfsfHVAGCPsnjA27WxueHU9jZHo4Ubf-sopho0hIW2ksedr_BsrbYO3bve1o-3cdnfSfXOxNU2wvbTbixvzm0E3b_4rYSPtdigON95Okcva9na7-vCm_zcAAP__MFNWIA">