Skip to content

Commit c74a2e1

Browse files
committed
[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
1 parent 9984624 commit c74a2e1

File tree

4 files changed

+74
-16
lines changed

4 files changed

+74
-16
lines changed

libcxxabi/src/cxa_exception.cpp

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,16 @@ cxa_exception_from_exception_unwind_exception(_Unwind_Exception* unwind_exceptio
6363
return cxa_exception_from_thrown_object(unwind_exception + 1 );
6464
}
6565

66-
static
67-
inline
68-
size_t
69-
cxa_exception_size_from_exception_thrown_size(size_t size)
70-
{
71-
return size + sizeof (__cxa_exception);
66+
// Round s up to next multiple of a.
67+
static inline
68+
size_t aligned_allocation_size(size_t s, size_t a) {
69+
return (s + a - 1) & ~(a - 1);
70+
}
71+
72+
static inline
73+
size_t cxa_exception_size_from_exception_thrown_size(size_t size) {
74+
return aligned_allocation_size(size + sizeof (__cxa_exception),
75+
alignof(__cxa_exception));
7276
}
7377

7478
static void setExceptionClass(_Unwind_Exception* unwind_exception) {
@@ -140,7 +144,7 @@ extern "C" {
140144
void *__cxa_allocate_exception(size_t thrown_size) throw() {
141145
size_t actual_size = cxa_exception_size_from_exception_thrown_size(thrown_size);
142146
__cxa_exception *exception_header =
143-
static_cast<__cxa_exception *>(__malloc_with_fallback(actual_size));
147+
static_cast<__cxa_exception *>(__aligned_malloc_with_fallback(actual_size));
144148
if (NULL == exception_header)
145149
std::terminate();
146150
std::memset(exception_header, 0, actual_size);
@@ -150,7 +154,7 @@ void *__cxa_allocate_exception(size_t thrown_size) throw() {
150154

151155
// Free a __cxa_exception object allocated with __cxa_allocate_exception.
152156
void __cxa_free_exception(void *thrown_object) throw() {
153-
__free_with_fallback(cxa_exception_from_thrown_object(thrown_object));
157+
__aligned_free_with_fallback(cxa_exception_from_thrown_object(thrown_object));
154158
}
155159

156160

@@ -159,7 +163,7 @@ void __cxa_free_exception(void *thrown_object) throw() {
159163
// Otherwise, it will work like __cxa_allocate_exception.
160164
void * __cxa_allocate_dependent_exception () {
161165
size_t actual_size = sizeof(__cxa_dependent_exception);
162-
void *ptr = __malloc_with_fallback(actual_size);
166+
void *ptr = __aligned_malloc_with_fallback(actual_size);
163167
if (NULL == ptr)
164168
std::terminate();
165169
std::memset(ptr, 0, actual_size);
@@ -170,7 +174,7 @@ void * __cxa_allocate_dependent_exception () {
170174
// This function shall free a dependent_exception.
171175
// It does not affect the reference count of the primary exception.
172176
void __cxa_free_dependent_exception (void * dependent_exception) {
173-
__free_with_fallback(dependent_exception);
177+
__aligned_free_with_fallback(dependent_exception);
174178
}
175179

176180

libcxxabi/src/fallback_malloc.cpp

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -194,13 +194,26 @@ size_t print_free_list () {
194194

195195
namespace __cxxabiv1 {
196196

197-
void * __malloc_with_fallback(size_t size) {
198-
void *ptr = std::malloc(size);
199-
if (NULL == ptr) // if malloc fails, fall back to emergency stash
200-
ptr = fallback_malloc(size);
201-
return ptr;
197+
struct __attribute__((aligned)) __aligned_type {};
198+
199+
void * __aligned_malloc_with_fallback(size_t size) {
200+
#if defined(_WIN32)
201+
if (void *dest = _aligned_malloc(size, alignof(__aligned_type)))
202+
return dest;
203+
#elif defined(_LIBCPP_HAS_NO_ALIGNED_ALLOCATION)
204+
if (void* dest = std::malloc(size))
205+
return dest;
206+
#else
207+
if (size == 0)
208+
size = 1;
209+
void* dest;
210+
if (::posix_memalign(&dest, alignof(__aligned_type), size) == 0)
211+
return dest;
212+
#endif
213+
return fallback_malloc(size);
202214
}
203215

216+
204217
void * __calloc_with_fallback(size_t count, size_t size) {
205218
void *ptr = std::calloc(count, size);
206219
if (NULL != ptr)
@@ -212,6 +225,18 @@ void * __calloc_with_fallback(size_t count, size_t size) {
212225
return ptr;
213226
}
214227

228+
void __aligned_free_with_fallback(void* ptr) {
229+
if (is_fallback_ptr(ptr))
230+
fallback_free(ptr);
231+
else {
232+
#if defined(_WIN32)
233+
::_aligned_free(ptr);
234+
#else
235+
std::free(ptr);
236+
#endif
237+
}
238+
}
239+
215240
void __free_with_fallback(void *ptr) {
216241
if (is_fallback_ptr(ptr))
217242
fallback_free(ptr);

libcxxabi/src/fallback_malloc.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,12 @@
1616
namespace __cxxabiv1 {
1717

1818
// Allocate some memory from _somewhere_
19-
_LIBCXXABI_HIDDEN void * __malloc_with_fallback(size_t size);
19+
_LIBCXXABI_HIDDEN void * __aligned_malloc_with_fallback(size_t size);
2020

2121
// Allocate and zero-initialize memory from _somewhere_
2222
_LIBCXXABI_HIDDEN void * __calloc_with_fallback(size_t count, size_t size);
2323

24+
_LIBCXXABI_HIDDEN void __aligned_free_with_fallback(void *ptr);
2425
_LIBCXXABI_HIDDEN void __free_with_fallback(void *ptr);
2526

2627
} // namespace __cxxabiv1
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is dual licensed under the MIT and the University of Illinois Open
6+
// Source Licenses. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
// Test that the address of the exception object is properly aligned to the
11+
// largest supported alignment for the system.
12+
13+
#include <cstdint>
14+
#include <cassert>
15+
16+
struct __attribute__((aligned)) AlignedType {};
17+
struct MinAligned { };
18+
static_assert(alignof(MinAligned) == 1 && sizeof(MinAligned) == 1, "");
19+
20+
int main() {
21+
for (int i=0; i < 10; ++i) {
22+
try {
23+
throw MinAligned{};
24+
} catch (MinAligned const& ref) {
25+
assert(reinterpret_cast<uintptr_t>(&ref) % alignof(AlignedType) == 0);
26+
}
27+
}
28+
}

0 commit comments

Comments
 (0)