Skip to content

[libc++] Fix std::make_exception_ptr interaction with ObjC #135386

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 24 commits into from
Jul 8, 2025

Conversation

itrofimow
Copy link
Contributor

@itrofimow itrofimow commented Apr 11, 2025

Clang treats throwing/catching ObjC types differently from C++ types, and omitting the throw in std::make_exception_ptr breaks ObjC invariants about how types are thrown/caught.

Fixes #135089

@itrofimow itrofimow changed the title fix std::make_exception_ptr interaction with ObjC [libc++] fix std::make_exception_ptr interaction with ObjC Apr 14, 2025
@itrofimow itrofimow marked this pull request as ready for review April 14, 2025 19:04
@itrofimow itrofimow requested a review from a team as a code owner April 14, 2025 19:04
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Apr 14, 2025
@llvmbot
Copy link
Member

llvmbot commented Apr 14, 2025

@llvm/pr-subscribers-libcxx

Author: None (itrofimow)

Changes

Clang treats throwing/catching ObjC types differently from C++ types, and omitting the throw in std::make_exception_ptr breaks ObjC invariants about how types are thrown/caught


Full diff: https://github.com/llvm/llvm-project/pull/135386.diff

1 Files Affected:

  • (modified) libcxx/include/__exception/exception_ptr.h (+2-1)
diff --git a/libcxx/include/__exception/exception_ptr.h b/libcxx/include/__exception/exception_ptr.h
index dac5b00b57fe3..167aa4d9b367a 100644
--- a/libcxx/include/__exception/exception_ptr.h
+++ b/libcxx/include/__exception/exception_ptr.h
@@ -92,7 +92,8 @@ class _LIBCPP_EXPORTED_FROM_ABI exception_ptr {
 template <class _Ep>
 _LIBCPP_HIDE_FROM_ABI exception_ptr make_exception_ptr(_Ep __e) _NOEXCEPT {
 #  if _LIBCPP_HAS_EXCEPTIONS
-#    if _LIBCPP_AVAILABILITY_HAS_INIT_PRIMARY_EXCEPTION && __cplusplus >= 201103L
+  // Clang treats throwing ObjC types differently, and we have to preserve original throw-ing behavior
+#    if !defined(__OBJC__) && _LIBCPP_AVAILABILITY_HAS_INIT_PRIMARY_EXCEPTION && __cplusplus >= 201103L
   using _Ep2 = __decay_t<_Ep>;
 
   void* __ex = __cxxabiv1::__cxa_allocate_exception(sizeof(_Ep));

@jyknight
Copy link
Member

It's not great to condition only on __OBJC__ preprocessor define, since that'll create a potential ODR issue for std::make_exception_ptr on a C++ type, when you're mixing a TU built with C++ and another TU built with ObjC++ in the same program (which, everyone is).

If you switch to the throw impl only for ObjC object-pointers, that stops being a problem, as an ObjC object pointer type cannot exist in a non-ObjC++ TU.

As a refinement to my suggestion on the issue, I think std::is_pointer_v<_Ep> && std::is_convertible_v<_Ep, id> would be better (so as to not accidentally trigger on a C++ value with a user-defined conversion operator id()).

@jyknight
Copy link
Member

Are you still planning to update this patch?

@itrofimow
Copy link
Contributor Author

Hi! Yes, sorry, just got back to office

I was thinking, wouldn't just std::is_pointer_v<_Ep> condition be better it terms of readability?
After all, this is just an optimization, and given that people very seldom create exception pointers from pointers, it shouldn't be that much of a performance hit, and the less odd conditions we have here the better

@jyknight
Copy link
Member

You mean without the OBJC ifdef? I think that would be OK. But IMO it's not actually an improvement, because the condition is no longer clearly connected with the actual reason for the existence of the alternate codepath.

@itrofimow
Copy link
Contributor Author

I don't think CI failure has to do with these changes, @jyknight could you please have a look?

using _Ep2 = __decay_t<_Ep>;

void* __ex = __cxxabiv1::__cxa_allocate_exception(sizeof(_Ep));
# if _LIBCPP_AVAILABILITY_HAS_INIT_PRIMARY_EXCEPTION && __cplusplus >= 201703L
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should really be _LIBCPP_STD_VER >= 17. Also, why did this change from C++11 to C++17?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is about language-level features rather than libc++ features: c++11 or higher was required for the lambda to compile; c++17 or higher is now required for if constexpr

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both are available as extensions in older versions. No need to put this behind a guard.

@itrofimow itrofimow requested a review from philnik777 May 20, 2025 10:26
Copy link
Member

@jyknight jyknight left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change looks fine.

But is there any way to add a test-case for this? (It's not clear to me there is since it depends on the non-llvm-project objc runtime, but it'd be great if there was.)

@rsesek
Copy link

rsesek commented Jun 5, 2025

Change looks fine.

But is there any way to add a test-case for this? (It's not clear to me there is since it depends on the non-llvm-project objc runtime, but it'd be great if there was.)

There's some prior art in func.blocks.arc.pass.mm for depending on the Blocks runtime in a test. Not sure if it's also okay to depend on the host libobjc similarly.

@itrofimow
Copy link
Contributor Author

itrofimow commented Jun 10, 2025

I'll see what I can do about the test for this.
I don't think it's actually necessary (but would be nice to have) to depend on objc runtime: maybe just a objc-codegen test is somewhat enough

@ldionne ldionne changed the title [libc++] fix std::make_exception_ptr interaction with ObjC [libc++] Fix std::make_exception_ptr interaction with ObjC Jul 2, 2025
@ldionne
Copy link
Member

ldionne commented Jul 2, 2025

@itrofimow @jyknight Thanks for the PR. I updated the PR with a test and I refactored the code as a drive-by so it would be easier to understand -- after adding yet another if in there, the function was getting pretty hard to follow. Can you please have a look at the PR? I'd like to get it merged whenever possible.

@ldionne
Copy link
Member

ldionne commented Jul 2, 2025

We might be able to make it into LLVM 20.1.9 if we end up having such a release.

@ldionne
Copy link
Member

ldionne commented Jul 4, 2025

Gentle ping @itrofimow @jyknight WDYT about the current PR? It's passing CI and I'd like to get it merged whenever possible!

@itrofimow
Copy link
Contributor Author

Hi @ldionne! Thank you for taking care of this PR, I've got completely consumed by work and absolutely failed to clean up my own mess in time.

Personally, I don't think narrowing the "could it be ObjC type" condition any further via compiler intrinsics is worth it: for me (as someone who just reads libcxx source code from time to time, not a maintainer) the mere presence of ObjC-related code/comments in libcxx seems confusing enough, and I'd say that std::make_exception_ptr<T*> in C++ is a use-case too niche to further complicate code here, especially via something directly ObjC-related.

Nice refactoring by you, and I'm happy to see CI finally working.

LGTM

@ldionne
Copy link
Member

ldionne commented Jul 7, 2025

Thanks for the reviews. I'll merge this once CI is green.

@ldionne
Copy link
Member

ldionne commented Jul 8, 2025

CI is red for reasons unrelated to this patch, landing.

@ldionne ldionne merged commit fcc09b6 into llvm:main Jul 8, 2025
90 of 94 checks passed
@ldionne ldionne added this to the LLVM 20.X Release milestone Jul 8, 2025
@github-project-automation github-project-automation bot moved this to Needs Triage in LLVM Release Status Jul 8, 2025
@ldionne
Copy link
Member

ldionne commented Jul 8, 2025

/cherry-pick fcc09b6

@llvmbot
Copy link
Member

llvmbot commented Jul 8, 2025

/pull-request #147554

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
Development

Successfully merging this pull request may close these issues.

[libc++] [libc++abi] Regression: std::make_exception_ptr breaks catching ObjC objects on rethrow
6 participants