forked from OSchip/llvm-project
[libcxxabi] Fix alignment of allocated exceptions in 32 bit builds
Summary: In 32 bit builds on a 64 bit system `std::malloc` does not return correctly aligned memory. This leads to undefined behavior. This patch switches to using `posix_memalign` to allocate correctly aligned memory instead. Reviewers: mclow.lists, danalbert, jroelofs, compnerd Reviewed By: compnerd Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D25417 llvm-svn: 296952
This commit is contained in:
parent
9984624edf
commit
c74a2e1297
|
@ -63,12 +63,16 @@ cxa_exception_from_exception_unwind_exception(_Unwind_Exception* unwind_exceptio
|
|||
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 @@ extern "C" {
|
|||
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 @@ void *__cxa_allocate_exception(size_t thrown_size) throw() {
|
|||
|
||||
// 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 @@ void __cxa_free_exception(void *thrown_object) throw() {
|
|||
// 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 @@ void * __cxa_allocate_dependent_exception () {
|
|||
// 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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -194,13 +194,26 @@ size_t print_free_list () {
|
|||
|
||||
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 @@ void * __calloc_with_fallback(size_t count, size_t size) {
|
|||
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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 <cstdint>
|
||||
#include <cassert>
|
||||
|
||||
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<uintptr_t>(&ref) % alignof(AlignedType) == 0);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue