.. _exceptions:

======================
C++ Exceptions Support
======================

By default, exception catching is disabled in Emscripten. For example, if you
compile the following program:

.. code-block:: cpp

    #include <stdio.h>

    int main() {
      try {
        puts("throw...");
        throw 1;
        puts("(never reached)");
      } catch(...) {
        puts("catch!");
      }
      return 0;
    }

The first ``throw`` will abort the program and you'll see something like this in
the output:

.. code-block:: text

  throw...
  Aborted(Assertion failed: Exception thrown, but exception catching is not enabled. Compile with -sNO_DISABLE_EXCEPTION_CATCHING or -sEXCEPTION_CATCHING_ALLOWED=[..] to catch.)

If you want to opt-in, you have two following options.


.. _javascript-based-exception-support:

Emscripten (JavaScript-based) Exception Support
===============================================

First, you can enable exceptions via Emscripten's JavaScript-based support. To
enable it, pass ``-fexceptions`` at both compile time and link time.

When you rebuild the example above with this flag, the output will change to:

.. code-block:: text

  throw...
  catch!

Note that this option has relatively high overhead, but it will work on all
JavaScript engines with WebAssembly support. You can reduce the overhead by
specifying a list of allowed functions in which exceptions are enabled, see the
``EXCEPTION_CATCHING_ALLOWED`` setting.


.. _webassembly-exception-handling-based-support:

WebAssembly Exception Handling-based Support
============================================

Alternatively, you can opt-in to the `native WebAssembly exception handling
<https://github.com/WebAssembly/exception-handling/blob/master/proposals/exception-handling/Exceptions.md>`_
proposal. To enable it, pass ``-fwasm-exceptions`` at both compile time and link
time.

Rebuilding the example with this flag will result in the same output as with
``-fexceptions`` above:

.. code-block:: text

  throw...
  catch!

This option leverages a new feature that brings built-in instructions for
throwing and catching exceptions to WebAssembly. As a result, it can reduce code
size and performance overhead compared to the JavaScript-based implementation.
This option is currently supported in several major web browsers, but `may not
be supported in all WebAssembly engines yet
<https://webassembly.org/roadmap/>`_.


Debugging Exceptions
====================

Stack Traces
------------

For :ref:`native Wasm exceptions
<webassembly-exception-handling-based-support>`, when :ref:`ASSERTIONS
<debugging-ASSERTIONS>` is enabled, uncaught exceptions will print stack traces
for debugging. :ref:`ASSERTIONS <debugging-ASSERTIONS>` is enabled by default
in :ref:`-O0 <emcc-O0>` and disabled in optimized builds (:ref:`-O1 <emcc-O1>`
and above). You can enable it by passing ``-sASSERTIONS`` to the ``emcc``
command line in optimized builds as well. To display Wasm function names in
stack traces, you also need :ref:`--profiling-funcs <emcc-profiling-funcs>`
(or :ref:`-g <emcc-g>` or :ref:`-gsource-map<emcc-gsource-map>`).

In JavaScript, you can also examine the stack traces using
`WebAssembly.Exception.prototype.stack
<https://developer.mozilla.org/en-US/docs/WebAssembly/JavaScript_interface/Exception/stack>`_
property. For example:

.. code-block:: javascript

  try {
    ... // some code that calls WebAssembly
  } catch (e) {
    // Do something with e.stack
    console.log(e.stack);
  }

Stack traces within Wasm code are not supported in :ref:`JavaScript-based
exceptions <javascript-based-exception-support>`.


.. _handling-c-exceptions-from-javascript:

Handling C++ Exceptions from JavaScript
---------------------------------------

You can also catch and examine the type and the message of C++ exceptions from
JavaScript, in case they inherit from ``std::exception`` and thus have ``what``
method.

``getExceptionMessage`` returns a list of two strings: ``[type, message]``. the
``message`` is the result of calling ``what`` method in case the exception is a
subclass of ``std::exception``. Otherwise it will be just an empty string.

.. code-block:: javascript

  var sp = stackSave();
  try {
    ... // some code that calls WebAssembly
  } catch (e) {
    stackRestore(sp);
    console.log(getExceptionMessage(e).toString());
  } finally {
    ...
  }

In case the thrown value is an integer 3, this will print ``int,``, because the
message part is empty. If the thrown value is an instance of ``MyException``
that is a subclass of ``std::exception`` and its ``what`` message is ``My
exception thrown``, this code will print ``MyException,My exception thrown``.

``getExceptionMessage`` is available when exceptions are used and either
``-sASSERTIONS`` or ``-sEXCEPTION_STACK_TRACES`` is set, which are by default
true at ``-O0``.  At ``-O1`` or above, you can export it separately by
``-sEXPORTED_RUNTIME_METHODS=getExceptionMessage,decrementExceptionRefcount``.

If the stack pointer has been moved due to stack allocations within the Wasm
function before an exception is thrown, you can use ``stackSave()`` and
``stackRestore()`` to restore the stack pointer so that no stack memory is
leaked.

.. note:: If you catch a Wasm exception and do not rethrow it, you need to free
   the storage associated with the exception in JS using
   ``decrementExceptionRefcount`` method because the exception catching code in
   Wasm does not have a chance to free it. See ``test_getExceptionMessage`` in
   ``test/test_core.py`` for an example usage.


Using Exceptions and setjmp-longjmp Together
============================================

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


Limitations regarding std::terminate()
======================================

  * 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 up to the topmost caller and crashes the program, i.e., there is no
    ``catch`` that catches it and the callers are not marked as ``noexcept``.
    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. So the following program does NOT print ``my set_terminate``:

    .. code-block:: cpp

        #include <iostream>
        #include <exception>

        int main() {
          std::set_terminate([] {
            std::cerr << "my set_terminate" << std::endl;
            std::abort();
          });
          throw 3;
        }

  * 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 `std::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``; note
    that the use of ``noexcept`` here means that the ``throw 3`` will turn into
    a termination condition.

    .. 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;
        }

    This can possibly be supported in the future.
