}
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 __n)
{
if (__p == (pointer)&buf_)
__allocated_ = false;
else
- _VSTD::__libcpp_deallocate(__p, __alignof(_Tp));
+ _VSTD::__libcpp_deallocate(__p, __n * sizeof(_Tp), __alignof(_Tp));
}
_LIBCPP_INLINE_VISIBILITY size_type max_size() const throw() {return size_type(~0) / sizeof(_Tp);}
}
static inline _LIBCPP_INLINE_VISIBILITY
- void __deallocate_value(value_type* __ptr ) noexcept {
- _VSTD::__libcpp_deallocate(static_cast<void *>(__ptr), __alignof(value_type));
+ void __deallocate_value(value_type* __ptr, size_t __count) noexcept {
+ _VSTD::__libcpp_deallocate(static_cast<void *>(__ptr), sizeof(value_type) * __count, __alignof(value_type));
}
public:
value_type *__data = data () + __size_;
for ( size_t i = 0; i < __size_; ++i )
(--__data)->value_type::~value_type();
- __deallocate_value( __base_ );
+ __deallocate_value(__base_, __size_);
}
template <class _Tp>
" 'n' exceeds maximum supported size");
return static_cast<pointer>(_VSTD::__libcpp_allocate(__n * sizeof(_Tp), __alignof(_Tp)));
}
- _LIBCPP_INLINE_VISIBILITY void deallocate(pointer __p, size_type) _NOEXCEPT
- {_VSTD::__libcpp_deallocate((void*)__p, __alignof(_Tp));}
+ _LIBCPP_INLINE_VISIBILITY void deallocate(pointer __p, size_type __n) _NOEXCEPT
+ {_VSTD::__libcpp_deallocate((void*)__p, __n * sizeof(_Tp), __alignof(_Tp));}
_LIBCPP_INLINE_VISIBILITY size_type max_size() const _NOEXCEPT
{return size_type(~0) / sizeof(_Tp);}
#if !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) && !defined(_LIBCPP_HAS_NO_VARIADICS)
" 'n' exceeds maximum supported size");
return static_cast<pointer>(_VSTD::__libcpp_allocate(__n * sizeof(_Tp), __alignof(_Tp)));
}
- _LIBCPP_INLINE_VISIBILITY void deallocate(pointer __p, size_type) _NOEXCEPT
- {_VSTD::__libcpp_deallocate((void*) const_cast<_Tp *>(__p), __alignof(_Tp));}
+ _LIBCPP_INLINE_VISIBILITY void deallocate(pointer __p, size_type __n) _NOEXCEPT
+ {_VSTD::__libcpp_deallocate((void*) const_cast<_Tp *>(__p), __n * sizeof(_Tp), __alignof(_Tp));}
_LIBCPP_INLINE_VISIBILITY size_type max_size() const _NOEXCEPT
{return size_type(~0) / sizeof(_Tp);}
#if !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) && !defined(_LIBCPP_HAS_NO_VARIADICS)
inline _LIBCPP_INLINE_VISIBILITY
void return_temporary_buffer(_Tp* __p) _NOEXCEPT
{
- _VSTD::__libcpp_deallocate((void*)__p, __alignof(_Tp));
+ _VSTD::__libcpp_deallocate_unsized((void*)__p, __alignof(_Tp));
}
#if _LIBCPP_STD_VER <= 14 || defined(_LIBCPP_ENABLE_CXX17_REMOVED_AUTO_PTR)
#pragma GCC system_header
#endif
-#if !defined(_LIBCPP_BUILDING_LIBRARY) && _LIBCPP_STD_VER < 14
+#if !defined(__cpp_sized_deallocation) || __cpp_sized_deallocation < 201309L
+#define _LIBCPP_HAS_NO_LANGUAGE_SIZED_DEALLOCATION
+#endif
+
+#if !defined(_LIBCPP_BUILDING_LIBRARY) && _LIBCPP_STD_VER < 14 && \
+ defined(_LIBCPP_HAS_NO_LANGUAGE_SIZED_DEALLOCATION)
# define _LIBCPP_HAS_NO_LIBRARY_SIZED_DEALLOCATION
#endif
#if defined(_LIBCPP_HAS_NO_LIBRARY_SIZED_DEALLOCATION) || \
- !defined(__cpp_sized_deallocation) || __cpp_sized_deallocation < 201309
+ defined(_LIBCPP_HAS_NO_LANGUAGE_SIZED_DEALLOCATION)
# define _LIBCPP_HAS_NO_SIZED_DEALLOCATION
#endif
#endif
}
-inline _LIBCPP_INLINE_VISIBILITY void __libcpp_deallocate(void* __ptr, size_t __align) {
+struct _DeallocateCaller {
+ static inline _LIBCPP_INLINE_VISIBILITY
+ void __do_deallocate_handle_size_align(void *__ptr, size_t __size, size_t __align) {
+#if defined(_LIBCPP_HAS_NO_ALIGNED_ALLOCATION)
+ ((void)__align);
+ return __do_deallocate_handle_size(__ptr, __size);
+#else
+ if (__is_overaligned_for_new(__align)) {
+ const align_val_t __align_val = static_cast<align_val_t>(__align);
+ return __do_deallocate_handle_size(__ptr, __size, __align_val);
+ } else {
+ return __do_deallocate_handle_size(__ptr, __size);
+ }
+#endif
+ }
+
+ static inline _LIBCPP_INLINE_VISIBILITY
+ void __do_deallocate_handle_align(void *__ptr, size_t __align) {
+#if defined(_LIBCPP_HAS_NO_ALIGNED_ALLOCATION)
+ ((void)__align);
+ return __do_call(__ptr);
+#else
+ if (__is_overaligned_for_new(__align)) {
+ const align_val_t __align_val = static_cast<align_val_t>(__align);
+ return __do_call(__ptr, __align_val);
+ } else {
+ return __do_call(__ptr);
+ }
+#endif
+ }
+
+ private:
+ static inline void __do_deallocate_handle_size(void *__ptr, size_t __size) {
+#ifdef _LIBCPP_HAS_NO_SIZED_DEALLOCATION
+ ((void)__size);
+ return __do_call(__ptr);
+#else
+ return __do_call(__ptr, __size);
+#endif
+ }
+
#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_OVERLOADED_OPERATOR_NEW_DELETE
- return ::operator delete(__ptr, __align_val);
-# else
- return __builtin_operator_delete(__ptr, __align_val);
-# endif
+ static inline void __do_deallocate_handle_size(void *__ptr, size_t __size, align_val_t __align) {
+#ifdef _LIBCPP_HAS_NO_SIZED_DEALLOCATION
+ ((void)__size);
+ return __do_call(__ptr, __align);
+#else
+ return __do_call(__ptr, __size, __align);
+#endif
}
+#endif
+
+private:
+ template <class _A1, class _A2>
+ static inline void __do_call(void *__ptr, _A1 __a1, _A2 __a2) {
+#if defined(_LIBCPP_HAS_NO_BUILTIN_OPERATOR_NEW_DELETE) || \
+ defined(_LIBCPP_HAS_NO_BUILTIN_OVERLOADED_OPERATOR_NEW_DELETE)
+ return ::operator delete(__ptr, __a1, __a2);
#else
- ((void)__align);
+ return __builtin_operator_delete(__ptr, __a1, __a2);
#endif
+ }
+
+ template <class _A1>
+ static inline void __do_call(void *__ptr, _A1 __a1) {
+#if defined(_LIBCPP_HAS_NO_BUILTIN_OPERATOR_NEW_DELETE) || \
+ defined(_LIBCPP_HAS_NO_BUILTIN_OVERLOADED_OPERATOR_NEW_DELETE)
+ return ::operator delete(__ptr, __a1);
+#else
+ return __builtin_operator_delete(__ptr, __a1);
+#endif
+ }
+
+ static inline void __do_call(void *__ptr) {
#ifdef _LIBCPP_HAS_NO_BUILTIN_OPERATOR_NEW_DELETE
- return ::operator delete(__ptr);
+ return ::operator delete(__ptr);
#else
- return __builtin_operator_delete(__ptr);
+ return __builtin_operator_delete(__ptr);
#endif
+ }
+};
+
+inline _LIBCPP_INLINE_VISIBILITY void __libcpp_deallocate(void* __ptr, size_t __size, size_t __align) {
+ _DeallocateCaller::__do_deallocate_handle_size_align(__ptr, __size, __align);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY void __libcpp_deallocate_unsized(void* __ptr, size_t __align) {
+ _DeallocateCaller::__do_deallocate_handle_align(__ptr, __align);
}
#ifdef _LIBCPP_BAD_ARRAY_LENGTH_DEFINED
const _Up*
end(const valarray<_Up>& __v);
- void __clear();
+ void __clear(size_t __capacity);
valarray& __assign_range(const value_type* __f, const value_type* __l);
};
try
{
#endif // _LIBCPP_NO_EXCEPTIONS
- for (; __n; --__n, ++__end_)
+ for (size_t __n_left = __n; __n_left; --__n_left, ++__end_)
::new (__end_) value_type();
#ifndef _LIBCPP_NO_EXCEPTIONS
}
catch (...)
{
- __clear();
+ __clear(__n);
throw;
}
#endif // _LIBCPP_NO_EXCEPTIONS
try
{
#endif // _LIBCPP_NO_EXCEPTIONS
- for (; __n; ++__end_, ++__p, --__n)
+ for (size_t __n_left = __n; __n_left; ++__end_, ++__p, --__n_left)
::new (__end_) value_type(*__p);
#ifndef _LIBCPP_NO_EXCEPTIONS
}
catch (...)
{
- __clear();
+ __clear(__n);
throw;
}
#endif // _LIBCPP_NO_EXCEPTIONS
}
catch (...)
{
- __clear();
+ __clear(__v.size());
throw;
}
#endif // _LIBCPP_NO_EXCEPTIONS
: __begin_(0),
__end_(0)
{
- size_t __n = __il.size();
+ const size_t __n = __il.size();
if (__n)
{
__begin_ = __end_ = static_cast<value_type*>(
try
{
#endif // _LIBCPP_NO_EXCEPTIONS
- for (const value_type* __p = __il.begin(); __n; ++__end_, ++__p, --__n)
+ size_t __n_left = __n;
+ for (const value_type* __p = __il.begin(); __n_left; ++__end_, ++__p, --__n_left)
::new (__end_) value_type(*__p);
#ifndef _LIBCPP_NO_EXCEPTIONS
}
catch (...)
{
- __clear();
+ __clear(__n);
throw;
}
#endif // _LIBCPP_NO_EXCEPTIONS
: __begin_(0),
__end_(0)
{
- size_t __n = __sa.__size_;
+ const size_t __n = __sa.__size_;
if (__n)
{
__begin_ = __end_ = static_cast<value_type*>(
try
{
#endif // _LIBCPP_NO_EXCEPTIONS
- for (const value_type* __p = __sa.__vp_; __n; ++__end_, __p += __sa.__stride_, --__n)
+ size_t __n_left = __n;
+ for (const value_type* __p = __sa.__vp_; __n_left; ++__end_, __p += __sa.__stride_, --__n_left)
::new (__end_) value_type(*__p);
#ifndef _LIBCPP_NO_EXCEPTIONS
}
catch (...)
{
- __clear();
+ __clear(__n);
throw;
}
#endif // _LIBCPP_NO_EXCEPTIONS
: __begin_(0),
__end_(0)
{
- size_t __n = __ga.__1d_.size();
+ const size_t __n = __ga.__1d_.size();
if (__n)
{
__begin_ = __end_ = static_cast<value_type*>(
}
catch (...)
{
- __clear();
+ __clear(__n);
throw;
}
#endif // _LIBCPP_NO_EXCEPTIONS
: __begin_(0),
__end_(0)
{
- size_t __n = __ma.__1d_.size();
+ const size_t __n = __ma.__1d_.size();
if (__n)
{
__begin_ = __end_ = static_cast<value_type*>(
}
catch (...)
{
- __clear();
+ __clear(__n);
throw;
}
#endif // _LIBCPP_NO_EXCEPTIONS
: __begin_(0),
__end_(0)
{
- size_t __n = __ia.__1d_.size();
+ const size_t __n = __ia.__1d_.size();
if (__n)
{
__begin_ = __end_ = static_cast<value_type*>(
}
catch (...)
{
- __clear();
+ __clear(__n);
throw;
}
#endif // _LIBCPP_NO_EXCEPTIONS
inline
valarray<_Tp>::~valarray()
{
- __clear();
+ __clear(size());
}
template <class _Tp>
size_t __n = __l - __f;
if (size() != __n)
{
- __clear();
+ __clear(size());
__begin_ = static_cast<value_type*>(
_VSTD::__libcpp_allocate(__n * sizeof(value_type), __alignof(value_type)));
__end_ = __begin_ + __n;
valarray<_Tp>&
valarray<_Tp>::operator=(valarray&& __v) _NOEXCEPT
{
- __clear();
+ __clear(size());
__begin_ = __v.__begin_;
__end_ = __v.__end_;
__v.__begin_ = nullptr;
}
template <class _Tp>
-void
-valarray<_Tp>::__clear()
+inline _LIBCPP_INLINE_VISIBILITY
+void valarray<_Tp>::__clear(size_t __capacity)
{
- if (__begin_ != nullptr)
- {
- while (__end_ != __begin_)
- (--__end_)->~value_type();
- _VSTD::__libcpp_deallocate(__begin_, __alignof(value_type));
- __begin_ = __end_ = nullptr;
- }
+ if (__begin_ != nullptr)
+ {
+ while (__end_ != __begin_)
+ (--__end_)->~value_type();
+ _VSTD::__libcpp_deallocate(__begin_, __capacity * sizeof(value_type), __alignof(value_type));
+ __begin_ = __end_ = nullptr;
+ }
}
template <class _Tp>
void
valarray<_Tp>::resize(size_t __n, value_type __x)
{
- __clear();
+ __clear(size());
if (__n)
{
__begin_ = __end_ = static_cast<value_type*>(
try
{
#endif // _LIBCPP_NO_EXCEPTIONS
- for (; __n; --__n, ++__end_)
+ for (size_t __n_left = __n; __n_left; --__n_left, ++__end_)
::new (__end_) value_type(__x);
#ifndef _LIBCPP_NO_EXCEPTIONS
}
catch (...)
{
- __clear();
+ __clear(__n);
throw;
}
#endif // _LIBCPP_NO_EXCEPTIONS
virtual void* do_allocate(size_t __size, size_t __align)
{ return _VSTD::__libcpp_allocate(__size, __align); /* FIXME */}
- virtual void do_deallocate(void * __p, size_t, size_t __align)
- { _VSTD::__libcpp_deallocate(__p, __align); /* FIXME */ }
+ virtual void do_deallocate(void* __p, size_t __n, size_t __align) {
+ _VSTD::__libcpp_deallocate(__p, __n, __align); /* FIXME */
+ }
virtual bool do_is_equal(memory_resource const & __other) const _NOEXCEPT
{ return &__other == this; }
--- /dev/null
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// test libc++'s implementation of align_val_t, and the relevent 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
+
+// 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.7
+// XFAIL: with_system_cxx_lib=macosx10.8
+
+// XFAIL: sanitizer-new-delete, ubsan
+
+// 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() {
+ test_libcpp_dealloc();
+ test_allocator_and_new_match();
+}