diff --git a/libcxx/include/new b/libcxx/include/new --- a/libcxx/include/new +++ b/libcxx/include/new @@ -88,13 +88,11 @@ #include <__config> #include <__availability> +#include +#include #include #include -#include #include -#ifdef _LIBCPP_NO_EXCEPTIONS -#include -#endif #if defined(_LIBCPP_ABI_VCRUNTIME) #include @@ -303,6 +301,34 @@ #endif } +// Low-level helpers to call the aligned allocation and deallocation functions +// on the target platform. This is used to implement libc++'s own memory +// allocation routines -- if you need to allocate memory inside the library, +// chances are that you want to use `__libcpp_allocate` instead. +// +// Returns the allocated memory, or `nullptr` on failure. +inline _LIBCPP_INLINE_VISIBILITY +void* __libcpp_aligned_alloc(std::size_t __alignment, std::size_t __size) { +#if defined(_LIBCPP_MSVCRT_LIKE) + return ::_aligned_malloc(__size, __alignment); +#else + void* __result = nullptr; + ::posix_memalign(&__result, __alignment, __size); + // If posix_memalign fails, __result is unmodified so we still return `nullptr`. + return __result; +#endif +} + +inline _LIBCPP_INLINE_VISIBILITY +void __libcpp_aligned_free(void* __ptr) { +#if defined(_LIBCPP_MSVCRT_LIKE) + ::_aligned_free(__ptr); +#else + ::free(__ptr); +#endif +} + + template _LIBCPP_NODISCARD_AFTER_CXX17 inline _LIBCPP_CONSTEXPR _Tp* __launder(_Tp* __p) _NOEXCEPT diff --git a/libcxx/src/new.cpp b/libcxx/src/new.cpp --- a/libcxx/src/new.cpp +++ b/libcxx/src/new.cpp @@ -179,15 +179,16 @@ size = 1; if (static_cast(alignment) < sizeof(void*)) alignment = std::align_val_t(sizeof(void*)); + + // Try allocating memory. If allocation fails and there is a new_handler, + // call it to try free up memory, and try again until it succeeds, or until + // the new_handler decides to terminate. + // + // If allocation fails and there is no new_handler, we throw bad_alloc + // (or return nullptr if exceptions are disabled). void* p; -#if defined(_LIBCPP_MSVCRT_LIKE) - while ((p = _aligned_malloc(size, static_cast(alignment))) == nullptr) -#else - while (::posix_memalign(&p, static_cast(alignment), size) != 0) -#endif + while ((p = std::__libcpp_aligned_alloc(static_cast(alignment), size)) == nullptr) { - // If posix_memalign fails and there is a new_handler, - // call it to try free up memory. std::new_handler nh = std::get_new_handler(); if (nh) nh(); @@ -195,7 +196,6 @@ #ifndef _LIBCPP_NO_EXCEPTIONS throw std::bad_alloc(); #else - p = nullptr; // posix_memalign doesn't initialize 'p' on failure break; #endif } @@ -252,12 +252,9 @@ void operator delete(void* ptr, std::align_val_t) _NOEXCEPT { - if (ptr) -#if defined(_LIBCPP_MSVCRT_LIKE) - ::_aligned_free(ptr); -#else - ::free(ptr); -#endif + if (ptr) { + std::__libcpp_aligned_free(ptr); + } } _LIBCPP_WEAK diff --git a/libcxxabi/src/fallback_malloc.cpp b/libcxxabi/src/fallback_malloc.cpp --- a/libcxxabi/src/fallback_malloc.cpp +++ b/libcxxabi/src/fallback_malloc.cpp @@ -17,6 +17,7 @@ #include // for malloc, calloc, free #include // for memset +#include // for std::__libcpp_aligned_{alloc,free} // A small, simple heap manager based (loosely) on // the startup heap manager from FreeBSD, optimized for space. @@ -204,7 +205,7 @@ void* __aligned_malloc_with_fallback(size_t size) { #if defined(_WIN32) - if (void* dest = _aligned_malloc(size, alignof(__aligned_type))) + if (void* dest = std::__libcpp_aligned_alloc(alignof(__aligned_type), size)) return dest; #elif defined(_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION) if (void* dest = ::malloc(size)) @@ -212,8 +213,7 @@ #else if (size == 0) size = 1; - void* dest; - if (::posix_memalign(&dest, __alignof(__aligned_type), size) == 0) + if (void* dest = std::__libcpp_aligned_alloc(__alignof(__aligned_type), size)) return dest; #endif return fallback_malloc(size); @@ -234,11 +234,7 @@ if (is_fallback_ptr(ptr)) fallback_free(ptr); else { -#if defined(_WIN32) - ::_aligned_free(ptr); -#else - ::free(ptr); -#endif + std::__libcpp_aligned_free(ptr); } } diff --git a/libcxxabi/src/stdlib_new_delete.cpp b/libcxxabi/src/stdlib_new_delete.cpp --- a/libcxxabi/src/stdlib_new_delete.cpp +++ b/libcxxabi/src/stdlib_new_delete.cpp @@ -142,15 +142,16 @@ size = 1; if (static_cast(alignment) < sizeof(void*)) alignment = std::align_val_t(sizeof(void*)); + + // Try allocating memory. If allocation fails and there is a new_handler, + // call it to try free up memory, and try again until it succeeds, or until + // the new_handler decides to terminate. + // + // If allocation fails and there is no new_handler, we throw bad_alloc + // (or return nullptr if exceptions are disabled). void* p; -#if defined(_LIBCPP_WIN32API) - while ((p = _aligned_malloc(size, static_cast(alignment))) == nullptr) -#else - while (::posix_memalign(&p, static_cast(alignment), size) != 0) -#endif + while ((p = std::__libcpp_aligned_alloc(static_cast(alignment), size)) == nullptr) { - // If posix_memalign fails and there is a new_handler, - // call it to try free up memory. std::new_handler nh = std::get_new_handler(); if (nh) nh(); @@ -158,7 +159,6 @@ #ifndef _LIBCXXABI_NO_EXCEPTIONS throw std::bad_alloc(); #else - p = nullptr; // posix_memalign doesn't initialize 'p' on failure break; #endif } @@ -215,12 +215,9 @@ void operator delete(void* ptr, std::align_val_t) _NOEXCEPT { - if (ptr) -#if defined(_LIBCPP_WIN32API) - ::_aligned_free(ptr); -#else - ::free(ptr); -#endif + if (ptr) { + std::__libcpp_aligned_free(ptr); + } } _LIBCXXABI_WEAK