<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/135089>135089</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
[libc++] [libc++abi] Regression: std::make_exception_ptr breaks catching ObjC objects on rethrow
</td>
</tr>
<tr>
<th>Labels</th>
<td>
libc++,
libc++abi
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
rsesek
</td>
</tr>
</table>
<pre>
This is a regression introduced in LLVM commit 51e91b64d0deb6a743861c2a0fba84865250036e (PR #65534). The following code used to work prior to the change:
```objc++
#include <exception>
#import <Foundation/Foundation.h>
NSError* RecoverException(const std::exception_ptr& exc) {
try {
std::rethrow_exception(exc);
} catch (NSError* error) {
return error;
} catch (...) {
}
return nil;
}
int main() {
NSError* error = [NSError errorWithDomain:NSPOSIXErrorDomain code:EPERM userInfo:nil];
std::exception_ptr exc = std::make_exception_ptr(error);
NSError* recov = RecoverException(exc);
if (recov) {
printf("[+] PASS: %s\n", recov.description.UTF8String);
} else {
printf("[-] FAIL: Expected NSError, got nil\n");
}
}
```
This kind of code may be written when working with an Objective-C++ codebase that uses exceptions, and NSError*/NSException* types need to be handled alongside C++ errors. I believe this is supported because Objective-C exceptions are [interoperable](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Exceptions/Articles/Exceptions64Bit.html#//apple_ref/doc/uid/TP40009044-SW1) with C++ exceptions.
This broke with the aforementioned commit because `std::make_exception_ptr` no longer internally throws the exception object and uses `std::current_exception` to capture the value. Instead, it directly allocates and populates the `__cxxabiv1::__cxa_exception` using the C++ type information. However, when an ObjC exception is thrown natively, it uses [a different representation](https://github.com/apple-oss-distributions/objc4/blob/objc4-928.2/runtime/objc-exception.mm#L385) for the exception's typeinfo.
This is apparent when looking at the assembly output from `clang++ -S`. In the sample program above, the Catch TypeInfos in `GCC_except_table0` for `RecoverException()` is a `_OBJC_EHTYPE_$_NSError`. This corresponds to the type stored in a `struct objc_exception` produced in the ObjC runtime when an object is thrown via `objc_exception_throw`.
But in the assembly produced after that commit, the template instantiation for `std::exception_ptr std::make_exception_ptr<NSError*>(NSError*)` produces an exception with a reference to the `__ZTIP7NSError` typeinfo. I.e., after the commit, the exception stores the C++ typeinfo for the object, rather than the ObjC typeinfo. When the exception is rethrown, the catch arms fail to match because the typeinfos between the catch arm and the exception object do not match.
Putting a breakpoint on `RecoverException` and then inspecting the argument shows this too. After the commit:
```
(lldb) p *(((__cxxabiv1::__cxa_exception*)exc.__ptr_)-1)
(__cxxabiv1::__cxa_exception) {
reserve = 0x0000000000000000
referenceCount = 1
exceptionType = 0x00000001000040a0
exceptionDestructor = 0x0000000100000b8c (cocoa-exc`std::exception_ptr std::make_exception_ptr[abi:ne180000]<NSError*>(NSError*)::'lambda'(void*)::__invoke(void*) at exception_ptr.h:91)
unexpectedHandler = 0x0000000100141570 (libc++abi.1.dylib`demangling_unexpected_handler() at cxa_default_handlers.cpp:90)
terminateHandler = 0x000000010014138c (libc++abi.1.dylib`demangling_terminate_handler() at cxa_default_handlers.cpp:39)
nextException = nil
handlerCount = 0
handlerSwitchValue = 0
actionRecord = 0x0000000000000000
languageSpecificData = 0x0000000000000000
catchTemp = 0x0000000000000000
adjustedPtr = 0x0000000000000000
unwindHeader = {
exception_class = 4849336966747728640
exception_cleanup = 0x0000000100177288 (libc++abi.1.dylib`__cxxabiv1::exception_cleanup_func(_Unwind_Reason_Code, _Unwind_Exception*) at cxa_exception.cpp:134)
private_1 = 0
private_2 = 0
}
}
(lldb) p/s (((__cxxabiv1::__cxa_exception*)exc.__ptr_)-1)->exceptionType->name()
(const char *) "P7NSError" "P7NSError"
(lldb) x/2a (((__cxxabiv1::__cxa_exception*)exc.__ptr_)-1)->exceptionType
0x1000040a0: 0x0000000100183bc0 libc++abi.1.0.dylib`vtable for __cxxabiv1::__pointer_type_info + 16
0x1000040a8: 0x8000000100000cf7 (0x0000000100000cf7) cocoa-exc`typeinfo name for NSError*
```
Before the commit:
```
(lldb) p *(((__cxxabiv1::__cxa_exception*)exc.__ptr_)-1)
(__cxxabiv1::__cxa_exception) {
reserve = 0x0000000000000000
referenceCount = 1
exceptionType = 0x00006000008c4088
exceptionDestructor = 0x000000019290b1ec (libobjc.A.dylib`_objc_exception_destructor(void*))
unexpectedHandler = 0x0000000192c8dd30 (libc++abi.dylib`demangling_unexpected_handler())
terminateHandler = 0x0000000192914cd8 (libobjc.A.dylib`_objc_terminate())
nextException = nil
handlerCount = 0
handlerSwitchValue = 1
actionRecord = 0x0000000100000bc1 "\U00000001"
languageSpecificData = 0x0000000100000bb0 "\xff\x9b\U00000015\U00000001\f\U0000001c\U00000004(\U00000001 ("
catchTemp = 0x0000000100000a90
adjustedPtr = 0x00006000008c4080
unwindHeader = {
exception_class = 4849336966747728640
exception_cleanup = 0x0000000192ca1af4 (libc++abi.dylib`__cxxabiv1::exception_cleanup_func(_Unwind_Reason_Code, _Unwind_Exception*))
private_1 = 0
private_2 = 6171911792
}
}
(lldb) p/s (((__cxxabiv1::__cxa_exception*)exc.__ptr_)-1)->exceptionType->name()
(const char *) "NSError" "NSError"
(lldb) x/2a (((__cxxabiv1::__cxa_exception*)exc.__ptr_)-1)->exceptionType
0x6000008c4088: 0x0000000202c44938 libobjc.A.dylib`objc_ehtype_vtable + 16
0x6000008c4090: 0x0000000194de7dfa "NSError"
```
Also filed as FB17179536.
</pre>
<img width="1" height="1" alt="" src="http://email.email.llvm.org/o/eJzkWd1u4ziyfhrmhoggUT-WLnLhOPHpPuiZCTqZmXP2xqCoks2JTAok5SRvvyhKsqQkne7ZncUusA0jbvGnqlj1VX1FmVsr9wrgiqTXJL254J07aHNlLFh4vCh19XL1cJCWSks5NbA3YK3UikrljK46ARWVin758ttPVOjjUTqaRlBEZZZUYQVlxldJnGeRYDysS54neZayNAzjDChh-d1XSlicpWmcEFYE9OEAtNZNo5-k2lOhK6CdhYo6TZ-0eaStkdrgkzsAFQeu9kDiNQn9Jwv7jy7_EIRd4ydcExZLJZquAkriDTwLaJ3UisS3w-Sx1cbh3FZ3quJ-km2nh-AwrA3XP9_fGqMNYWv6FYQ-gbk9y2O50Mo6al2FFsXrs6pd6wxhGYVnQVhByQrNotSZl_P_6bTNgDsY_bSDmeR-J4n7xWR1QwV34oAOnJkE_X-KmVQDrjNqmHlvexAE8x1kdeO_h31KNv2ufpyEa6kcPXKJRs33vbaCkviGkvR6GO8Hf5fucKP97nj98_3dL_ef_89P94M-2iRe397dfv0Jo24-q1qTeI1WpDeD-e-7F33rdZ6nj_wRdq9CkI8eGl0xM9tgPL2IdyK79L-s0XN-w9LbrZHK1d41DLOJYULRu_X9PYnXlLDUknSjcJJteoVBBVYY6fUEvz5s83tnpNq_CjY0Fr6t5hKVbNefv6CS2-cWhINqOtqG7rXzkRx1z2VPsR2Tp4-zT_lHqSqq6z4Nj_yFlkCfjHQOFH064B9tHjFPn6Q7UK7oL-UfIJw8weWmzz-_teQWqDtwh0G19BwUi8ZxNbN1Tdj25_uZ59fUvbRgqYK-BpRAD1xVDVSUN1rtrayAjrp8dG1AP9MSGgknVNoXLtu1mORQ0RIE7yzMLZ0ZRLkBhK1UDoxuwfCyAcQeyw_OtRahxbaEbSs4QYMLAt62DQRCHwnbNrI03LwQtuVGHOQJcKUW3RGUG-vKRgvN_bdCrR1vCNvezlyyXRsnRQN2MZ4l19IFB3dsCIt7G7zmnYG610LYtpMVYduHuyQMwyJMksv73yNEqA_P2UtnmcEs1KXRj9AvxMrKa20AzZZaQTUW9tF5JAs_yrMspEpTDA8Y6l2peNO8UF_XrJd_3kC1D4SHgUfHXLbojAHlZqUwCxEFgreuM-AlnXjTQUA_K-uAV4go6WglDQjXvFDeNFpwB9YraHXbNf4Jd6Kq3U48P_NSnqJeIz7zpb7OIsJxw-hBhCSVqtbm2BME_aSf4AQ-2Xxe9KkwQxaC0B9fUcURds3LYGp_6PSa00rWNeB5qYHWgD2D5h387aU7dOUAOw-ES23tZSWtM7LsRighESaEbctGl-PjZcHygBG2NZ1y8gjD-OXZ1uB4JCz-EucpYqdGup1HjLCV9S5AD8whhA1C23J_Au-FRmtfHbjrMWUtHMvmherOtZ2jtdFHjIFoOFY879rLe5KFGE2_w_Jj2wBtjd4bfqS81JhSmz4YnsEeXlpAlrDYg5As_J_NZojezmHuYkHzRyBZ-E5dx1qYhX1rg2j45fp_N7vbTw__f3e7IyzZjYUJbfJnFNoYsK1WlR2bEI8G67TpGyHeI9h0wiG2xRJM7axlws0eJUMgztAZUmKCzEl6qUtxOz-JpvUxuO7cKPXs6bM6XjswfQ3uc3l0o4NjiylBpbKOKyc95EaXfYNsP0r-eDOr5vHtokMZ3D1YhTk5y5CeQ6gBnwQCRv_6LP3bw-e71RSNCX_0cwCB55HhhPDqgJMCHyP7JpNRzBnlves9PXN36F02i9Sk9neM1VK-tHTo3dSovG-zuDlaWnPZ4JGOfmispCOApMdwCe4JBrnnrb5yvVszK02Vdr3EAQR3nXM-5WhpgD-2Gvs1rd6FfxaOorGZt9g3jJWOm70nLWoPfcVGLGod0PVrL7_pvX1TnTdNVWL1aKkPe95_vldtPULgWQQ7hNKOsOIS-asX-d3NUyeGxdOcwHdz4XP46t-wZIDZRnfK-ZWRnzgLxNKylBDhnyTk4XLhDfTpPnS9y-VhmQvq7wZCc6yx_1hWpde8lNgKQ5T7M2A__J1M87IIWzX8WFacsBVh-UljizBN73ZSnfQjLKawYC_U4w1oXQyhoLRTMHSZn3wv9vbcURKlqxDP3chyuIrxUgZRUL00siRZWMGRq30j1X43idv1vZ0ZLhdYrJ75roKad40bJ20g2hbtCUd7HJijVNzBB-bEfRh-wJyztD9lTVyM1ih4duck86Zg740zw5YJcR5Iw-j9k3Ti8Bt2M9Mc5QKlYOqa6gM4I4N2fA_3LQhZS3HDHf8I_b64PMCx_WARr_7orIPqzpmPRHXqSarqE_BqcPx0T5kwJBpurZ9N8qSI46zIslWyWrE8S8J3VgNXXfs2jLgh_yiMr2vEG5m7ulMCi8mv3uzdV-BWq90Gb55sQ8fh22VJGmM_tUh90CP_0mK6lZ0QNdEUvnGIzSK6uHPNCiVhW0v_2Up5SeLbRQHDAcWxycvPhbR_TSEO3NDheISxiV0Ze_28tPSZsC3jf72pJFyHz1OJjdfL2OdxKUL6OvDhOfQn3-95In9rkedBMDuk2p0nfGT_KFvozHud-bx6i3qFJ31V00W9Qk_Ma_q5k0BveytmxfjN7foa8H71X8mjmd-biyTM8x_k0YIVYRnBWMCxDQ7WU86_aours5gl3_0geRVM5FUVv0Nef4K6BmXfIaaCFVEiqvyjc51FLAT_WY75Fsn4UH2bY4YORkTUv2na_DqO90WB_gDvDCLKcBDxXNf4tygncVG6EJ1u6tmcmM0l6IPZUjq8AgvX3yK0XjsvBjJ9l9FmgPTL_hpC-x6bFUzwiNfJt2H2L-KyDwlrNtpzVhatoiKKVoX38n8ody2Z69_CW4uqNqcuFjKRJEWc07cZ3heugyelgb5mtDSJLF6xYZFUsKpq_va0S5ZZN1bTWvqXpZZur6NVtCrSOAsuqqu4KuKCX8BVtEoSFqdZlFwcrvKiSKIwXCUsDes8jMsY8jKKs1WcC5GW5YW8YiFLwyQsWJTGcRJUsOJJEq6KNGc5ACNJCEcum6BpTsdAm_2FtLaDqyhOw7y4aHgJjfU_NTE24b5_Jb4YwvsOVoybC3OFsi7Lbm9JEjbSOjtJd9I1_qermbDU__SwFJXe0K_n367QnR_ctvq7s-2LCl6J_d2_v3RbvE0P1_yLzjRXH7yXQyOHr8vW6P7Nwtb7wxK2HVxyumJ_DwAA___36obE">