4491bb19df
Under some circumstances there is no struct _Unwind_Exception, it's just an alias to another struct. This would result in an error like this: libcxxabi/test/forced_unwind3.pass.cpp:50:77: error: typedef '_Unwind_Exception' cannot be referenced with a struct specifier static _Unwind_Reason_Code stop(int, _Unwind_Action actions, type, struct _Unwind_Exception*, struct _Unwind_Context*, ^ <...>/lib/clang/15.0.0/include/unwind.h:68:38: note: declared here typedef struct _Unwind_Control_Block _Unwind_Exception; /* Alias */ ^ This seems to have been an issue since the test was first added in D109856, except that it didn't surface with Clang 14 because the code is filtered out by the preprocessor if `__clang_major__ < 15`. Reviewed By: danielkiss, mstorsjo, #libc_abi, ldionne Differential Revision: https://reviews.llvm.org/D132873
80 lines
2.1 KiB
C++
80 lines
2.1 KiB
C++
//===----------------------------------------------------------------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Let's run ForcedUnwind until it reaches end of the stack, this test simulates
|
|
// what pthread_cancel does.
|
|
|
|
// UNSUPPORTED: c++03
|
|
// UNSUPPORTED: no-threads
|
|
// UNSUPPORTED: no-exceptions
|
|
|
|
#include <assert.h>
|
|
#include <exception>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unwind.h>
|
|
#include <thread>
|
|
#include <tuple>
|
|
#include <__cxxabi_config.h>
|
|
|
|
// TODO: dump version back to 14 once clang is updated on the CI.
|
|
#if defined(_LIBCXXABI_ARM_EHABI) && defined(__clang__) && __clang_major__ < 15
|
|
// _Unwind_ForcedUnwind is not available or broken before version 14.
|
|
int main(int, char**) { return 0; }
|
|
|
|
#else
|
|
static bool destructorCalled = false;
|
|
|
|
struct myClass {
|
|
myClass() {}
|
|
~myClass() {
|
|
assert(destructorCalled == false);
|
|
destructorCalled = true;
|
|
};
|
|
};
|
|
|
|
template <typename T>
|
|
struct Stop;
|
|
|
|
template <typename R, typename... Args>
|
|
struct Stop<R (*)(Args...)> {
|
|
// 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<Args...>>::type type;
|
|
|
|
static _Unwind_Reason_Code stop(int, _Unwind_Action actions, type, _Unwind_Exception*, struct _Unwind_Context*,
|
|
void*) {
|
|
if (actions & _UA_END_OF_STACK) {
|
|
assert(destructorCalled == true);
|
|
exit(0);
|
|
}
|
|
return _URC_NO_REASON;
|
|
}
|
|
};
|
|
|
|
static void forced_unwind() {
|
|
_Unwind_Exception* exc = new _Unwind_Exception;
|
|
memset(&exc->exception_class, 0, sizeof(exc->exception_class));
|
|
exc->exception_cleanup = 0;
|
|
_Unwind_ForcedUnwind(exc, Stop<_Unwind_Stop_Fn>::stop, 0);
|
|
abort();
|
|
}
|
|
|
|
__attribute__((__noinline__)) static void test() {
|
|
myClass c{};
|
|
forced_unwind();
|
|
abort();
|
|
}
|
|
|
|
int main(int, char**) {
|
|
std::thread t{test};
|
|
t.join();
|
|
return -1;
|
|
}
|
|
#endif
|