Index: src/cxa_exception.cpp =================================================================== --- src/cxa_exception.cpp +++ src/cxa_exception.cpp @@ -63,12 +63,16 @@ return cxa_exception_from_thrown_object(unwind_exception + 1 ); } -static -inline -size_t -cxa_exception_size_from_exception_thrown_size(size_t size) -{ - return size + sizeof (__cxa_exception); +// Round s up to next multiple of a. +static inline +size_t aligned_allocation_size(size_t s, size_t a) { + return (s + a - 1) & ~(a - 1); +} + +static inline +size_t cxa_exception_size_from_exception_thrown_size(size_t size) { + return aligned_allocation_size(size + sizeof (__cxa_exception), + alignof(__cxa_exception)); } static void setExceptionClass(_Unwind_Exception* unwind_exception) { @@ -140,7 +144,7 @@ void *__cxa_allocate_exception(size_t thrown_size) throw() { size_t actual_size = cxa_exception_size_from_exception_thrown_size(thrown_size); __cxa_exception *exception_header = - static_cast<__cxa_exception *>(__malloc_with_fallback(actual_size)); + static_cast<__cxa_exception *>(__aligned_malloc_with_fallback(actual_size)); if (NULL == exception_header) std::terminate(); std::memset(exception_header, 0, actual_size); @@ -150,7 +154,7 @@ // Free a __cxa_exception object allocated with __cxa_allocate_exception. void __cxa_free_exception(void *thrown_object) throw() { - __free_with_fallback(cxa_exception_from_thrown_object(thrown_object)); + __aligned_free_with_fallback(cxa_exception_from_thrown_object(thrown_object)); } @@ -159,7 +163,7 @@ // Otherwise, it will work like __cxa_allocate_exception. void * __cxa_allocate_dependent_exception () { size_t actual_size = sizeof(__cxa_dependent_exception); - void *ptr = __malloc_with_fallback(actual_size); + void *ptr = __aligned_malloc_with_fallback(actual_size); if (NULL == ptr) std::terminate(); std::memset(ptr, 0, actual_size); @@ -170,7 +174,7 @@ // This function shall free a dependent_exception. // It does not affect the reference count of the primary exception. void __cxa_free_dependent_exception (void * dependent_exception) { - __free_with_fallback(dependent_exception); + __aligned_free_with_fallback(dependent_exception); } Index: src/fallback_malloc.h =================================================================== --- src/fallback_malloc.h +++ src/fallback_malloc.h @@ -16,11 +16,12 @@ namespace __cxxabiv1 { // Allocate some memory from _somewhere_ -_LIBCXXABI_HIDDEN void * __malloc_with_fallback(size_t size); +_LIBCXXABI_HIDDEN void * __aligned_malloc_with_fallback(size_t size); // Allocate and zero-initialize memory from _somewhere_ _LIBCXXABI_HIDDEN void * __calloc_with_fallback(size_t count, size_t size); +_LIBCXXABI_HIDDEN void __aligned_free_with_fallback(void *ptr); _LIBCXXABI_HIDDEN void __free_with_fallback(void *ptr); } // namespace __cxxabiv1 Index: src/fallback_malloc.cpp =================================================================== --- src/fallback_malloc.cpp +++ src/fallback_malloc.cpp @@ -194,13 +194,26 @@ namespace __cxxabiv1 { -void * __malloc_with_fallback(size_t size) { - void *ptr = std::malloc(size); - if (NULL == ptr) // if malloc fails, fall back to emergency stash - ptr = fallback_malloc(size); - return ptr; +struct __attribute__((aligned)) __aligned_type {}; + +void * __aligned_malloc_with_fallback(size_t size) { +#if defined(_WIN32) + if (void *dest = _aligned_malloc(size, alignof(__aligned_type))) + return dest; +#elif defined(_LIBCPP_HAS_NO_ALIGNED_ALLOCATION) + if (void* dest = std::malloc(size)) + return dest; +#else + if (size == 0) + size = 1; + void* dest; + if (::posix_memalign(&dest, alignof(__aligned_type), size) == 0) + return dest; +#endif + return fallback_malloc(size); } + void * __calloc_with_fallback(size_t count, size_t size) { void *ptr = std::calloc(count, size); if (NULL != ptr) @@ -212,6 +225,18 @@ return ptr; } +void __aligned_free_with_fallback(void* ptr) { + if (is_fallback_ptr(ptr)) + fallback_free(ptr); + else { +#if defined(_WIN32) + ::_aligned_free(ptr); +#else + std::free(ptr); +#endif + } +} + void __free_with_fallback(void *ptr) { if (is_fallback_ptr(ptr)) fallback_free(ptr); Index: test/test_exception_address_alignment.pass.cpp =================================================================== --- /dev/null +++ test/test_exception_address_alignment.pass.cpp @@ -0,0 +1,28 @@ +//===----------------------------------------------------------------------===// +// +// 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 that the address of the exception object is properly aligned to the +// largest supported alignment for the system. + +#include +#include + +struct __attribute__((aligned)) AlignedType {}; +struct MinAligned { }; +static_assert(alignof(MinAligned) == 1 && sizeof(MinAligned) == 1, ""); + +int main() { + for (int i=0; i < 10; ++i) { + try { + throw MinAligned{}; + } catch (MinAligned const& ref) { + assert(reinterpret_cast(&ref) % alignof(AlignedType) == 0); + } + } +}