r264998 - [CodeGenCXX] Fix ItaniumCXXABI::getAlignmentOfExnObject to return 8-byte

Akira Hatanaka via cfe-commits cfe-commits at lists.llvm.org
Wed Mar 30 23:36:09 PDT 2016


Author: ahatanak
Date: Thu Mar 31 01:36:07 2016
New Revision: 264998

URL: http://llvm.org/viewvc/llvm-project?rev=264998&view=rev
Log:
[CodeGenCXX] Fix ItaniumCXXABI::getAlignmentOfExnObject to return 8-byte
alignment on Darwin.

Itanium C++ ABI specifies that _Unwind_Exception should be double-word
aligned (16B). To conform to the ABI, libraries implementing exception
handling declare the struct with __attribute__((aligned)), which aligns
the unwindHeader field (and the end of __cxa_exception) to the default
target alignment (which is typically 16-bytes).

struct __cxa_exception {
  ...
  // struct is declared with __attribute__((aligned)).
  _Unwind_Exception unwindHeader;
};

Based on the assumption that _Unwind_Exception is declared with
__attribute__((aligned)), ItaniumCXXABI::getAlignmentOfExnObject returns
the target default alignment for __attribute__((aligned)). It turns out
that libc++abi, which is used on Darwin, doesn't declare the struct with
the attribute and therefore doesn't guarantee that unwindHeader is
aligned to the alignment specified by the ABI, which in some cases
causes the program to crash because of unaligned memory accesses.

This commit avoids crashes due to unaligned memory accesses by having
getAlignmentOfExnObject return an 8-byte alignment on Darwin. I've only
fixed the problem for Darwin, but we should also figure out whether other
platforms using libc++abi need similar fixes.

rdar://problem/25314277

Differential revision: http://reviews.llvm.org/D18479

Modified:
    cfe/trunk/include/clang/Basic/TargetInfo.h
    cfe/trunk/lib/Basic/Targets.cpp
    cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
    cfe/trunk/test/CodeGenCXX/eh.cpp

Modified: cfe/trunk/include/clang/Basic/TargetInfo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TargetInfo.h?rev=264998&r1=264997&r2=264998&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/TargetInfo.h (original)
+++ cfe/trunk/include/clang/Basic/TargetInfo.h Thu Mar 31 01:36:07 2016
@@ -414,6 +414,19 @@ public:
   /// types for the given target.
   unsigned getSimdDefaultAlign() const { return SimdDefaultAlign; }
 
+  /// Return the alignment (in bits) of the thrown exception object.
+  virtual unsigned getExnObjectAlignment() const {
+    /// Itanium says that an _Unwind_Exception has to be "double-word"
+    /// aligned (and thus the end of it is also so-aligned), meaning 16
+    /// bytes.  Of course, that was written for the actual Itanium,
+    /// which is a 64-bit platform.  Classically, the ABI doesn't really
+    /// specify the alignment on other platforms, but in practice
+    /// libUnwind declares the struct with __attribute__((aligned)), so
+    /// we assume that alignment here.  (It's generally 16 bytes, but
+    /// some targets overwrite it.)
+    return getDefaultAlignForAttributeAligned();
+  }
+
   /// \brief Return the size of intmax_t and uintmax_t for this target, in bits.
   unsigned getIntMaxTWidth() const {
     return getTypeWidth(IntMaxType);

Modified: cfe/trunk/lib/Basic/Targets.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Targets.cpp?rev=264998&r1=264997&r2=264998&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/Targets.cpp (original)
+++ cfe/trunk/lib/Basic/Targets.cpp Thu Mar 31 01:36:07 2016
@@ -262,6 +262,13 @@ public:
   bool hasProtectedVisibility() const override {
     return false;
   }
+
+  unsigned getExnObjectAlignment() const override {
+    // The alignment of an exception object is 8-bytes for darwin since
+    // libc++abi doesn't declare _Unwind_Exception with __attribute__((aligned))
+    // and therefore doesn't guarantee 16-byte alignment.
+    return  64;
+  }
 };
 
 

Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=264998&r1=264997&r2=264998&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Thu Mar 31 01:36:07 2016
@@ -154,17 +154,9 @@ public:
                                Address Ptr, QualType ElementType,
                                const CXXDestructorDecl *Dtor) override;
 
-  /// Itanium says that an _Unwind_Exception has to be "double-word"
-  /// aligned (and thus the end of it is also so-aligned), meaning 16
-  /// bytes.  Of course, that was written for the actual Itanium,
-  /// which is a 64-bit platform.  Classically, the ABI doesn't really
-  /// specify the alignment on other platforms, but in practice
-  /// libUnwind declares the struct with __attribute__((aligned)), so
-  /// we assume that alignment here.  (It's generally 16 bytes, but
-  /// some targets overwrite it.)
   CharUnits getAlignmentOfExnObject() {
-    auto align = CGM.getContext().getTargetDefaultAlignForAttributeAligned();
-    return CGM.getContext().toCharUnitsFromBits(align);
+    unsigned Align = CGM.getContext().getTargetInfo().getExnObjectAlignment();
+    return CGM.getContext().toCharUnitsFromBits(Align);
   }
 
   void emitRethrow(CodeGenFunction &CGF, bool isNoReturn) override;

Modified: cfe/trunk/test/CodeGenCXX/eh.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/eh.cpp?rev=264998&r1=264997&r2=264998&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/eh.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/eh.cpp Thu Mar 31 01:36:07 2016
@@ -448,5 +448,27 @@ namespace test16 {
   }
 }
 
+namespace test17 {
+class BaseException {
+private:
+  int a[4];
+public:
+  BaseException() {};
+};
+
+class DerivedException: public BaseException {
+};
+
+int foo() {
+  throw DerivedException();
+  // The alignment passed to memset is 8, not 16, on Darwin.
+
+  // CHECK: [[T0:%.*]] = call i8* @__cxa_allocate_exception(i64 16)
+  // CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to %"class.test17::DerivedException"*
+  // CHECK-NEXT: [[T2:%.*]] = bitcast %"class.test17::DerivedException"* [[T1]] to i8*
+  // CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T2]], i8 0, i64 16, i32 8, i1 false)
+}
+}
+
 // CHECK: attributes [[NUW]] = { nounwind }
 // CHECK: attributes [[NR]] = { noreturn }




More information about the cfe-commits mailing list