Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 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
8 changes: 8 additions & 0 deletions system/lib/libcxx/include/exception
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,11 @@ unexpected_handler get_unexpected() noexcept;
typedef void (*terminate_handler)();
terminate_handler set_terminate(terminate_handler f ) noexcept;
terminate_handler get_terminate() noexcept;
#ifdef __USING_WASM_EXCEPTIONS__
Copy link
Member

Choose a reason for hiding this comment

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

Might want to add a comment here, or just point people to libcxxabi for an explanation. Unless that's obvious enough?

Copy link
Member Author

Choose a reason for hiding this comment

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

I was not sure if it would be OK to copy-paste the same comment four times. Did that anyway.

[[noreturn]] void terminate();
#else
[[noreturn]] void terminate() noexcept;
#endif

bool uncaught_exception() noexcept;
int uncaught_exceptions() noexcept; // C++17
Expand Down Expand Up @@ -128,7 +132,11 @@ _LIBCPP_NORETURN _LIBCPP_FUNC_VIS void unexpected();
typedef void (*terminate_handler)();
_LIBCPP_FUNC_VIS terminate_handler set_terminate(terminate_handler) _NOEXCEPT;
_LIBCPP_FUNC_VIS terminate_handler get_terminate() _NOEXCEPT;
#ifdef __USING_WASM_EXCEPTIONS__
_LIBCPP_NORETURN _LIBCPP_FUNC_VIS void terminate();
#else
_LIBCPP_NORETURN _LIBCPP_FUNC_VIS void terminate() _NOEXCEPT;
#endif

_LIBCPP_FUNC_VIS bool uncaught_exception() _NOEXCEPT;
_LIBCPP_FUNC_VIS _LIBCPP_AVAILABILITY_UNCAUGHT_EXCEPTIONS int uncaught_exceptions() _NOEXCEPT;
Expand Down
12 changes: 12 additions & 0 deletions system/lib/libcxxabi/src/cxa_handlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,13 @@ get_terminate() noexcept
}

void
#ifdef __USING_WASM_EXCEPTIONS__
// In Wasm EH, a JS exception thrown by abort() is caught by 'noexcept' cleanup
// from which std::__terminate is called again, causing an infinite loop
__terminate(terminate_handler func)
#else
__terminate(terminate_handler func) noexcept
#endif
{
#ifndef _LIBCXXABI_NO_EXCEPTIONS
try
Expand All @@ -71,7 +77,13 @@ __terminate(terminate_handler func) noexcept

__attribute__((noreturn))
void
#ifdef __USING_WASM_EXCEPTIONS__
// In Wasm EH, a JS exception thrown by abort() is caught by 'noexcept' cleanup
// from which std::terminate is called again, causing an infinite loop
terminate()
#else
terminate() noexcept
#endif
{
#if !defined(_LIBCXXABI_NO_EXCEPTIONS) && !defined(__USING_EMSCRIPTEN_EXCEPTIONS__)
// If there might be an uncaught exception
Expand Down
4 changes: 4 additions & 0 deletions system/lib/libcxxabi/src/cxa_handlers.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ __unexpected(unexpected_handler func);

_LIBCXXABI_HIDDEN _LIBCXXABI_NORETURN
void
#ifdef __USING_WASM_EXCEPTIONS__
__terminate(terminate_handler func);
#else
__terminate(terminate_handler func) noexcept;
#endif

} // std

Expand Down
18 changes: 18 additions & 0 deletions tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -1639,6 +1639,24 @@ class Polymorphic {virtual void member(){}};
}
''', 'exception caught: std::bad_typeid')

@with_both_eh_sjlj
def test_std_terminate(self):
# std::terminate eventually calls abort(), which is implemented with
# throwing a JS exception, which used to cause an infinite loop that
# exhausted the call stack. The reason is std::terminate is marked
# 'noexcept' in the upstream LLVM, which generates cleanuppads that call
# std::terminate in case of an unexpected second exception happens while
# aborting, and our abort() was considered as that second exception. We
# removed 'noexcept' from std::terminate signature when Wasm EH is enabled
# to avoid this issue.
err = self.do_run(r'''
#include <exception>
int main() {
std::terminate();
}
''', assert_returncode=NON_ZERO)
self.assertNotContained('Maximum call stack size exceeded', err)

def test_iostream_ctors(self):
# iostream stuff must be globally constructed before user global
# constructors, so iostream works in global constructors
Expand Down