std::rethrow_exception is broken

François Dumont frs.dumont@gmail.com
Thu Mar 27 21:22:00 GMT 2014


Shouldn't static assertion messages say that layout is incorrect ? It is 
strange to have compilation error with a message saying that it is 
correct, isn't it ?

François


On 25/03/2014 18:25, Jonathan Wakely wrote:
> On 24/03/14 19:19 +0000, Jonathan Wakely wrote:
>> There is a lot of code in libsupc++/eh_* that relies on
>> __cxa_exception and __cxa_dependent_exception having similar layouts,
>> so tricks like this work:
>>
>> static inline void*
>> __gxx_caught_object(_Unwind_Exception* eo)
>> {
>>  // Bad as it looks, this actually works for dependent exceptions too.
>>  __cxa_exception* header = __get_exception_header_from_ue (eo);
>>  return header->adjustedPtr;
>> }
>>
>> The idea is that although the eo might be a pointer to the
>> unwindHeader member  of either __cxa_exception or
>> __cxa_dependent_exception, the adjustedPtr member will be always be at
>> the same location relative to the unwindHeader member, so it Just
>> Works.
>>
>> Except it doesn't.
>>
>> offsetof(__cxa_exception, unwindHeader) == 80
>> offsetof(__cxa_dependent_exception, unwindHeader) == 80
>> offsetof(__cxa_exception, adjustedPtr) == 72
>> offsetof(__cxa_dependent_exception, adjustedPtr) == 64
>
> Here's the output of GDB's pahole on __cxa_exception
>
> (gdb) pahole struct __cxxabiv1::__cxa_exception
>                struct __cxxabiv1::__cxa_exception {
>  /*   0   8 */    std::type_info * exceptionType
>  /*   8   8 */    void (*)(void *) exceptionDestructor
>  /*  16   8 */    void (*)(void) unexpectedHandler
>  /*  24   8 */    void (*)(void) terminateHandler
>  /*  32   8 */    __cxxabiv1::__cxa_exception * nextException
>  /*  40   4 */    int handlerCount
>  /*  44   4 */    int handlerSwitchValue
>  /*  48   8 */    const unsigned char * actionRecord
>  /*  56   8 */    const unsigned char * languageSpecificData
>  /*  64   8 */    unsigned long catchTemp
>  /*  72   8 */    void * adjustedPtr
>  /*  80  32 */   struct _Unwind_Exception {
>  /*   0   8 */      unsigned long exception_class
>  /*   8   8 */      void (*)(_Unwind_Reason_Code, _Unwind_Exception *) 
> exception_cleanup
>  /*  16   8 */      unsigned long private_1
>  /*  24   8 */      unsigned long private_2
>                  } unwindHeader
>                }
> And here's the current definition of __cxa_dependent_exception:
>
> (gdb) pahole struct __cxxabiv1::__cxa_dependent_exception 
>                struct __cxxabiv1::__cxa_dependent_exception {
>  /*   0   8 */    void * primaryException
>  /*   8   8 */    void (*)(void) unexpectedHandler
>  /*  16   8 */    void (*)(void) terminateHandler
>  /*  24   8 */    __cxxabiv1::__cxa_exception * nextException
>  /*  32   4 */    int handlerCount
>  /*  36   4 */    int handlerSwitchValue
>  /*  40   8 */    const unsigned char * actionRecord
>  /*  48   8 */    const unsigned char * languageSpecificData
>  /*  56   8 */    unsigned long catchTemp
>  /*  64   8 */    void * adjustedPtr
>   /* XXX 64 bit hole, try to pack */
>  /*  80  32 */   struct _Unwind_Exception {
>  /*   0   8 */      unsigned long exception_class
>  /*   8   8 */      void (*)(_Unwind_Reason_Code, _Unwind_Exception *) 
> exception_cleanup
>  /*  16   8 */      unsigned long private_1
>  /*  24   8 */      unsigned long private_2
>                  } unwindHeader
>                }
> Notice the hole right before the unwindHeader member which is not
> there in __cxa_exception. All the member which are supposed to be at
> the same offsets as in __cxa_exception are 8 bytes earlier.
>
> The attached patch adds a __padding member near the start so changes
> that to:
>
> (gdb) pahole struct __cxxabiv1::__cxa_dependent_exception 
>                struct __cxxabiv1::__cxa_dependent_exception {
>  /*   0   8 */    void * primaryException
>  /*   8   8 */    void (*)(void *) __padding
>  /*  16   8 */    void (*)(void) unexpectedHandler
>  /*  24   8 */    void (*)(void) terminateHandler
>  /*  32   8 */    __cxxabiv1::__cxa_exception * nextException
>  /*  40   4 */    int handlerCount
>  /*  44   4 */    int handlerSwitchValue
>  /*  48   8 */    const unsigned char * actionRecord
>  /*  56   8 */    const unsigned char * languageSpecificData
>  /*  64   8 */    unsigned long catchTemp
>  /*  72   8 */    void * adjustedPtr
>  /*  80  32 */   struct _Unwind_Exception {
>  /*   0   8 */      unsigned long exception_class
>  /*   8   8 */      void (*)(_Unwind_Reason_Code, _Unwind_Exception *) 
> exception_cleanup
>  /*  16   8 */      unsigned long private_1
>  /*  24   8 */      unsigned long private_2
>                  } unwindHeader
>                }
> That change allows all the pointer tricks in libsupc++/eh_*.cc to
> continue working.  It's a change to the layout of a low-level type,
> which is not visible to users linking to libsupc++.so, but anyone
> linking statically will not be able to mix code using GCC 4.9's
> libsupc++.a with the libsupc++.a from previous versions if they use
> std::rethrow_exception() anywhere.
>
> Tested x86_64-linux, I plan to commit this to trunk soon.
>



More information about the Libstdc++ mailing list