Skip to content

Commit 9ef1daa

Browse files
committed
Insert padding before the __cxa_exception header to ensure the thrown
object is sufficiently aligned. r303175 annotated field unwindHeader of __cxa_exception with attribute 'aligned' to ensure the thrown object following the __cxa_exception header was sufficiently aligned. This caused changes in the field offsets of __cxa_exception relative to the start of the thrown object, which was an ABI breaking change for some clients. Instead of annotating field unwindHeader, this commit inserts extra space before the header. This ensures the thrown object following the header is sufficiently aligned without changing the field offsets, thus avoiding any ABI breakages. rdar://problem/25364625 rdar://problem/35556163 llvm-svn: 319123
1 parent ce732e7 commit 9ef1daa

File tree

2 files changed

+36
-26
lines changed

2 files changed

+36
-26
lines changed

libcxxabi/src/cxa_exception.cpp

+36-4
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,28 @@ static _LIBCXXABI_NORETURN void failed_throw(__cxa_exception* exception_header)
137137
std::__terminate(exception_header->terminateHandler);
138138
}
139139

140+
// Return the offset of the __cxa_exception header from the start of the
141+
// allocated buffer. If __cxa_exception's alignment is smaller than the maximum
142+
// useful alignment for the target machine, padding has to be inserted before
143+
// the header to ensure the thrown object that follows the header is
144+
// sufficiently aligned. This happens if _Unwind_exception isn't double-word
145+
// aligned (on Darwin, for example).
146+
static size_t get_cxa_exception_offset() {
147+
struct S {
148+
} __attribute__((aligned));
149+
150+
// Compute the maximum alignment for the target machine.
151+
constexpr size_t alignment = std::alignment_of<S>::value;
152+
constexpr size_t excp_size = sizeof(__cxa_exception);
153+
constexpr size_t aligned_size =
154+
(excp_size + alignment - 1) / alignment * alignment;
155+
constexpr size_t offset = aligned_size - excp_size;
156+
static_assert((offset == 0 ||
157+
std::alignment_of<_Unwind_Exception>::value < alignment),
158+
"offset is non-zero only if _Unwind_Exception isn't aligned");
159+
return offset;
160+
}
161+
140162
extern "C" {
141163

142164
// Allocate a __cxa_exception object, and zero-fill it.
@@ -146,18 +168,28 @@ extern "C" {
146168
// user's exception object.
147169
void *__cxa_allocate_exception(size_t thrown_size) throw() {
148170
size_t actual_size = cxa_exception_size_from_exception_thrown_size(thrown_size);
149-
__cxa_exception *exception_header =
150-
static_cast<__cxa_exception *>(__aligned_malloc_with_fallback(actual_size));
151-
if (NULL == exception_header)
171+
172+
// Allocate extra space before the __cxa_exception header to ensure the
173+
// start of the thrown object is sufficiently aligned.
174+
size_t header_offset = get_cxa_exception_offset();
175+
char *raw_buffer =
176+
(char *)__aligned_malloc_with_fallback(header_offset + actual_size);
177+
if (NULL == raw_buffer)
152178
std::terminate();
179+
__cxa_exception *exception_header =
180+
static_cast<__cxa_exception *>((void *)(raw_buffer + header_offset));
153181
std::memset(exception_header, 0, actual_size);
154182
return thrown_object_from_cxa_exception(exception_header);
155183
}
156184

157185

158186
// Free a __cxa_exception object allocated with __cxa_allocate_exception.
159187
void __cxa_free_exception(void *thrown_object) throw() {
160-
__aligned_free_with_fallback(cxa_exception_from_thrown_object(thrown_object));
188+
// Compute the size of the padding before the header.
189+
size_t header_offset = get_cxa_exception_offset();
190+
char *raw_buffer =
191+
((char *)cxa_exception_from_thrown_object(thrown_object)) - header_offset;
192+
__aligned_free_with_fallback((void *)raw_buffer);
161193
}
162194

163195

libcxxabi/src/cxa_exception.hpp

-22
Original file line numberDiff line numberDiff line change
@@ -60,22 +60,7 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
6060
// previously adding padded to 64-bit align unwindHeader.
6161
size_t referenceCount;
6262
#endif
63-
64-
// This field is annotated with attribute aligned so that the exception
65-
// object following the field is sufficiently aligned and there is no
66-
// gap between the field and the exception object. r276215 made a change to
67-
// annotate _Unwind_Exception in unwind.h with __attribute__((aligned)), but
68-
// we cannot incorporate the fix on Darwin since it is an ABI-breaking
69-
// change, which is why we need the attribute on this field.
70-
//
71-
// For ARM EHABI, we do not align this field since _Unwind_Exception is an
72-
// alias of _Unwind_Control_Block, which is not annotated with
73-
// __attribute__((aligned).
74-
#if defined(_LIBCXXABI_ARM_EHABI)
7563
_Unwind_Exception unwindHeader;
76-
#else
77-
_Unwind_Exception unwindHeader __attribute__((aligned));
78-
#endif
7964
};
8065

8166
// http://sourcery.mentor.com/archives/cxx-abi-dev/msg01924.html
@@ -109,14 +94,7 @@ struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
10994
#if !defined(__LP64__) && !defined(_LIBCXXABI_ARM_EHABI)
11095
void* primaryException;
11196
#endif
112-
113-
// See the comment in __cxa_exception as to why this field has attribute
114-
// aligned.
115-
#if defined(_LIBCXXABI_ARM_EHABI)
11697
_Unwind_Exception unwindHeader;
117-
#else
118-
_Unwind_Exception unwindHeader __attribute__((aligned));
119-
#endif
12098
};
12199

122100
struct _LIBCXXABI_HIDDEN __cxa_eh_globals {

0 commit comments

Comments
 (0)