| //===----------------------------------------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| // test libc++'s implementation of align_val_t, and the relevant new/delete |
| // overloads in all dialects when -faligned-allocation is present. |
| |
| // Libc++ defers to the underlying MSVC library to provide the new/delete |
| // definitions, which does not yet provide aligned allocation |
| // XFAIL: LIBCXX-WINDOWS-FIXME |
| |
| // The dylibs shipped before macosx10.13 do not contain the aligned allocation |
| // functions, so trying to force using those with -faligned-allocation results |
| // in a link error. |
| // XFAIL: with_system_cxx_lib=macosx10.12 |
| // XFAIL: with_system_cxx_lib=macosx10.11 |
| // XFAIL: with_system_cxx_lib=macosx10.10 |
| // XFAIL: with_system_cxx_lib=macosx10.9 |
| // XFAIL: with_system_cxx_lib=macosx10.8 |
| // XFAIL: with_system_cxx_lib=macosx10.7 |
| |
| // The test will fail on deployment targets that do not support sized deallocation. |
| // XFAIL: availability=macosx10.11 |
| // XFAIL: availability=macosx10.10 |
| // XFAIL: availability=macosx10.9 |
| // XFAIL: availability=macosx10.8 |
| // XFAIL: availability=macosx10.7 |
| |
| // AppleClang < 10 incorrectly warns that aligned allocation is not supported |
| // even when it is supported. |
| // UNSUPPORTED: apple-clang-9 |
| |
| // XFAIL: sanitizer-new-delete, ubsan |
| |
| // GCC doesn't support the aligned-allocation flags. |
| // XFAIL: gcc |
| |
| // RUN: %build -faligned-allocation -fsized-deallocation |
| // RUN: %run |
| // RUN: %build -faligned-allocation -fno-sized-deallocation -DNO_SIZE |
| // RUN: %run |
| // RUN: %build -fno-aligned-allocation -fsized-deallocation -DNO_ALIGN |
| // RUN: %run |
| // RUN: %build -fno-aligned-allocation -fno-sized-deallocation -DNO_ALIGN -DNO_SIZE |
| // RUN: %run |
| |
| #include <new> |
| #include <typeinfo> |
| #include <string> |
| #include <cassert> |
| |
| #include "test_macros.h" |
| |
| struct alloc_stats { |
| alloc_stats() { reset(); } |
| |
| int aligned_sized_called; |
| int aligned_called; |
| int sized_called; |
| int plain_called; |
| int last_size; |
| int last_align; |
| |
| void reset() { |
| aligned_sized_called = aligned_called = sized_called = plain_called = 0; |
| last_align = last_size = -1; |
| } |
| |
| bool expect_plain() const { |
| assert(aligned_sized_called == 0); |
| assert(aligned_called == 0); |
| assert(sized_called == 0); |
| assert(last_size == -1); |
| assert(last_align == -1); |
| return plain_called == 1; |
| } |
| |
| bool expect_size(int n) const { |
| assert(plain_called == 0); |
| assert(aligned_sized_called == 0); |
| assert(aligned_called == 0); |
| assert(last_size == n); |
| assert(last_align == -1); |
| return sized_called == 1; |
| } |
| |
| bool expect_align(int a) const { |
| assert(plain_called == 0); |
| assert(aligned_sized_called == 0); |
| assert(sized_called == 0); |
| assert(last_size == -1); |
| assert(last_align == a); |
| return aligned_called == 1; |
| } |
| |
| bool expect_size_align(int n, int a) const { |
| assert(plain_called == 0); |
| assert(sized_called == 0); |
| assert(aligned_called == 0); |
| assert(last_size == n); |
| assert(last_align == a); |
| return aligned_sized_called == 1; |
| } |
| }; |
| alloc_stats stats; |
| |
| void operator delete(void* p)TEST_NOEXCEPT { |
| ::free(p); |
| stats.plain_called++; |
| stats.last_size = stats.last_align = -1; |
| } |
| |
| #ifndef NO_SIZE |
| void operator delete(void* p, size_t n)TEST_NOEXCEPT { |
| ::free(p); |
| stats.sized_called++; |
| stats.last_size = n; |
| stats.last_align = -1; |
| } |
| #endif |
| |
| #ifndef NO_ALIGN |
| void operator delete(void* p, std::align_val_t a)TEST_NOEXCEPT { |
| ::free(p); |
| stats.aligned_called++; |
| stats.last_align = static_cast<int>(a); |
| stats.last_size = -1; |
| } |
| |
| void operator delete(void* p, size_t n, std::align_val_t a)TEST_NOEXCEPT { |
| ::free(p); |
| stats.aligned_sized_called++; |
| stats.last_align = static_cast<int>(a); |
| stats.last_size = n; |
| } |
| #endif |
| |
| void test_libcpp_dealloc() { |
| void* p = nullptr; |
| size_t over_align_val = TEST_ALIGNOF(std::max_align_t) * 2; |
| size_t under_align_val = TEST_ALIGNOF(int); |
| size_t with_size_val = 2; |
| |
| { |
| std::__libcpp_deallocate_unsized(p, under_align_val); |
| assert(stats.expect_plain()); |
| } |
| stats.reset(); |
| |
| #if defined(NO_SIZE) && defined(NO_ALIGN) |
| { |
| std::__libcpp_deallocate(p, with_size_val, over_align_val); |
| assert(stats.expect_plain()); |
| } |
| stats.reset(); |
| #elif defined(NO_SIZE) |
| { |
| std::__libcpp_deallocate(p, with_size_val, over_align_val); |
| assert(stats.expect_align(over_align_val)); |
| } |
| stats.reset(); |
| #elif defined(NO_ALIGN) |
| { |
| std::__libcpp_deallocate(p, with_size_val, over_align_val); |
| assert(stats.expect_size(with_size_val)); |
| } |
| stats.reset(); |
| #else |
| { |
| std::__libcpp_deallocate(p, with_size_val, over_align_val); |
| assert(stats.expect_size_align(with_size_val, over_align_val)); |
| } |
| stats.reset(); |
| { |
| std::__libcpp_deallocate_unsized(p, over_align_val); |
| assert(stats.expect_align(over_align_val)); |
| } |
| stats.reset(); |
| { |
| std::__libcpp_deallocate(p, with_size_val, under_align_val); |
| assert(stats.expect_size(with_size_val)); |
| } |
| stats.reset(); |
| #endif |
| } |
| |
| struct TEST_ALIGNAS(128) AlignedType { |
| AlignedType() : elem(0) {} |
| TEST_ALIGNAS(128) char elem; |
| }; |
| |
| void test_allocator_and_new_match() { |
| stats.reset(); |
| #if defined(NO_SIZE) && defined(NO_ALIGN) |
| { |
| int* x = new int(42); |
| delete x; |
| assert(stats.expect_plain()); |
| } |
| stats.reset(); |
| { |
| AlignedType* a = new AlignedType(); |
| delete a; |
| assert(stats.expect_plain()); |
| } |
| stats.reset(); |
| #elif defined(NO_SIZE) |
| stats.reset(); |
| #if TEST_STD_VER >= 11 |
| { |
| int* x = new int(42); |
| delete x; |
| assert(stats.expect_plain()); |
| } |
| #endif |
| stats.reset(); |
| { |
| AlignedType* a = new AlignedType(); |
| delete a; |
| assert(stats.expect_align(TEST_ALIGNOF(AlignedType))); |
| } |
| stats.reset(); |
| #elif defined(NO_ALIGN) |
| stats.reset(); |
| { |
| int* x = new int(42); |
| delete x; |
| assert(stats.expect_size(sizeof(int))); |
| } |
| stats.reset(); |
| { |
| AlignedType* a = new AlignedType(); |
| delete a; |
| assert(stats.expect_size(sizeof(AlignedType))); |
| } |
| stats.reset(); |
| #else |
| stats.reset(); |
| { |
| int* x = new int(42); |
| delete x; |
| assert(stats.expect_size(sizeof(int))); |
| } |
| stats.reset(); |
| { |
| AlignedType* a = new AlignedType(); |
| delete a; |
| assert(stats.expect_size_align(sizeof(AlignedType), |
| TEST_ALIGNOF(AlignedType))); |
| } |
| stats.reset(); |
| #endif |
| } |
| |
| int main(int, char**) { |
| test_libcpp_dealloc(); |
| test_allocator_and_new_match(); |
| |
| return 0; |
| } |