Original file line number Diff line number Diff line change
Expand Up @@ -15,39 +15,93 @@
#include <memory>
#include <cassert>

#include "test_macros.h"
#include "count_new.hpp"

int A_constructed = 0;

struct A
{
int data;
A() {++A_constructed;}
A(const A&) {++A_constructed;}
~A() {--A_constructed;}
#ifdef TEST_HAS_NO_ALIGNED_ALLOCATION
static const bool UsingAlignedNew = false;
#else
static const bool UsingAlignedNew = true;
#endif

#ifdef __STDCPP_DEFAULT_NEW_ALIGNMENT__
static const size_t MaxAligned = __STDCPP_DEFAULT_NEW_ALIGNMENT__;
#else
static const size_t MaxAligned = std::alignment_of<std::max_align_t>::value;
#endif

static const size_t OverAligned = MaxAligned * 2;


template <size_t Align>
struct TEST_ALIGNAS(Align) AlignedType {
char data;
static int constructed;
AlignedType() { ++constructed; }
AlignedType(AlignedType const&) { ++constructed; }
~AlignedType() { --constructed; }
};
template <size_t Align>
int AlignedType<Align>::constructed = 0;

int main()
{
globalMemCounter.reset();
std::allocator<A> a;

template <size_t Align>
void test_aligned() {
typedef AlignedType<Align> T;
T::constructed = 0;
globalMemCounter.reset();
std::allocator<T> a;
const bool IsOverAlignedType = Align > MaxAligned;
const bool ExpectAligned = IsOverAlignedType && UsingAlignedNew;
{
assert(globalMemCounter.checkOutstandingNewEq(0));
assert(A_constructed == 0);
assert(T::constructed == 0);
globalMemCounter.last_new_size = 0;
A* volatile ap = a.allocate(3);
globalMemCounter.last_new_align = 0;
T* volatile ap = a.allocate(3);
assert(globalMemCounter.checkOutstandingNewEq(1));
assert(globalMemCounter.checkLastNewSizeEq(3 * sizeof(int)));
assert(A_constructed == 0);
assert(globalMemCounter.checkNewCalledEq(1));
assert(globalMemCounter.checkAlignedNewCalledEq(ExpectAligned));
assert(globalMemCounter.checkLastNewSizeEq(3 * sizeof(T)));
assert(globalMemCounter.checkLastNewAlignEq(ExpectAligned ? Align : 0));
assert(T::constructed == 0);
globalMemCounter.last_delete_align = 0;
a.deallocate(ap, 3);
assert(globalMemCounter.checkOutstandingNewEq(0));
assert(A_constructed == 0);

assert(globalMemCounter.checkDeleteCalledEq(1));
assert(globalMemCounter.checkAlignedDeleteCalledEq(ExpectAligned));
assert(globalMemCounter.checkLastDeleteAlignEq(ExpectAligned ? Align : 0));
assert(T::constructed == 0);
}
globalMemCounter.reset();
{
globalMemCounter.last_new_size = 0;
A* volatile ap2 = a.allocate(3, (const void*)5);
globalMemCounter.last_new_align = 0;
T* volatile ap2 = a.allocate(11, (const void*)5);
assert(globalMemCounter.checkOutstandingNewEq(1));
assert(globalMemCounter.checkLastNewSizeEq(3 * sizeof(int)));
assert(A_constructed == 0);
a.deallocate(ap2, 3);
assert(globalMemCounter.checkNewCalledEq(1));
assert(globalMemCounter.checkAlignedNewCalledEq(ExpectAligned));
assert(globalMemCounter.checkLastNewSizeEq(11 * sizeof(T)));
assert(globalMemCounter.checkLastNewAlignEq(ExpectAligned ? Align : 0));
assert(T::constructed == 0);
globalMemCounter.last_delete_align = 0;
a.deallocate(ap2, 11);
assert(globalMemCounter.checkOutstandingNewEq(0));
assert(A_constructed == 0);
assert(globalMemCounter.checkDeleteCalledEq(1));
assert(globalMemCounter.checkAlignedDeleteCalledEq(ExpectAligned));
assert(globalMemCounter.checkLastDeleteAlignEq(ExpectAligned ? Align : 0));
assert(T::constructed == 0);
}
}

int main() {
test_aligned<1>();
test_aligned<2>();
test_aligned<4>();
test_aligned<8>();
test_aligned<16>();
test_aligned<MaxAligned>();
test_aligned<OverAligned>();
test_aligned<OverAligned * 2>();
}
169 changes: 164 additions & 5 deletions libcxx/test/support/count_new.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,20 @@ class MemCounter
int outstanding_new;
int new_called;
int delete_called;
int aligned_new_called;
int aligned_delete_called;
std::size_t last_new_size;
std::size_t last_new_align;
std::size_t last_delete_align;

int outstanding_array_new;
int new_array_called;
int delete_array_called;
int aligned_new_array_called;
int aligned_delete_array_called;
std::size_t last_new_array_size;
std::size_t last_new_array_align;
std::size_t last_delete_array_align;

public:
void newCalled(std::size_t s)
Expand All @@ -82,13 +90,25 @@ class MemCounter
last_new_size = s;
}

void alignedNewCalled(std::size_t s, std::size_t a) {
newCalled(s);
++aligned_new_called;
last_new_align = a;
}

void deleteCalled(void * p)
{
assert(p);
--outstanding_new;
++delete_called;
}

void alignedDeleteCalled(void *p, std::size_t a) {
deleteCalled(p);
++aligned_delete_called;
last_delete_align = a;
}

void newArrayCalled(std::size_t s)
{
assert(disable_allocations == false);
Expand All @@ -104,13 +124,25 @@ class MemCounter
last_new_array_size = s;
}

void alignedNewArrayCalled(std::size_t s, std::size_t a) {
newArrayCalled(s);
++aligned_new_array_called;
last_new_array_align = a;
}

void deleteArrayCalled(void * p)
{
assert(p);
--outstanding_array_new;
++delete_array_called;
}

void alignedDeleteArrayCalled(void * p, std::size_t a) {
deleteArrayCalled(p);
++aligned_delete_array_called;
last_delete_array_align = a;
}

void disableAllocations()
{
disable_allocations = true;
Expand All @@ -121,7 +153,6 @@ class MemCounter
disable_allocations = false;
}


void reset()
{
disable_allocations = false;
Expand All @@ -130,12 +161,18 @@ class MemCounter
outstanding_new = 0;
new_called = 0;
delete_called = 0;
aligned_new_called = 0;
aligned_delete_called = 0;
last_new_size = 0;
last_new_align = 0;

outstanding_array_new = 0;
new_array_called = 0;
delete_array_called = 0;
aligned_new_array_called = 0;
aligned_delete_array_called = 0;
last_new_array_size = 0;
last_new_array_align = 0;
}

public:
Expand Down Expand Up @@ -174,6 +211,31 @@ class MemCounter
return disable_checking || n != delete_called;
}

bool checkAlignedNewCalledEq(int n) const
{
return disable_checking || n == aligned_new_called;
}

bool checkAlignedNewCalledNotEq(int n) const
{
return disable_checking || n != aligned_new_called;
}

bool checkAlignedNewCalledGreaterThan(int n) const
{
return disable_checking || aligned_new_called > n;
}

bool checkAlignedDeleteCalledEq(int n) const
{
return disable_checking || n == aligned_delete_called;
}

bool checkAlignedDeleteCalledNotEq(int n) const
{
return disable_checking || n != aligned_delete_called;
}

bool checkLastNewSizeEq(std::size_t n) const
{
return disable_checking || n == last_new_size;
Expand All @@ -184,6 +246,26 @@ class MemCounter
return disable_checking || n != last_new_size;
}

bool checkLastNewAlignEq(std::size_t n) const
{
return disable_checking || n == last_new_align;
}

bool checkLastNewAlignNotEq(std::size_t n) const
{
return disable_checking || n != last_new_align;
}

bool checkLastDeleteAlignEq(std::size_t n) const
{
return disable_checking || n == last_delete_align;
}

bool checkLastDeleteAlignNotEq(std::size_t n) const
{
return disable_checking || n != last_delete_align;
}

bool checkOutstandingArrayNewEq(int n) const
{
return disable_checking || n == outstanding_array_new;
Expand Down Expand Up @@ -214,6 +296,31 @@ class MemCounter
return disable_checking || n != delete_array_called;
}

bool checkAlignedNewArrayCalledEq(int n) const
{
return disable_checking || n == aligned_new_array_called;
}

bool checkAlignedNewArrayCalledNotEq(int n) const
{
return disable_checking || n != aligned_new_array_called;
}

bool checkAlignedNewArrayCalledGreaterThan(int n) const
{
return disable_checking || aligned_new_array_called > n;
}

bool checkAlignedDeleteArrayCalledEq(int n) const
{
return disable_checking || n == aligned_delete_array_called;
}

bool checkAlignedDeleteArrayCalledNotEq(int n) const
{
return disable_checking || n != aligned_delete_array_called;
}

bool checkLastNewArraySizeEq(std::size_t n) const
{
return disable_checking || n == last_new_array_size;
Expand All @@ -223,6 +330,16 @@ class MemCounter
{
return disable_checking || n != last_new_array_size;
}

bool checkLastNewArrayAlignEq(std::size_t n) const
{
return disable_checking || n == last_new_array_align;
}

bool checkLastNewArrayAlignNotEq(std::size_t n) const
{
return disable_checking || n != last_new_array_align;
}
};

#ifdef DISABLE_NEW_COUNT
Expand Down Expand Up @@ -254,22 +371,65 @@ void operator delete(void* p) TEST_NOEXCEPT
std::free(p);
}


void* operator new[](std::size_t s) TEST_THROW_SPEC(std::bad_alloc)
{
getGlobalMemCounter()->newArrayCalled(s);
return operator new(s);
}


void operator delete[](void* p) TEST_NOEXCEPT
{
getGlobalMemCounter()->deleteArrayCalled(p);
operator delete(p);
}

#endif // DISABLE_NEW_COUNT
#ifndef TEST_HAS_NO_ALIGNED_ALLOCATION
#if defined(_LIBCPP_MSVCRT_LIKE) || \
(!defined(_LIBCPP_VERSION) && defined(_WIN32))
#define USE_ALIGNED_ALLOC
#endif

void* operator new(std::size_t s, std::align_val_t av) TEST_THROW_SPEC(std::bad_alloc) {
const std::size_t a = static_cast<std::size_t>(av);
getGlobalMemCounter()->alignedNewCalled(s, a);
void *ret;
#ifdef USE_ALIGNED_ALLOC
ret = _aligned_malloc(s, a);
#else
posix_memalign(&ret, a, s);
#endif
if (ret == nullptr)
detail::throw_bad_alloc_helper();
return ret;
}

void operator delete(void *p, std::align_val_t av) TEST_NOEXCEPT {
const std::size_t a = static_cast<std::size_t>(av);
getGlobalMemCounter()->alignedDeleteCalled(p, a);
if (p) {
#ifdef USE_ALIGNED_ALLOC
::_aligned_free(p);
#else
::free(p);
#endif
}
}

void* operator new[](std::size_t s, std::align_val_t av) TEST_THROW_SPEC(std::bad_alloc) {
const std::size_t a = static_cast<std::size_t>(av);
getGlobalMemCounter()->alignedNewArrayCalled(s, a);
return operator new(s, av);
}

void operator delete[](void *p, std::align_val_t av) TEST_NOEXCEPT {
const std::size_t a = static_cast<std::size_t>(av);
getGlobalMemCounter()->alignedDeleteArrayCalled(p, a);
return operator delete(p, av);
}

#endif // TEST_HAS_NO_ALIGNED_ALLOCATION

#endif // DISABLE_NEW_COUNT

struct DisableAllocationGuard {
explicit DisableAllocationGuard(bool disable = true) : m_disabled(disable)
Expand All @@ -295,7 +455,6 @@ struct DisableAllocationGuard {
DisableAllocationGuard& operator=(DisableAllocationGuard const&);
};


struct RequireAllocationGuard {
explicit RequireAllocationGuard(std::size_t RequireAtLeast = 1)
: m_req_alloc(RequireAtLeast),
Expand Down
6 changes: 6 additions & 0 deletions libcxx/test/support/test_macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,11 @@
#define TEST_NORETURN [[noreturn]]
#endif

#if !defined(__cpp_aligned_new) || __cpp_aligned_new < 201606L || \
defined(_LIBCPP_HAS_NO_ALIGNED_ALLOCATION)
#define TEST_HAS_NO_ALIGNED_ALLOCATION
#endif

#if defined(_LIBCPP_SAFE_STATIC)
#define TEST_SAFE_STATIC _LIBCPP_SAFE_STATIC
#else
Expand Down Expand Up @@ -228,6 +233,7 @@ inline void DoNotOptimize(Tp const& value) {
}
#endif


#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
Expand Down