Fix PR22634 - std::allocator doesn't respect over-aligned types.

This patch fixes std::allocator, and more specifically, all users
of __libcpp_allocate and __libcpp_deallocate, to support over-aligned
types.

__libcpp_allocate/deallocate now take an alignment parameter, and when
the specified alignment is greater than that supported by malloc/new,
the aligned version of operator new is called (assuming it's available).

When aligned new isn't available, the old behavior has been kept, and the
alignment parameter is ignored.

This patch depends on recent changes to __builtin_operator_new/delete which
allow them to be used to call any regular new/delete operator. By using
__builtin_operator_new/delete when possible, the new/delete erasure optimization
is maintained.

git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@328180 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Eric Fiselier
2018-03-22 04:42:56 +00:00
parent 256f187bc6
commit a831287399
9 changed files with 343 additions and 87 deletions

View File

@@ -955,6 +955,7 @@ template <unsigned> struct __static_assert_check {};
# endif # endif
#endif // defined(__APPLE__) #endif // defined(__APPLE__)
#if defined(__APPLE__) || defined(__FreeBSD__) #if defined(__APPLE__) || defined(__FreeBSD__)
#define _LIBCPP_HAS_DEFAULTRUNELOCALE #define _LIBCPP_HAS_DEFAULTRUNELOCALE
#endif #endif

View File

@@ -55,14 +55,14 @@ public:
__allocated_ = true; __allocated_ = true;
return (pointer)&buf_; return (pointer)&buf_;
} }
return static_cast<pointer>(_VSTD::__allocate(__n * sizeof(_Tp))); return static_cast<pointer>(_VSTD::__libcpp_allocate(__n * sizeof(_Tp), __alignof(_Tp)));
} }
_LIBCPP_INLINE_VISIBILITY void deallocate(pointer __p, size_type) _LIBCPP_INLINE_VISIBILITY void deallocate(pointer __p, size_type)
{ {
if (__p == (pointer)&buf_) if (__p == (pointer)&buf_)
__allocated_ = false; __allocated_ = false;
else else
_VSTD::__libcpp_deallocate(__p); _VSTD::__libcpp_deallocate(__p, __alignof(_Tp));
} }
_LIBCPP_INLINE_VISIBILITY size_type max_size() const throw() {return size_type(~0) / sizeof(_Tp);} _LIBCPP_INLINE_VISIBILITY size_type max_size() const throw() {return size_type(~0) / sizeof(_Tp);}

View File

@@ -1796,10 +1796,10 @@ public:
if (__n > max_size()) if (__n > max_size())
__throw_length_error("allocator<T>::allocate(size_t n)" __throw_length_error("allocator<T>::allocate(size_t n)"
" 'n' exceeds maximum supported size"); " 'n' exceeds maximum supported size");
return static_cast<pointer>(_VSTD::__allocate(__n * sizeof(_Tp))); return static_cast<pointer>(_VSTD::__libcpp_allocate(__n * sizeof(_Tp), __alignof(_Tp)));
} }
_LIBCPP_INLINE_VISIBILITY void deallocate(pointer __p, size_type) _NOEXCEPT _LIBCPP_INLINE_VISIBILITY void deallocate(pointer __p, size_type) _NOEXCEPT
{_VSTD::__libcpp_deallocate((void*)__p);} {_VSTD::__libcpp_deallocate((void*)__p, __alignof(_Tp));}
_LIBCPP_INLINE_VISIBILITY size_type max_size() const _NOEXCEPT _LIBCPP_INLINE_VISIBILITY size_type max_size() const _NOEXCEPT
{return size_type(~0) / sizeof(_Tp);} {return size_type(~0) / sizeof(_Tp);}
#if !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) && !defined(_LIBCPP_HAS_NO_VARIADICS) #if !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) && !defined(_LIBCPP_HAS_NO_VARIADICS)
@@ -1897,10 +1897,10 @@ public:
if (__n > max_size()) if (__n > max_size())
__throw_length_error("allocator<const T>::allocate(size_t n)" __throw_length_error("allocator<const T>::allocate(size_t n)"
" 'n' exceeds maximum supported size"); " 'n' exceeds maximum supported size");
return static_cast<pointer>(_VSTD::__allocate(__n * sizeof(_Tp))); return static_cast<pointer>(_VSTD::__libcpp_allocate(__n * sizeof(_Tp), __alignof(_Tp)));
} }
_LIBCPP_INLINE_VISIBILITY void deallocate(pointer __p, size_type) _NOEXCEPT _LIBCPP_INLINE_VISIBILITY void deallocate(pointer __p, size_type) _NOEXCEPT
{_VSTD::__libcpp_deallocate((void*) const_cast<_Tp *>(__p));} {_VSTD::__libcpp_deallocate((void*) const_cast<_Tp *>(__p), __alignof(_Tp));}
_LIBCPP_INLINE_VISIBILITY size_type max_size() const _NOEXCEPT _LIBCPP_INLINE_VISIBILITY size_type max_size() const _NOEXCEPT
{return size_type(~0) / sizeof(_Tp);} {return size_type(~0) / sizeof(_Tp);}
#if !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) && !defined(_LIBCPP_HAS_NO_VARIADICS) #if !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) && !defined(_LIBCPP_HAS_NO_VARIADICS)
@@ -2016,12 +2016,7 @@ get_temporary_buffer(ptrdiff_t __n) _NOEXCEPT
while (__n > 0) while (__n > 0)
{ {
#if !defined(_LIBCPP_HAS_NO_ALIGNED_ALLOCATION) #if !defined(_LIBCPP_HAS_NO_ALIGNED_ALLOCATION)
#if defined(__STDCPP_DEFAULT_NEW_ALIGNMENT__) if (__is_overaligned_for_new(__alignof(_Tp)))
if (std::alignment_of<_Tp>::value > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
#else
if (std::alignment_of<_Tp>::value >
std::alignment_of<std::max_align_t>::value)
#endif
{ {
std::align_val_t __al = std::align_val_t __al =
std::align_val_t(std::alignment_of<_Tp>::value); std::align_val_t(std::alignment_of<_Tp>::value);
@@ -2032,12 +2027,7 @@ get_temporary_buffer(ptrdiff_t __n) _NOEXCEPT
__n * sizeof(_Tp), nothrow)); __n * sizeof(_Tp), nothrow));
} }
#else #else
#if defined(__STDCPP_DEFAULT_NEW_ALIGNMENT__) if (__is_overaligned_for_new(__alignof(_Tp)))
if (std::alignment_of<_Tp>::value > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
#else
if (std::alignment_of<_Tp>::value >
std::alignment_of<std::max_align_t>::value)
#endif
{ {
// Since aligned operator new is unavailable, return an empty // Since aligned operator new is unavailable, return an empty
// buffer rather than one with invalid alignment. // buffer rather than one with invalid alignment.
@@ -2061,20 +2051,7 @@ template <class _Tp>
inline _LIBCPP_INLINE_VISIBILITY inline _LIBCPP_INLINE_VISIBILITY
void return_temporary_buffer(_Tp* __p) _NOEXCEPT void return_temporary_buffer(_Tp* __p) _NOEXCEPT
{ {
#if !defined(_LIBCPP_HAS_NO_ALIGNED_ALLOCATION) _VSTD::__libcpp_deallocate((void*)__p, __alignof(_Tp));
#if defined(__STDCPP_DEFAULT_NEW_ALIGNMENT__)
if (std::alignment_of<_Tp>::value > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
#else
if (std::alignment_of<_Tp>::value >
std::alignment_of<std::max_align_t>::value)
#endif
{
std::align_val_t __al = std::align_val_t(std::alignment_of<_Tp>::value);
::operator delete(__p, __al);
return;
}
#endif
::operator delete(__p);
} }
#if _LIBCPP_STD_VER <= 14 || defined(_LIBCPP_ENABLE_CXX17_REMOVED_AUTO_PTR) #if _LIBCPP_STD_VER <= 14 || defined(_LIBCPP_ENABLE_CXX17_REMOVED_AUTO_PTR)

View File

@@ -89,6 +89,7 @@ void operator delete[](void* ptr, void*) noexcept;
#include <__config> #include <__config>
#include <exception> #include <exception>
#include <type_traits>
#include <cstddef> #include <cstddef>
#ifdef _LIBCPP_NO_EXCEPTIONS #ifdef _LIBCPP_NO_EXCEPTIONS
#include <cstdlib> #include <cstdlib>
@@ -113,6 +114,14 @@ void operator delete[](void* ptr, void*) noexcept;
# define _LIBCPP_HAS_NO_ALIGNED_ALLOCATION # define _LIBCPP_HAS_NO_ALIGNED_ALLOCATION
#endif #endif
#if !__has_builtin(__builtin_operator_new) || \
__has_builtin(__builtin_operator_new) < 201802L || \
defined(_LIBCPP_HAS_NO_ALIGNED_ALLOCATION) || \
!defined(__cpp_aligned_new) || __cpp_aligned_new < 201606
#define _LIBCPP_HAS_NO_BUILTIN_ALIGNED_OPERATOR_NEW_DELETE
#endif
namespace std // purposefully not using versioning namespace namespace std // purposefully not using versioning namespace
{ {
@@ -223,7 +232,27 @@ inline _LIBCPP_INLINE_VISIBILITY void operator delete[](void*, void*) _NOEXCEPT
_LIBCPP_BEGIN_NAMESPACE_STD _LIBCPP_BEGIN_NAMESPACE_STD
inline _LIBCPP_INLINE_VISIBILITY void *__allocate(size_t __size) { _LIBCPP_CONSTEXPR inline _LIBCPP_INLINE_VISIBILITY bool __is_overaligned_for_new(size_t __align) _NOEXCEPT {
#ifdef __STDCPP_DEFAULT_NEW_ALIGNMENT__
return __align > __STDCPP_DEFAULT_NEW_ALIGNMENT__;
#else
return __align > alignment_of<max_align_t>::value;
#endif
}
inline _LIBCPP_INLINE_VISIBILITY void *__libcpp_allocate(size_t __size, size_t __align) {
#ifndef _LIBCPP_HAS_NO_ALIGNED_ALLOCATION
if (__is_overaligned_for_new(__align)) {
const align_val_t __align_val = static_cast<align_val_t>(__align);
# ifdef _LIBCPP_HAS_NO_BUILTIN_ALIGNED_OPERATOR_NEW_DELETE
return ::operator new(__size, __align_val);
# else
return __builtin_operator_new(__size, __align_val);
# endif
}
#else
((void)__align);
#endif
#ifdef _LIBCPP_HAS_NO_BUILTIN_OPERATOR_NEW_DELETE #ifdef _LIBCPP_HAS_NO_BUILTIN_OPERATOR_NEW_DELETE
return ::operator new(__size); return ::operator new(__size);
#else #else
@@ -231,11 +260,23 @@ inline _LIBCPP_INLINE_VISIBILITY void *__allocate(size_t __size) {
#endif #endif
} }
inline _LIBCPP_INLINE_VISIBILITY void __libcpp_deallocate(void *__ptr) { inline _LIBCPP_INLINE_VISIBILITY void __libcpp_deallocate(void* __ptr, size_t __align) {
#ifdef _LIBCPP_HAS_NO_BUILTIN_OPERATOR_NEW_DELETE #ifndef _LIBCPP_HAS_NO_ALIGNED_ALLOCATION
::operator delete(__ptr); if (__is_overaligned_for_new(__align)) {
const align_val_t __align_val = static_cast<align_val_t>(__align);
# ifdef _LIBCPP_HAS_NO_BUILTIN_ALIGNED_OPERATOR_NEW_DELETE
return ::operator delete(__ptr, __align_val);
# else # else
__builtin_operator_delete(__ptr); return __builtin_operator_delete(__ptr, __align_val);
# endif
}
#else
((void)__align);
#endif
#ifdef _LIBCPP_HAS_NO_BUILTIN_OPERATOR_NEW_DELETE
return ::operator delete(__ptr);
#else
return __builtin_operator_delete(__ptr);
#endif #endif
} }

View File

@@ -2738,7 +2738,8 @@ __val_expr<_ValExpr>::operator valarray<__val_expr::result_type>() const
{ {
__r.__begin_ = __r.__begin_ =
__r.__end_ = __r.__end_ =
static_cast<result_type*>(_VSTD::__allocate(__n * sizeof(result_type))); static_cast<result_type*>(
_VSTD::__libcpp_allocate(__n * sizeof(result_type), __alignof(result_type)));
for (size_t __i = 0; __i != __n; ++__r.__end_, ++__i) for (size_t __i = 0; __i != __n; ++__r.__end_, ++__i)
::new (__r.__end_) result_type(__expr_[__i]); ::new (__r.__end_) result_type(__expr_[__i]);
} }
@@ -2755,7 +2756,8 @@ valarray<_Tp>::valarray(size_t __n)
{ {
if (__n) if (__n)
{ {
__begin_ = __end_ = static_cast<value_type*>(_VSTD::__allocate(__n * sizeof(value_type))); __begin_ = __end_ = static_cast<value_type*>(
_VSTD::__libcpp_allocate(__n * sizeof(value_type), __alignof(value_type)));
#ifndef _LIBCPP_NO_EXCEPTIONS #ifndef _LIBCPP_NO_EXCEPTIONS
try try
{ {
@@ -2789,7 +2791,8 @@ valarray<_Tp>::valarray(const value_type* __p, size_t __n)
{ {
if (__n) if (__n)
{ {
__begin_ = __end_ = static_cast<value_type*>(_VSTD::__allocate(__n * sizeof(value_type))); __begin_ = __end_ = static_cast<value_type*>(
_VSTD::__libcpp_allocate(__n * sizeof(value_type), __alignof(value_type)));
#ifndef _LIBCPP_NO_EXCEPTIONS #ifndef _LIBCPP_NO_EXCEPTIONS
try try
{ {
@@ -2814,7 +2817,8 @@ valarray<_Tp>::valarray(const valarray& __v)
{ {
if (__v.size()) if (__v.size())
{ {
__begin_ = __end_ = static_cast<value_type*>(_VSTD::__allocate(__v.size() * sizeof(value_type))); __begin_ = __end_ = static_cast<value_type*>(
_VSTD::__libcpp_allocate(__v.size() * sizeof(value_type), __alignof(value_type)));
#ifndef _LIBCPP_NO_EXCEPTIONS #ifndef _LIBCPP_NO_EXCEPTIONS
try try
{ {
@@ -2851,7 +2855,8 @@ valarray<_Tp>::valarray(initializer_list<value_type> __il)
size_t __n = __il.size(); size_t __n = __il.size();
if (__n) if (__n)
{ {
__begin_ = __end_ = static_cast<value_type*>(_VSTD::__allocate(__n * sizeof(value_type))); __begin_ = __end_ = static_cast<value_type*>(
_VSTD::__libcpp_allocate(__n * sizeof(value_type), __alignof(value_type)));
#ifndef _LIBCPP_NO_EXCEPTIONS #ifndef _LIBCPP_NO_EXCEPTIONS
try try
{ {
@@ -2879,7 +2884,8 @@ valarray<_Tp>::valarray(const slice_array<value_type>& __sa)
size_t __n = __sa.__size_; size_t __n = __sa.__size_;
if (__n) if (__n)
{ {
__begin_ = __end_ = static_cast<value_type*>(_VSTD::__allocate(__n * sizeof(value_type))); __begin_ = __end_ = static_cast<value_type*>(
_VSTD::__libcpp_allocate(__n * sizeof(value_type), __alignof(value_type)));
#ifndef _LIBCPP_NO_EXCEPTIONS #ifndef _LIBCPP_NO_EXCEPTIONS
try try
{ {
@@ -2905,7 +2911,8 @@ valarray<_Tp>::valarray(const gslice_array<value_type>& __ga)
size_t __n = __ga.__1d_.size(); size_t __n = __ga.__1d_.size();
if (__n) if (__n)
{ {
__begin_ = __end_ = static_cast<value_type*>(_VSTD::__allocate(__n * sizeof(value_type))); __begin_ = __end_ = static_cast<value_type*>(
_VSTD::__libcpp_allocate(__n * sizeof(value_type), __alignof(value_type)));
#ifndef _LIBCPP_NO_EXCEPTIONS #ifndef _LIBCPP_NO_EXCEPTIONS
try try
{ {
@@ -2934,7 +2941,8 @@ valarray<_Tp>::valarray(const mask_array<value_type>& __ma)
size_t __n = __ma.__1d_.size(); size_t __n = __ma.__1d_.size();
if (__n) if (__n)
{ {
__begin_ = __end_ = static_cast<value_type*>(_VSTD::__allocate(__n * sizeof(value_type))); __begin_ = __end_ = static_cast<value_type*>(
_VSTD::__libcpp_allocate(__n * sizeof(value_type), __alignof(value_type)));
#ifndef _LIBCPP_NO_EXCEPTIONS #ifndef _LIBCPP_NO_EXCEPTIONS
try try
{ {
@@ -2963,7 +2971,8 @@ valarray<_Tp>::valarray(const indirect_array<value_type>& __ia)
size_t __n = __ia.__1d_.size(); size_t __n = __ia.__1d_.size();
if (__n) if (__n)
{ {
__begin_ = __end_ = static_cast<value_type*>(_VSTD::__allocate(__n * sizeof(value_type))); __begin_ = __end_ = static_cast<value_type*>(
_VSTD::__libcpp_allocate(__n * sizeof(value_type), __alignof(value_type)));
#ifndef _LIBCPP_NO_EXCEPTIONS #ifndef _LIBCPP_NO_EXCEPTIONS
try try
{ {
@@ -2999,7 +3008,8 @@ valarray<_Tp>::__assign_range(const value_type* __f, const value_type* __l)
if (size() != __n) if (size() != __n)
{ {
__clear(); __clear();
__begin_ = static_cast<value_type*>(_VSTD::__allocate(__n * sizeof(value_type))); __begin_ = static_cast<value_type*>(
_VSTD::__libcpp_allocate(__n * sizeof(value_type), __alignof(value_type)));
__end_ = __begin_ + __n; __end_ = __begin_ + __n;
_VSTD::uninitialized_copy(__f, __l, __begin_); _VSTD::uninitialized_copy(__f, __l, __begin_);
} else { } else {
@@ -3254,7 +3264,8 @@ valarray<_Tp>::operator+() const
{ {
__r.__begin_ = __r.__begin_ =
__r.__end_ = __r.__end_ =
static_cast<value_type*>(_VSTD::__allocate(__n * sizeof(value_type))); static_cast<value_type*>(
_VSTD::__libcpp_allocate(__n * sizeof(value_type), __alignof(value_type)));
for (const value_type* __p = __begin_; __n; ++__r.__end_, ++__p, --__n) for (const value_type* __p = __begin_; __n; ++__r.__end_, ++__p, --__n)
::new (__r.__end_) value_type(+*__p); ::new (__r.__end_) value_type(+*__p);
} }
@@ -3271,7 +3282,8 @@ valarray<_Tp>::operator-() const
{ {
__r.__begin_ = __r.__begin_ =
__r.__end_ = __r.__end_ =
static_cast<value_type*>(_VSTD::__allocate(__n * sizeof(value_type))); static_cast<value_type*>(
_VSTD::__libcpp_allocate(__n * sizeof(value_type), __alignof(value_type)));
for (const value_type* __p = __begin_; __n; ++__r.__end_, ++__p, --__n) for (const value_type* __p = __begin_; __n; ++__r.__end_, ++__p, --__n)
::new (__r.__end_) value_type(-*__p); ::new (__r.__end_) value_type(-*__p);
} }
@@ -3288,7 +3300,8 @@ valarray<_Tp>::operator~() const
{ {
__r.__begin_ = __r.__begin_ =
__r.__end_ = __r.__end_ =
static_cast<value_type*>(_VSTD::__allocate(__n * sizeof(value_type))); static_cast<value_type*>(
_VSTD::__libcpp_allocate(__n * sizeof(value_type), __alignof(value_type)));
for (const value_type* __p = __begin_; __n; ++__r.__end_, ++__p, --__n) for (const value_type* __p = __begin_; __n; ++__r.__end_, ++__p, --__n)
::new (__r.__end_) value_type(~*__p); ::new (__r.__end_) value_type(~*__p);
} }
@@ -3305,7 +3318,7 @@ valarray<_Tp>::operator!() const
{ {
__r.__begin_ = __r.__begin_ =
__r.__end_ = __r.__end_ =
static_cast<bool*>(_VSTD::__allocate(__n * sizeof(bool))); static_cast<bool*>(_VSTD::__libcpp_allocate(__n * sizeof(bool), __alignof(bool)));
for (const value_type* __p = __begin_; __n; ++__r.__end_, ++__p, --__n) for (const value_type* __p = __begin_; __n; ++__r.__end_, ++__p, --__n)
::new (__r.__end_) bool(!*__p); ::new (__r.__end_) bool(!*__p);
} }
@@ -3625,7 +3638,8 @@ valarray<_Tp>::shift(int __i) const
{ {
__r.__begin_ = __r.__begin_ =
__r.__end_ = __r.__end_ =
static_cast<value_type*>(_VSTD::__allocate(__n * sizeof(value_type))); static_cast<value_type*>(
_VSTD::__libcpp_allocate(__n * sizeof(value_type), __alignof(value_type)));
const value_type* __sb; const value_type* __sb;
value_type* __tb; value_type* __tb;
value_type* __te; value_type* __te;
@@ -3663,7 +3677,8 @@ valarray<_Tp>::cshift(int __i) const
{ {
__r.__begin_ = __r.__begin_ =
__r.__end_ = __r.__end_ =
static_cast<value_type*>(_VSTD::__allocate(__n * sizeof(value_type))); static_cast<value_type*>(
_VSTD::__libcpp_allocate(__n * sizeof(value_type), __alignof(value_type)));
__i %= static_cast<int>(__n); __i %= static_cast<int>(__n);
const value_type* __m = __i >= 0 ? __begin_ + __i : __end_ + __i; const value_type* __m = __i >= 0 ? __begin_ + __i : __end_ + __i;
for (const value_type* __s = __m; __s != __end_; ++__r.__end_, ++__s) for (const value_type* __s = __m; __s != __end_; ++__r.__end_, ++__s)
@@ -3684,7 +3699,8 @@ valarray<_Tp>::apply(value_type __f(value_type)) const
{ {
__r.__begin_ = __r.__begin_ =
__r.__end_ = __r.__end_ =
static_cast<value_type*>(_VSTD::__allocate(__n * sizeof(value_type))); static_cast<value_type*>(
_VSTD::__libcpp_allocate(__n * sizeof(value_type), __alignof(value_type)));
for (const value_type* __p = __begin_; __n; ++__r.__end_, ++__p, --__n) for (const value_type* __p = __begin_; __n; ++__r.__end_, ++__p, --__n)
::new (__r.__end_) value_type(__f(*__p)); ::new (__r.__end_) value_type(__f(*__p));
} }
@@ -3701,7 +3717,8 @@ valarray<_Tp>::apply(value_type __f(const value_type&)) const
{ {
__r.__begin_ = __r.__begin_ =
__r.__end_ = __r.__end_ =
static_cast<value_type*>(_VSTD::__allocate(__n * sizeof(value_type))); static_cast<value_type*>(
_VSTD::__libcpp_allocate(__n * sizeof(value_type), __alignof(value_type)));
for (const value_type* __p = __begin_; __n; ++__r.__end_, ++__p, --__n) for (const value_type* __p = __begin_; __n; ++__r.__end_, ++__p, --__n)
::new (__r.__end_) value_type(__f(*__p)); ::new (__r.__end_) value_type(__f(*__p));
} }
@@ -3716,7 +3733,7 @@ valarray<_Tp>::__clear()
{ {
while (__end_ != __begin_) while (__end_ != __begin_)
(--__end_)->~value_type(); (--__end_)->~value_type();
_VSTD::__libcpp_deallocate(__begin_); _VSTD::__libcpp_deallocate(__begin_, __alignof(value_type));
__begin_ = __end_ = nullptr; __begin_ = __end_ = nullptr;
} }
} }
@@ -3728,7 +3745,8 @@ valarray<_Tp>::resize(size_t __n, value_type __x)
__clear(); __clear();
if (__n) if (__n)
{ {
__begin_ = __end_ = static_cast<value_type*>(_VSTD::__allocate(__n * sizeof(value_type))); __begin_ = __end_ = static_cast<value_type*>(
_VSTD::__libcpp_allocate(__n * sizeof(value_type), __alignof(value_type)));
#ifndef _LIBCPP_NO_EXCEPTIONS #ifndef _LIBCPP_NO_EXCEPTIONS
try try
{ {

View File

@@ -31,10 +31,10 @@ public:
protected: protected:
virtual void* do_allocate(size_t __size, size_t __align) virtual void* do_allocate(size_t __size, size_t __align)
{ return __allocate(__size); } { return _VSTD::__libcpp_allocate(__size, __align); /* FIXME */}
virtual void do_deallocate(void * __p, size_t, size_t) virtual void do_deallocate(void * __p, size_t, size_t __align)
{ _VSTD::__libcpp_deallocate(__p); } { _VSTD::__libcpp_deallocate(__p, __align); /* FIXME */ }
virtual bool do_is_equal(memory_resource const & __other) const _NOEXCEPT virtual bool do_is_equal(memory_resource const & __other) const _NOEXCEPT
{ return &__other == this; } { return &__other == this; }

View File

@@ -15,39 +15,93 @@
#include <memory> #include <memory>
#include <cassert> #include <cassert>
#include "test_macros.h"
#include "count_new.hpp" #include "count_new.hpp"
int A_constructed = 0;
struct A #ifdef TEST_HAS_NO_ALIGNED_ALLOCATION
{ static const bool UsingAlignedNew = false;
int data; #else
A() {++A_constructed;} static const bool UsingAlignedNew = true;
A(const A&) {++A_constructed;} #endif
~A() {--A_constructed;}
#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()
{ template <size_t Align>
void test_aligned() {
typedef AlignedType<Align> T;
T::constructed = 0;
globalMemCounter.reset(); globalMemCounter.reset();
std::allocator<A> a; std::allocator<T> a;
const bool IsOverAlignedType = Align > MaxAligned;
const bool ExpectAligned = IsOverAlignedType && UsingAlignedNew;
{
assert(globalMemCounter.checkOutstandingNewEq(0)); assert(globalMemCounter.checkOutstandingNewEq(0));
assert(A_constructed == 0); assert(T::constructed == 0);
globalMemCounter.last_new_size = 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.checkOutstandingNewEq(1));
assert(globalMemCounter.checkLastNewSizeEq(3 * sizeof(int))); assert(globalMemCounter.checkNewCalledEq(1));
assert(A_constructed == 0); 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); a.deallocate(ap, 3);
assert(globalMemCounter.checkOutstandingNewEq(0)); assert(globalMemCounter.checkOutstandingNewEq(0));
assert(A_constructed == 0); assert(globalMemCounter.checkDeleteCalledEq(1));
assert(globalMemCounter.checkAlignedDeleteCalledEq(ExpectAligned));
globalMemCounter.last_new_size = 0; assert(globalMemCounter.checkLastDeleteAlignEq(ExpectAligned ? Align : 0));
A* volatile ap2 = a.allocate(3, (const void*)5); assert(T::constructed == 0);
assert(globalMemCounter.checkOutstandingNewEq(1)); }
assert(globalMemCounter.checkLastNewSizeEq(3 * sizeof(int))); globalMemCounter.reset();
assert(A_constructed == 0); {
a.deallocate(ap2, 3); globalMemCounter.last_new_size = 0;
assert(globalMemCounter.checkOutstandingNewEq(0)); globalMemCounter.last_new_align = 0;
assert(A_constructed == 0); T* volatile ap2 = a.allocate(11, (const void*)5);
assert(globalMemCounter.checkOutstandingNewEq(1));
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(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>();
} }

View File

@@ -59,12 +59,20 @@ public:
int outstanding_new; int outstanding_new;
int new_called; int new_called;
int delete_called; int delete_called;
int aligned_new_called;
int aligned_delete_called;
std::size_t last_new_size; std::size_t last_new_size;
std::size_t last_new_align;
std::size_t last_delete_align;
int outstanding_array_new; int outstanding_array_new;
int new_array_called; int new_array_called;
int delete_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_size;
std::size_t last_new_array_align;
std::size_t last_delete_array_align;
public: public:
void newCalled(std::size_t s) void newCalled(std::size_t s)
@@ -82,6 +90,12 @@ public:
last_new_size = s; 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) void deleteCalled(void * p)
{ {
assert(p); assert(p);
@@ -89,6 +103,12 @@ public:
++delete_called; ++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) void newArrayCalled(std::size_t s)
{ {
assert(disable_allocations == false); assert(disable_allocations == false);
@@ -104,6 +124,12 @@ public:
last_new_array_size = s; 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) void deleteArrayCalled(void * p)
{ {
assert(p); assert(p);
@@ -111,6 +137,12 @@ public:
++delete_array_called; ++delete_array_called;
} }
void alignedDeleteArrayCalled(void * p, std::size_t a) {
deleteArrayCalled(p);
++aligned_delete_array_called;
last_delete_array_align = a;
}
void disableAllocations() void disableAllocations()
{ {
disable_allocations = true; disable_allocations = true;
@@ -121,7 +153,6 @@ public:
disable_allocations = false; disable_allocations = false;
} }
void reset() void reset()
{ {
disable_allocations = false; disable_allocations = false;
@@ -130,12 +161,18 @@ public:
outstanding_new = 0; outstanding_new = 0;
new_called = 0; new_called = 0;
delete_called = 0; delete_called = 0;
aligned_new_called = 0;
aligned_delete_called = 0;
last_new_size = 0; last_new_size = 0;
last_new_align = 0;
outstanding_array_new = 0; outstanding_array_new = 0;
new_array_called = 0; new_array_called = 0;
delete_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_size = 0;
last_new_array_align = 0;
} }
public: public:
@@ -174,6 +211,31 @@ public:
return disable_checking || n != delete_called; 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 bool checkLastNewSizeEq(std::size_t n) const
{ {
return disable_checking || n == last_new_size; return disable_checking || n == last_new_size;
@@ -184,6 +246,26 @@ public:
return disable_checking || n != last_new_size; 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 bool checkOutstandingArrayNewEq(int n) const
{ {
return disable_checking || n == outstanding_array_new; return disable_checking || n == outstanding_array_new;
@@ -214,6 +296,31 @@ public:
return disable_checking || n != delete_array_called; 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 bool checkLastNewArraySizeEq(std::size_t n) const
{ {
return disable_checking || n == last_new_array_size; return disable_checking || n == last_new_array_size;
@@ -223,6 +330,16 @@ public:
{ {
return disable_checking || n != last_new_array_size; 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 #ifdef DISABLE_NEW_COUNT
@@ -254,22 +371,65 @@ void operator delete(void* p) TEST_NOEXCEPT
std::free(p); std::free(p);
} }
void* operator new[](std::size_t s) TEST_THROW_SPEC(std::bad_alloc) void* operator new[](std::size_t s) TEST_THROW_SPEC(std::bad_alloc)
{ {
getGlobalMemCounter()->newArrayCalled(s); getGlobalMemCounter()->newArrayCalled(s);
return operator new(s); return operator new(s);
} }
void operator delete[](void* p) TEST_NOEXCEPT void operator delete[](void* p) TEST_NOEXCEPT
{ {
getGlobalMemCounter()->deleteArrayCalled(p); getGlobalMemCounter()->deleteArrayCalled(p);
operator delete(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 { struct DisableAllocationGuard {
explicit DisableAllocationGuard(bool disable = true) : m_disabled(disable) explicit DisableAllocationGuard(bool disable = true) : m_disabled(disable)
@@ -295,7 +455,6 @@ private:
DisableAllocationGuard& operator=(DisableAllocationGuard const&); DisableAllocationGuard& operator=(DisableAllocationGuard const&);
}; };
struct RequireAllocationGuard { struct RequireAllocationGuard {
explicit RequireAllocationGuard(std::size_t RequireAtLeast = 1) explicit RequireAllocationGuard(std::size_t RequireAtLeast = 1)
: m_req_alloc(RequireAtLeast), : m_req_alloc(RequireAtLeast),

View File

@@ -157,6 +157,11 @@
#define TEST_NORETURN [[noreturn]] #define TEST_NORETURN [[noreturn]]
#endif #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) #if defined(_LIBCPP_SAFE_STATIC)
#define TEST_SAFE_STATIC _LIBCPP_SAFE_STATIC #define TEST_SAFE_STATIC _LIBCPP_SAFE_STATIC
#else #else
@@ -228,6 +233,7 @@ inline void DoNotOptimize(Tp const& value) {
} }
#endif #endif
#if defined(__GNUC__) #if defined(__GNUC__)
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#endif #endif