-
Notifications
You must be signed in to change notification settings - Fork 122
Description
Throwing exceptions in Objective C++ code currently crashes with some setups. #138 adds tests that expose (some of?) these issues.
According to @davidchisnall:
I've had a look and found a few minor bugs that are easy to fix. Unfortunately, when I fix them I find some more interesting issues that arise from the way that we're now creating the exception by hijacking the C++ runtime library.
I think that the solution that we're going to have to end up with is using that path only to figure our which structure we have and then casting to the correct variant structure and creating it ourselves.
I have created cxa_exception_variants.cpp containing the four different possible layouts of the __cxa_exception struct that are found in libobjc2, libcxxrt, and libunwind:
- There are two different versions of the __cxa_exception struct: without and with the added "referenceCount" field.
- However the struct also references _Unwind_Exception, which itself comes in two different variants: without and with an "__aligned__" attribute (and an added "reserved" field on x86).
This leaves us with a total of four different variants of __cxa_exception:
- __cxa_exception_v1: without referenceCount field, using unaligned _Unwind_Exception
- __cxa_exception_v2: without referenceCount field, using aligned _Unwind_Exception
- __cxa_exception_v3: with referenceCount field, using unaligned _Unwind_Exception
- __cxa_exception_v4: with referenceCount field, using aligned _Unwind_Exception
Depending on the architecture some of these will have the same size. Following are the sizes for the different architectures as printed by the attached tool.
x86
_Unwind_Exception_v1 size: 20, alignment: 4
_Unwind_Exception_v2 size: 32, alignment: 16
__cxa_exception_v1 size: 64, alignment: 4
__cxa_exception_v2 size: 80, alignment: 16
__cxa_exception_v3 size: 68, alignment: 4
__cxa_exception_v4 size: 80, alignment: 16
x86_64
_Unwind_Exception_v1 size: 32, alignment: 8
_Unwind_Exception_v2 size: 32, alignment: 16
__cxa_exception_v1 size: 112, alignment: 8
__cxa_exception_v2 size: 112, alignment: 16
__cxa_exception_v3 size: 120, alignment: 8
__cxa_exception_v4 size: 128, alignment: 16
ARM32
_Unwind_Exception_v1 size: 88, alignment: 4
_Unwind_Exception_v2 size: 88, alignment: 8
__cxa_exception_v1 size: 132, alignment: 4
__cxa_exception_v2 size: 136, alignment: 8
__cxa_exception_v3 size: 136, alignment: 4
__cxa_exception_v4 size: 136, alignment: 8
ARM64
_Unwind_Exception_v1 size: 104, alignment: 8
_Unwind_Exception_v2 size: 104, alignment: 8
__cxa_exception_v1 size: 184, alignment: 8
__cxa_exception_v2 size: 184, alignment: 8
__cxa_exception_v3 size: 192, alignment: 8
__cxa_exception_v4 size: 192, alignment: 8
I’m not 100% sure which of these variants are actually used in the wild, although I think that FreeBSD 12.0 is using v2, and libcxxrt was using v3 and is now using v4 after libcxxrt/libcxxrt#1 was merged.