Skip to content

std::allocate_shared & std::make_shared for arrays causes new-delete-size-mismatch under asan #68051

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
rupprecht opened this issue Oct 2, 2023 · 1 comment · Fixed by #68233
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.

Comments

@rupprecht
Copy link
Collaborator

The following snippet yields a new/delete type mismatch when building with sized deallocation:

int main(int argc, char *argv[]) {
    std::allocate_shared<int64_t[]>(std::allocator<int64_t>{}, 1);
}

It runs fine with -stdlib=libc++ -fsanitize=address -std=c++20, but fails when adding -fsized-deallocation. Asan stack trace:

=================================================================
==1==ERROR: AddressSanitizer: new-delete-type-mismatch on 0x504000000050 in thread T0:
  object passed to delete has wrong type:
  size of the allocated type:   40 bytes;
  size of the deallocated type: 320 bytes.
    #0 0x561aa17a18d2 in operator delete(void*, unsigned long) /root/llvm-project/compiler-rt/lib/asan/asan_new_delete.cpp:164:3
    #1 0x561aa17a4f6c in void std::__1::__libcpp_operator_delete[abi:v180000]<void*, unsigned long>(void*, unsigned long) /opt/compiler-explorer/clang-trunk-20231002/bin/../include/c++/v1/new:282:3
    #2 0x561aa17a4f0c in void std::__1::__do_deallocate_handle_size[abi:v180000]<>(void*, unsigned long) /opt/compiler-explorer/clang-trunk-20231002/bin/../include/c++/v1/new:308:10
    #3 0x561aa17a4eb4 in std::__1::__libcpp_deallocate[abi:v180000](void*, unsigned long, unsigned long) /opt/compiler-explorer/clang-trunk-20231002/bin/../include/c++/v1/new:322:14
    #4 0x561aa17a4e39 in std::__1::allocator<std::__1::__sp_aligned_storage<8ul>>::deallocate[abi:v180000](std::__1::__sp_aligned_storage<8ul>*, unsigned long) /opt/compiler-explorer/clang-trunk-20231002/bin/../include/c++/v1/__memory/allocator.h:130:13
    #5 0x561aa17a4df4 in std::__1::allocator_traits<std::__1::allocator<std::__1::__sp_aligned_storage<8ul>>>::deallocate[abi:v180000](std::__1::allocator<std::__1::__sp_aligned_storage<8ul>>&, std::__1::__sp_aligned_storage<8ul>*, unsigned long) /opt/compiler-explorer/clang-trunk-20231002/bin/../include/c++/v1/__memory/allocator_traits.h:288:13
    #6 0x561aa17a4586 in std::__1::__unbounded_array_control_block<long [], std::__1::allocator<long>>::__on_zero_shared_weak() /opt/compiler-explorer/clang-trunk-20231002/bin/../include/c++/v1/__memory/shared_ptr.h:1140:9
    #7 0x561aa17a50ee in std::__1::__shared_weak_count::__release_shared[abi:v180000]() /opt/compiler-explorer/clang-trunk-20231002/bin/../include/c++/v1/__memory/shared_ptr.h:215:9
    #8 0x561aa17a31a5 in std::__1::shared_ptr<long []>::~shared_ptr[abi:v180000]() /opt/compiler-explorer/clang-trunk-20231002/bin/../include/c++/v1/__memory/shared_ptr.h:775:23
    #9 0x561aa17a305b in main /app/example.cpp:5:5
    #10 0x7f028f312082 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24082) (BuildId: 1878e6b475720c7c51969e69ab2d276fae6d1dee)
    #11 0x561aa16c536d in _start (/app/output.s+0x2c36d)

0x504000000050 is located 0 bytes inside of 40-byte region [0x504000000050,0x504000000078)
allocated by thread T0 here:
    #0 0x561aa17a0c6d in operator new(unsigned long) /root/llvm-project/compiler-rt/lib/asan/asan_new_delete.cpp:95:3
    #1 0x561aa17a3af4 in void* std::__1::__libcpp_operator_new[abi:v180000]<unsigned long>(unsigned long) /opt/compiler-explorer/clang-trunk-20231002/bin/../include/c++/v1/new:272:10
    #2 0x561aa17a3a5c in std::__1::__libcpp_allocate[abi:v180000](unsigned long, unsigned long) /opt/compiler-explorer/clang-trunk-20231002/bin/../include/c++/v1/new:298:10
    #3 0x561aa17a399c in std::__1::allocator<std::__1::__sp_aligned_storage<8ul>>::allocate[abi:v180000](unsigned long) /opt/compiler-explorer/clang-trunk-20231002/bin/../include/c++/v1/__memory/allocator.h:114:38
    #4 0x561aa17a392c in std::__1::allocator_traits<std::__1::allocator<std::__1::__sp_aligned_storage<8ul>>>::allocate[abi:v180000](std::__1::allocator<std::__1::__sp_aligned_storage<8ul>>&, unsigned long) /opt/compiler-explorer/clang-trunk-20231002/bin/../include/c++/v1/__memory/allocator_traits.h:268:20
    #5 0x561aa17a3626 in std::__1::__allocation_guard<std::__1::allocator<std::__1::__sp_aligned_storage<8ul>>>::__allocation_guard[abi:v180000]<std::__1::allocator<long>>(std::__1::allocator<long>, unsigned long) /opt/compiler-explorer/clang-trunk-20231002/bin/../include/c++/v1/__memory/allocation_guard.h:57:18
    #6 0x561aa17a3317 in std::__1::shared_ptr<long []> std::__1::__allocate_shared_unbounded_array[abi:v180000]<long [], std::__1::allocator<long>>(std::__1::allocator<long> const&, unsigned long) /opt/compiler-explorer/clang-trunk-20231002/bin/../include/c++/v1/__memory/shared_ptr.h:1162:39
    #7 0x561aa17a30f7 in std::__1::shared_ptr<long []> std::__1::allocate_shared[abi:v180000]<long [], std::__1::allocator<long>, void>(std::__1::allocator<long> const&, unsigned long) /opt/compiler-explorer/clang-trunk-20231002/bin/../include/c++/v1/__memory/shared_ptr.h:1301:12
    #8 0x561aa17a3052 in main /app/example.cpp:5:5
    #9 0x7f028f312082 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24082) (BuildId: 1878e6b475720c7c51969e69ab2d276fae6d1dee)

SUMMARY: AddressSanitizer: new-delete-type-mismatch /root/llvm-project/compiler-rt/lib/asan/asan_new_delete.cpp:164:3 in operator delete(void*, unsigned long)

Live snippet: https://godbolt.org/z/ddYr6TYb1

Note: the mismatch was found by running the std::boyer_moore_searcher example snippet on cppreference: https://godbolt.org/z/Gsx6dWPYn. Likely it has the same underlying issue, although this one does not require c++20 to reproduce.

The allocation divides by sizeof(_AlignedStorage), but the deallocation does not appear to make the same adjustment. That may be the source of the issue, which could be fixed w/ something like:

--- a/libcxx/include/__memory/shared_ptr.h
+++ b/libcxx/include/__memory/shared_ptr.h
@@ -1137,7 +1137,9 @@
         __alloc_.~_Alloc();
         size_t __size = __unbounded_array_control_block::__bytes_for(__count_);
         _AlignedStorage* __storage = reinterpret_cast<_AlignedStorage*>(this);
-        allocator_traits<_StorageAlloc>::deallocate(__tmp, _PointerTraits::pointer_to(*__storage), __size);
+        allocator_traits<_StorageAlloc>::deallocate(
+            __tmp, _PointerTraits::pointer_to(*__storage),
+            __size / sizeof(_AlignedStorage));
     }
@rupprecht rupprecht added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Oct 2, 2023
@ilya-biryukov
Copy link
Contributor

Note that the deallocation of bounded arrays is broken too.

ilya-biryukov added a commit to ilya-biryukov/llvm-project that referenced this issue Oct 4, 2023
Fixes llvm#68051.

Current implementation passes the number of `_AlignedStorage` objects
when it calls to `allocate` and the number of **bytes** on deallocate.
This only applies to allocations that allocate control block and the
storage together, i.e. `make_shared` and `allocate_shared`.

Found by ASan.
tru pushed a commit that referenced this issue Nov 20, 2023
…68233)

Fixes #68051.

Current implementation passes the number of `_AlignedStorage` objects
when it calls to `allocate` and the number of **bytes** on `deallocate`.
This only applies to allocations that allocate control block and the
storage together, i.e. `make_shared` and `allocate_shared`.

Found by ASan under Clang combined with `-fsized-deallocation`.

(cherry picked from commit f722db0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants