summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cxa_exception.cpp40
-rw-r--r--src/cxa_exception.hpp22
2 files changed, 36 insertions, 26 deletions
diff --git a/src/cxa_exception.cpp b/src/cxa_exception.cpp
index e6ed093..d5230cd 100644
--- a/src/cxa_exception.cpp
+++ b/src/cxa_exception.cpp
@@ -137,6 +137,28 @@ static _LIBCXXABI_NORETURN void failed_throw(__cxa_exception* exception_header)
std::__terminate(exception_header->terminateHandler);
}
+// Return the offset of the __cxa_exception header from the start of the
+// allocated buffer. If __cxa_exception's alignment is smaller than the maximum
+// useful alignment for the target machine, padding has to be inserted before
+// the header to ensure the thrown object that follows the header is
+// sufficiently aligned. This happens if _Unwind_exception isn't double-word
+// aligned (on Darwin, for example).
+static size_t get_cxa_exception_offset() {
+ struct S {
+ } __attribute__((aligned));
+
+ // Compute the maximum alignment for the target machine.
+ constexpr size_t alignment = std::alignment_of<S>::value;
+ constexpr size_t excp_size = sizeof(__cxa_exception);
+ constexpr size_t aligned_size =
+ (excp_size + alignment - 1) / alignment * alignment;
+ constexpr size_t offset = aligned_size - excp_size;
+ static_assert((offset == 0 ||
+ std::alignment_of<_Unwind_Exception>::value < alignment),
+ "offset is non-zero only if _Unwind_Exception isn't aligned");
+ return offset;
+}
+
extern "C" {
// Allocate a __cxa_exception object, and zero-fill it.
@@ -146,10 +168,16 @@ extern "C" {
// user's exception object.
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 *>(__aligned_malloc_with_fallback(actual_size));
- if (NULL == exception_header)
+
+ // Allocate extra space before the __cxa_exception header to ensure the
+ // start of the thrown object is sufficiently aligned.
+ size_t header_offset = get_cxa_exception_offset();
+ char *raw_buffer =
+ (char *)__aligned_malloc_with_fallback(header_offset + actual_size);
+ if (NULL == raw_buffer)
std::terminate();
+ __cxa_exception *exception_header =
+ static_cast<__cxa_exception *>((void *)(raw_buffer + header_offset));
std::memset(exception_header, 0, actual_size);
return thrown_object_from_cxa_exception(exception_header);
}
@@ -157,7 +185,11 @@ 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() {
- __aligned_free_with_fallback(cxa_exception_from_thrown_object(thrown_object));
+ // Compute the size of the padding before the header.
+ size_t header_offset = get_cxa_exception_offset();
+ char *raw_buffer =
+ ((char *)cxa_exception_from_thrown_object(thrown_object)) - header_offset;
+ __aligned_free_with_fallback((void *)raw_buffer);
}
diff --git a/src/cxa_exception.hpp b/src/cxa_exception.hpp
index b9f74e3..c8b0fb1 100644
--- a/src/cxa_exception.hpp
+++ b/src/cxa_exception.hpp
@@ -60,22 +60,7 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
// previously adding padded to 64-bit align unwindHeader.
size_t referenceCount;
#endif
-
- // This field is annotated with attribute aligned so that the exception
- // object following the field is sufficiently aligned and there is no
- // gap between the field and the exception object. r276215 made a change to
- // annotate _Unwind_Exception in unwind.h with __attribute__((aligned)), but
- // we cannot incorporate the fix on Darwin since it is an ABI-breaking
- // change, which is why we need the attribute on this field.
- //
- // For ARM EHABI, we do not align this field since _Unwind_Exception is an
- // alias of _Unwind_Control_Block, which is not annotated with
- // __attribute__((aligned).
-#if defined(_LIBCXXABI_ARM_EHABI)
_Unwind_Exception unwindHeader;
-#else
- _Unwind_Exception unwindHeader __attribute__((aligned));
-#endif
};
// http://sourcery.mentor.com/archives/cxx-abi-dev/msg01924.html
@@ -109,14 +94,7 @@ struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
#if !defined(__LP64__) && !defined(_LIBCXXABI_ARM_EHABI)
void* primaryException;
#endif
-
- // See the comment in __cxa_exception as to why this field has attribute
- // aligned.
-#if defined(_LIBCXXABI_ARM_EHABI)
_Unwind_Exception unwindHeader;
-#else
- _Unwind_Exception unwindHeader __attribute__((aligned));
-#endif
};
struct _LIBCXXABI_HIDDEN __cxa_eh_globals {