[libcxxabi] r296952 - [libcxxabi] Fix alignment of allocated exceptions in 32 bit builds

Eric Fiselier via cfe-commits cfe-commits at lists.llvm.org
Fri Mar 3 18:04:45 PST 2017


Author: ericwf
Date: Fri Mar  3 20:04:45 2017
New Revision: 296952

URL: http://llvm.org/viewvc/llvm-project?rev=296952&view=rev
Log:
[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

Added:
    libcxxabi/trunk/test/test_exception_address_alignment.pass.cpp
Modified:
    libcxxabi/trunk/src/cxa_exception.cpp
    libcxxabi/trunk/src/fallback_malloc.cpp
    libcxxabi/trunk/src/fallback_malloc.h

Modified: libcxxabi/trunk/src/cxa_exception.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/cxa_exception.cpp?rev=296952&r1=296951&r2=296952&view=diff
==============================================================================
--- libcxxabi/trunk/src/cxa_exception.cpp (original)
+++ libcxxabi/trunk/src/cxa_exception.cpp Fri Mar  3 20:04:45 2017
@@ -63,12 +63,16 @@ cxa_exception_from_exception_unwind_exce
     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 th
 
 //  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_o
 //  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_exceptio
 //  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);
 }
 
 

Modified: libcxxabi/trunk/src/fallback_malloc.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/fallback_malloc.cpp?rev=296952&r1=296951&r2=296952&view=diff
==============================================================================
--- libcxxabi/trunk/src/fallback_malloc.cpp (original)
+++ libcxxabi/trunk/src/fallback_malloc.cpp Fri Mar  3 20:04:45 2017
@@ -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 cou
     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);

Modified: libcxxabi/trunk/src/fallback_malloc.h
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/fallback_malloc.h?rev=296952&r1=296951&r2=296952&view=diff
==============================================================================
--- libcxxabi/trunk/src/fallback_malloc.h (original)
+++ libcxxabi/trunk/src/fallback_malloc.h Fri Mar  3 20:04:45 2017
@@ -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

Added: libcxxabi/trunk/test/test_exception_address_alignment.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/test/test_exception_address_alignment.pass.cpp?rev=296952&view=auto
==============================================================================
--- libcxxabi/trunk/test/test_exception_address_alignment.pass.cpp (added)
+++ libcxxabi/trunk/test/test_exception_address_alignment.pass.cpp Fri Mar  3 20:04:45 2017
@@ -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);
+    }
+  }
+}




More information about the cfe-commits mailing list