diff --git a/libcxxabi/test/forced_unwind1.pass.cpp b/libcxxabi/test/forced_unwind1.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxxabi/test/forced_unwind1.pass.cpp @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// _Unwind_ForcedUnwind raised exception can be caught by catch (...) and be +// rethrown. If not rethrown, exception_cleanup will be called. + +// UNSUPPORTED: no-exceptions, c++03 + +#include +#include +#include +#include + +static int bits = 0; + +struct C { + int bit; + C(int b) : bit(b) {} + ~C() { bits |= bit; } +}; + +template +struct Stop; + +template +struct Stop { + // The third argument of _Unwind_Stop_Fn is uint64_t in Itanium C++ ABI/LLVM + // libunwind while _Unwind_Exception_Class in libgcc. + typedef typename std::tuple_element<2, std::tuple>::type type; + + static _Unwind_Reason_Code stop(int, _Unwind_Action actions, type, + struct _Unwind_Exception*, + struct _Unwind_Context*, void*) { + if (actions & _UA_END_OF_STACK) + abort(); + return _URC_NO_REASON; + } +}; + +static void cleanup(_Unwind_Reason_Code, struct _Unwind_Exception* exc) { + bits |= 8; + delete exc; +} + +static void forced_unwind() { + _Unwind_Exception* exc = new _Unwind_Exception; + exc->exception_class = 0; + exc->exception_cleanup = cleanup; + _Unwind_ForcedUnwind(exc, Stop<_Unwind_Stop_Fn>::stop, 0); + abort(); +} + +static void test() { + try { + C four(4); + try { + C one(1); + forced_unwind(); + } catch (...) { + bits |= 2; + throw; + } + } catch (int) { + } catch (...) { + // __cxa_end_catch calls cleanup. + } +} + +int main() { + test(); + return bits != 15; +} diff --git a/libcxxabi/test/forced_unwind2.pass.cpp b/libcxxabi/test/forced_unwind2.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxxabi/test/forced_unwind2.pass.cpp @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// Forced unwinding causes std::terminate when going through noexcept. + +// UNSUPPORTED: no-exceptions, c++03 + +#include +#include +#include +#include +#include +#include + +template +struct Stop; + +template +struct Stop { + // The third argument of _Unwind_Stop_Fn is uint64_t in Itanium C++ ABI/LLVM + // libunwind while _Unwind_Exception_Class in libgcc. + typedef typename std::tuple_element<2, std::tuple>::type type; + + static _Unwind_Reason_Code stop(int, _Unwind_Action actions, type, + struct _Unwind_Exception*, + struct _Unwind_Context*, void*) { + if (actions & _UA_END_OF_STACK) + abort(); + return _URC_NO_REASON; + } +}; + +static void forced_unwind() { + _Unwind_Exception* exc = new _Unwind_Exception; + exc->exception_class = 0; + exc->exception_cleanup = 0; + _Unwind_ForcedUnwind(exc, Stop<_Unwind_Stop_Fn>::stop, 0); + abort(); +} + +static void test() noexcept { forced_unwind(); } + +static void terminate() { exit(0); } + +int main() { + std::set_terminate(terminate); + try { + test(); + } catch (...) { + } + abort(); +}