Skip to content
Merged
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions site/source/docs/porting/exceptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -171,3 +171,40 @@ Using Exceptions and setjmp-longjmp Together
============================================

See :ref:`using-exceptions-and-setjmp-longjmp-together`.


Limitations
Copy link
Collaborator

Choose a reason for hiding this comment

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

Since both of these limitation are regarding std::set_terminate should we call this section Limitations regarding std::terminate?

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

===========

* Currently `std::set_terminate
<https://en.cppreference.com/w/cpp/error/set_terminate>`_ is NOT supported
when a thrown exception does not have a matching handler and unwinds all the
stack and crashes the program. This applies to both Emscripten-style and
WebAssembly exceptions. That functionality requires `two-phase exception
handling <https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html>`_, which
neither supports.
Copy link
Collaborator

Choose a reason for hiding this comment

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

This seems to say that set_terminate will not work.. but in the example below you show it working (although without a valid current_exception). These two things seems to be in contradiction with each other.

I guess maybe the noexcept thing on main is important here and that meas that there is maybe some kind of handler implicitly added to main? but that isn't obvious to me at least ..

Copy link
Member Author

Choose a reason for hiding this comment

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

This seems to say that set_terminate will not work.. but in the example below you show it working (although without a valid current_exception). These two things seems to be in contradiction with each other.

So there's a condition written in the sentence:

... is NOT supported when a thrown exception does not have a matching handler and unwinds all the stack and crashes the program.

When we call std::terminate is not when all stack is unwound due to an exception.

I guess maybe the noexcept thing on main is important here and that means that there is maybe some kind of handler implicitly added to main? but that isn't obvious to me at least ..

If a function is marked noexcept, the code catches an exception within the function and calls std::terminate (or __clang_call_terminate, which calls std::terminate), and it does not throw the exception to the caller. So the stack unwinding does not happen.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I still think its a little confusing though since the main function you wrote looks like it doesn't catch anything (since it contains no catches).

Understanding the noexcept injects a invisible catch-all handler is required in order to understand what is going on there. That seems pretty non-obvious to me.

Maybe add comment right above main saying somthing like "The use of noexcept here means that the throw 3 will turn into a termination condition".

Copy link
Member Author

@aheejin aheejin Mar 5, 2025

Choose a reason for hiding this comment

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

Added "The use of noexcept here means that the throw 3 will turn into a termination condition" as you suggested in the second bullet point, and also added a little more clarifying words in the first bullet point.

Copy link
Member Author

Choose a reason for hiding this comment

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

Also added an example program to the first bullet point to make the situation clearer.


* When the exception handling encounters a termination condition, libc++abi
spec says we call `__cxa_begin_catch()` to mark the exception as handled and
then call `terminate()`. But currently Wasm EH does not support calling
`__cxa_begin_catch()`. So the following program prints ``exception_ptr is
null``, where it is supposed to print ``exception_ptr is NOT null``.

.. code-block:: cpp

#include <iostream>
#include <exception>

int main() noexcept {
std::set_terminate([] {
auto ptr = std::current_exception();
if (ptr)
std::cerr << "exception_ptr is NOT null" << std::endl;
else
std::cerr << "exception_ptr is null" << std::endl;
std::abort();
});
throw 3;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would writing std::terminate() here have the same effect?

Copy link
Member Author

Choose a reason for hiding this comment

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

In that case there's no exception so __cxa_begin_catch is (correctly) not called and the program (correctly) prints exception_ptr is null, so it does not show the bug (or limitation) here.

}

This can possibly be supported in the future.