Index: CMakeLists.txt =================================================================== --- CMakeLists.txt +++ CMakeLists.txt @@ -275,6 +275,10 @@ add_definitions(-DLIBCXXABI_HAS_NO_THREADS=1) endif() +if (NOT LIBCXXABI_HAS_POSIX_MEMALIGN) + add_definitions(-DLIBCXXABI_HAS_NO_POSIX_MEMALIGN=1) +endif() + # This is the _ONLY_ place where add_definitions is called. if (MSVC) add_definitions(-D_CRT_SECURE_NO_WARNINGS) Index: cmake/config-ix.cmake =================================================================== --- cmake/config-ix.cmake +++ cmake/config-ix.cmake @@ -1,6 +1,7 @@ include(CheckLibraryExists) include(CheckCCompilerFlag) include(CheckCXXCompilerFlag) +include(CheckSymbolExists) # Check compiler flags check_c_compiler_flag(-funwind-tables LIBCXXABI_HAS_FUNWIND_TABLES) @@ -45,3 +46,6 @@ check_library_exists(gcc_eh _Unwind_GetRegionStart "" LIBCXXABI_HAS_GCC_EH_LIB) check_library_exists(c __cxa_thread_atexit_impl "" LIBCXXABI_HAS_CXA_THREAD_ATEXIT_IMPL) + +# Check symbols +check_symbol_exists(posix_memalign stdlib.h LIBCXXABI_HAS_POSIX_MEMALIGN) Index: src/cxa_exception.cpp =================================================================== --- src/cxa_exception.cpp +++ src/cxa_exception.cpp @@ -118,13 +118,22 @@ // Allocate some memory from _somewhere_ static void *do_malloc(size_t size) { - void *ptr = std::malloc(size); + void* ptr = nullptr; +#ifndef LIBCXXABI_HAS_NO_POSIX_MEMALIGN + (void)posix_memalign(&ptr, alignof(__cxa_exception), size); +#else + // FIXME: The output of malloc needs to be manually aligned to a 16 byte + // on 32 bit targets. + ptr = std::malloc(size); +#endif if (NULL == ptr) // if malloc fails, fall back to emergency stash ptr = fallback_malloc(size); return ptr; } static void do_free(void *ptr) { + // NOTE: std::free can free pointers allocated with both std::malloc + // and posix_memalign. is_fallback_ptr(ptr) ? fallback_free(ptr) : std::free(ptr); } Index: test/test_cxa_allocate_exception.pass.cpp =================================================================== --- /dev/null +++ test/test_cxa_allocate_exception.pass.cpp @@ -0,0 +1,65 @@ +//===--------------------- test_fallback_malloc.cpp -----------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// +// +// UNSUPPORTED: c++98, c++03 + +// void* __cxa_allocate_exception(size_t); +// void __cxa_free_exception(void*); +// void* __cxa_allocate_dependent_exception(); +// void __cxa_free_dependent_exception(); + +// __cxa_exception is specified with __attribute__((aligned)) for GNU unwind. +// This means that during 32 bit builds __cxa_exception is "over aligned". This +// test checks that __cxa_allocate_exception return correctly overaligned memory. +// See PR24604 - https://llvm.org/bugs/show_bug.cgi?id=24604 + +#include "../src/cxa_exception.hpp" +#include // for std::max_align_t +#include + +#if defined(__GNUC__) && !defined(_LP64) +#define SHOULD_BE_OVERALIGNED 1 +#endif + +using namespace __cxxabiv1; + +const std::size_t max_alignment = alignof(std::max_align_t); +const std::size_t required_alignment = alignof(__cxa_exception); +const bool requires_over_alignment = max_alignment < required_alignment; + +static_assert(alignof(__cxa_exception) == alignof(__cxa_dependent_exception), + "They should have the same alignment requirements"); + +#if defined(__GNUC__) && !defined(_LP64) +static_assert(alignof(__cxa_exception) > alignof(std::max_align_t), + "On 32 bit platforms __cxa_exception is expected to be over aligned."); +#endif + +void test_cxa_allocate_exception() { + for (int i=0; i < 4096; ++i) { + void* ptr = __cxa_allocate_exception(i); + assert(ptr); + assert(reinterpret_cast(ptr) % required_alignment == 0); + __cxa_free_exception(ptr); + } +} + +void test_cxa_allocate_dependent_exception() { + for (int i=0; i < 100; ++i) { + void* ptr = __cxa_allocate_dependent_exception(); + assert(ptr); + assert(reinterpret_cast(ptr) % required_alignment == 0); + __cxa_free_dependent_exception(ptr); + } +} + +int main() { + test_cxa_allocate_exception(); + test_cxa_allocate_dependent_exception(); +}