Import libcxxrt 47661d00cd4d6cd728ae31b0bb29a49a6c06272a
The repository moved to https://github.com/libcxxrt/libcxxrt in the mean time, but keep it on the same branch as before. This primarily brings C++14 support.
This commit is contained in:
parent
effaea5059
commit
224744e92e
|
@ -304,13 +304,17 @@ static pthread_key_t eh_key;
|
|||
static void exception_cleanup(_Unwind_Reason_Code reason,
|
||||
struct _Unwind_Exception *ex)
|
||||
{
|
||||
__cxa_free_exception(static_cast<void*>(ex));
|
||||
// Exception layout:
|
||||
// [__cxa_exception [_Unwind_Exception]] [exception object]
|
||||
//
|
||||
// __cxa_free_exception expects a pointer to the exception object
|
||||
__cxa_free_exception(static_cast<void*>(ex + 1));
|
||||
}
|
||||
static void dependent_exception_cleanup(_Unwind_Reason_Code reason,
|
||||
struct _Unwind_Exception *ex)
|
||||
{
|
||||
|
||||
__cxa_free_dependent_exception(static_cast<void*>(ex));
|
||||
__cxa_free_dependent_exception(static_cast<void*>(ex + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -340,7 +344,8 @@ static void thread_cleanup(void* thread_info)
|
|||
if (info->foreign_exception_state != __cxa_thread_info::none)
|
||||
{
|
||||
_Unwind_Exception *e = reinterpret_cast<_Unwind_Exception*>(info->globals.caughtExceptions);
|
||||
e->exception_cleanup(_URC_FOREIGN_EXCEPTION_CAUGHT, e);
|
||||
if (e->exception_cleanup)
|
||||
e->exception_cleanup(_URC_FOREIGN_EXCEPTION_CAUGHT, e);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -516,7 +521,7 @@ static void emergency_malloc_free(char *ptr)
|
|||
break;
|
||||
}
|
||||
}
|
||||
assert(buffer > 0 &&
|
||||
assert(buffer >= 0 &&
|
||||
"Trying to free something that is not an emergency buffer!");
|
||||
// emergency_malloc() is expected to return 0-initialized data. We don't
|
||||
// zero the buffer when allocating it, because the static buffers will
|
||||
|
@ -556,7 +561,7 @@ static void free_exception(char *e)
|
|||
{
|
||||
// If this allocation is within the address range of the emergency buffer,
|
||||
// don't call free() because it was not allocated with malloc()
|
||||
if ((e > emergency_buffer) &&
|
||||
if ((e >= emergency_buffer) &&
|
||||
(e < (emergency_buffer + sizeof(emergency_buffer))))
|
||||
{
|
||||
emergency_malloc_free(e);
|
||||
|
@ -854,6 +859,13 @@ extern "C" void __cxa_rethrow()
|
|||
|
||||
assert(ex->handlerCount > 0 && "Rethrowing uncaught exception!");
|
||||
|
||||
// `globals->uncaughtExceptions` was decremented by `__cxa_begin_catch`.
|
||||
// It's normally incremented by `throw_exception`, but this path invokes
|
||||
// `_Unwind_Resume_or_Rethrow` directly to rethrow the exception.
|
||||
// This path is only reachable if we're rethrowing a C++ exception -
|
||||
// foreign exceptions don't adjust any of this state.
|
||||
globals->uncaughtExceptions++;
|
||||
|
||||
// ex->handlerCount will be decremented in __cxa_end_catch in enclosing
|
||||
// catch block
|
||||
|
||||
|
@ -1199,11 +1211,13 @@ extern "C" void *__cxa_begin_catch(void *e)
|
|||
// we see is a foreign exception then we won't have called it yet.
|
||||
__cxa_thread_info *ti = thread_info();
|
||||
__cxa_eh_globals *globals = &ti->globals;
|
||||
globals->uncaughtExceptions--;
|
||||
_Unwind_Exception *exceptionObject = static_cast<_Unwind_Exception*>(e);
|
||||
|
||||
if (isCXXException(exceptionObject->exception_class))
|
||||
{
|
||||
// Only exceptions thrown with a C++ exception throwing function will
|
||||
// increment this, so don't decrement it here.
|
||||
globals->uncaughtExceptions--;
|
||||
__cxa_exception *ex = exceptionFromPointer(exceptionObject);
|
||||
|
||||
if (ex->handlerCount == 0)
|
||||
|
@ -1280,12 +1294,13 @@ extern "C" void __cxa_end_catch()
|
|||
|
||||
if (ti->foreign_exception_state != __cxa_thread_info::none)
|
||||
{
|
||||
globals->caughtExceptions = 0;
|
||||
if (ti->foreign_exception_state != __cxa_thread_info::rethrown)
|
||||
{
|
||||
_Unwind_Exception *e = reinterpret_cast<_Unwind_Exception*>(ti->globals.caughtExceptions);
|
||||
e->exception_cleanup(_URC_FOREIGN_EXCEPTION_CAUGHT, e);
|
||||
if (e->exception_cleanup)
|
||||
e->exception_cleanup(_URC_FOREIGN_EXCEPTION_CAUGHT, e);
|
||||
}
|
||||
globals->caughtExceptions = 0;
|
||||
ti->foreign_exception_state = __cxa_thread_info::none;
|
||||
return;
|
||||
}
|
||||
|
@ -1338,6 +1353,14 @@ extern "C" std::type_info *__cxa_current_exception_type()
|
|||
return ex ? ex->exceptionType : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup, ensures that `__cxa_end_catch` is called to balance an explicit
|
||||
* `__cxa_begin_catch` call.
|
||||
*/
|
||||
static void end_catch(char *)
|
||||
{
|
||||
__cxa_end_catch();
|
||||
}
|
||||
/**
|
||||
* ABI function, called when an exception specification is violated.
|
||||
*
|
||||
|
@ -1346,6 +1369,12 @@ extern "C" std::type_info *__cxa_current_exception_type()
|
|||
extern "C" void __cxa_call_unexpected(void*exception)
|
||||
{
|
||||
_Unwind_Exception *exceptionObject = static_cast<_Unwind_Exception*>(exception);
|
||||
// Wrap the call to the unexpected handler in calls to `__cxa_begin_catch`
|
||||
// and `__cxa_end_catch` so that we correctly update exception counts if
|
||||
// the unexpected handler throws an exception.
|
||||
__cxa_begin_catch(exceptionObject);
|
||||
__attribute__((cleanup(end_catch)))
|
||||
char unused;
|
||||
if (exceptionObject->exception_class == exception_class)
|
||||
{
|
||||
__cxa_exception *ex = exceptionFromPointer(exceptionObject);
|
||||
|
@ -1471,6 +1500,15 @@ namespace std
|
|||
__cxa_thread_info *info = thread_info();
|
||||
return info->globals.uncaughtExceptions != 0;
|
||||
}
|
||||
/**
|
||||
* Returns the number of exceptions currently being thrown that have not
|
||||
* been caught. This can occur inside a nested catch statement.
|
||||
*/
|
||||
int uncaught_exceptions() throw()
|
||||
{
|
||||
__cxa_thread_info *info = thread_info();
|
||||
return info->globals.uncaughtExceptions;
|
||||
}
|
||||
/**
|
||||
* Returns the current unexpected handler.
|
||||
*/
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -71,8 +71,17 @@ namespace std
|
|||
}
|
||||
|
||||
|
||||
#if __cplusplus < 201103L
|
||||
#define NOEXCEPT throw()
|
||||
#define BADALLOC throw(std::bad_alloc)
|
||||
#else
|
||||
#define NOEXCEPT noexcept
|
||||
#define BADALLOC
|
||||
#endif
|
||||
|
||||
|
||||
__attribute__((weak))
|
||||
void* operator new(size_t size)
|
||||
void* operator new(size_t size) BADALLOC
|
||||
{
|
||||
if (0 == size)
|
||||
{
|
||||
|
@ -97,7 +106,7 @@ void* operator new(size_t size)
|
|||
}
|
||||
|
||||
__attribute__((weak))
|
||||
void* operator new(size_t size, const std::nothrow_t &) throw()
|
||||
void* operator new(size_t size, const std::nothrow_t &) NOEXCEPT
|
||||
{
|
||||
try {
|
||||
return :: operator new(size);
|
||||
|
@ -110,27 +119,21 @@ void* operator new(size_t size, const std::nothrow_t &) throw()
|
|||
|
||||
|
||||
__attribute__((weak))
|
||||
void operator delete(void * ptr)
|
||||
#if __cplusplus < 201000L
|
||||
throw()
|
||||
#endif
|
||||
void operator delete(void * ptr) NOEXCEPT
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
|
||||
__attribute__((weak))
|
||||
void * operator new[](size_t size)
|
||||
#if __cplusplus < 201000L
|
||||
throw(std::bad_alloc)
|
||||
#endif
|
||||
void * operator new[](size_t size) BADALLOC
|
||||
{
|
||||
return ::operator new(size);
|
||||
}
|
||||
|
||||
|
||||
__attribute__((weak))
|
||||
void * operator new[](size_t size, const std::nothrow_t &) throw()
|
||||
void * operator new[](size_t size, const std::nothrow_t &) NOEXCEPT
|
||||
{
|
||||
try {
|
||||
return ::operator new[](size);
|
||||
|
@ -143,12 +146,26 @@ void * operator new[](size_t size, const std::nothrow_t &) throw()
|
|||
|
||||
|
||||
__attribute__((weak))
|
||||
void operator delete[](void * ptr)
|
||||
#if __cplusplus < 201000L
|
||||
throw()
|
||||
#endif
|
||||
void operator delete[](void * ptr) NOEXCEPT
|
||||
{
|
||||
::operator delete(ptr);
|
||||
}
|
||||
|
||||
// C++14 additional delete operators
|
||||
|
||||
#if __cplusplus >= 201402L
|
||||
|
||||
__attribute__((weak))
|
||||
void operator delete(void * ptr, size_t) NOEXCEPT
|
||||
{
|
||||
::operator delete(ptr);
|
||||
}
|
||||
|
||||
|
||||
__attribute__((weak))
|
||||
void operator delete[](void * ptr, size_t) NOEXCEPT
|
||||
{
|
||||
::operator delete(ptr);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -86,15 +86,7 @@ extern "C" char* __cxa_demangle(const char* mangled_name,
|
|||
if (NULL != demangled)
|
||||
{
|
||||
size_t len = strlen(demangled);
|
||||
if (buf == NULL)
|
||||
{
|
||||
if (n)
|
||||
{
|
||||
*n = len;
|
||||
}
|
||||
return demangled;
|
||||
}
|
||||
if (*n < len+1)
|
||||
if (!buf || (*n < len+1))
|
||||
{
|
||||
buf = static_cast<char*>(realloc(buf, len+1));
|
||||
}
|
||||
|
|
|
@ -20,15 +20,19 @@
|
|||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* For uint32_t and uint64_t */
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* ARM-specific unwind definitions. These are taken from the ARM EHABI
|
||||
* specification.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
_URC_NO_REASON = 0,
|
||||
_URC_OK = 0, /* operation completed successfully */
|
||||
_URC_FOREIGN_EXCEPTION_CAUGHT = 1,
|
||||
_URC_END_OF_STACK = 5,
|
||||
_URC_END_OF_STACK = 5,
|
||||
_URC_HANDLER_FOUND = 6,
|
||||
_URC_INSTALL_CONTEXT = 7,
|
||||
_URC_CONTINUE_UNWIND = 8,
|
||||
|
@ -41,10 +45,12 @@ typedef uint32_t _Unwind_State;
|
|||
static const _Unwind_State _US_VIRTUAL_UNWIND_FRAME = 0;
|
||||
static const _Unwind_State _US_UNWIND_FRAME_STARTING = 1;
|
||||
static const _Unwind_State _US_UNWIND_FRAME_RESUME = 2;
|
||||
static const _Unwind_State _US_ACTION_MASK = 3;
|
||||
#else // GCC fails at knowing what a constant expression is
|
||||
# define _US_VIRTUAL_UNWIND_FRAME 0
|
||||
# define _US_UNWIND_FRAME_STARTING 1
|
||||
# define _US_UNWIND_FRAME_RESUME 2
|
||||
# define _US_UNWIND_FRAME_RESUME 2
|
||||
# define _US_ACTION_MASK 3
|
||||
#endif
|
||||
|
||||
typedef struct _Unwind_Context _Unwind_Context;
|
||||
|
@ -89,7 +95,7 @@ struct _Unwind_Exception
|
|||
} pr_cache;
|
||||
/** Force alignment of next item to 8-byte boundary */
|
||||
long long int :0;
|
||||
};
|
||||
} __attribute__((__aligned__(8)));
|
||||
|
||||
/* Unwinding functions */
|
||||
_Unwind_Reason_Code _Unwind_RaiseException(struct _Unwind_Exception *ucbp);
|
||||
|
|
|
@ -40,6 +40,7 @@ extern "C" {
|
|||
typedef enum
|
||||
{
|
||||
_URC_NO_REASON = 0,
|
||||
_URC_OK = 0,
|
||||
_URC_FOREIGN_EXCEPTION_CAUGHT = 1,
|
||||
_URC_FATAL_PHASE2_ERROR = 2,
|
||||
_URC_FATAL_PHASE1_ERROR = 3,
|
||||
|
@ -78,9 +79,12 @@ struct _Unwind_Exception
|
|||
{
|
||||
uint64_t exception_class;
|
||||
_Unwind_Exception_Cleanup_Fn exception_cleanup;
|
||||
unsigned long private_1;
|
||||
unsigned long private_2;
|
||||
} ;
|
||||
uintptr_t private_1;
|
||||
uintptr_t private_2;
|
||||
#if __SIZEOF_POINTER__ == 4
|
||||
uint32_t reserved[3];
|
||||
#endif
|
||||
} __attribute__((__aligned__));
|
||||
|
||||
extern _Unwind_Reason_Code _Unwind_RaiseException (struct _Unwind_Exception *);
|
||||
extern _Unwind_Reason_Code _Unwind_ForcedUnwind (struct _Unwind_Exception *,
|
||||
|
|
|
@ -35,6 +35,7 @@ static void __attribute__((constructor)) init(void)
|
|||
void test_type_info(void);
|
||||
void test_exceptions();
|
||||
void test_guards(void);
|
||||
void test_demangle(void);
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ch;
|
||||
|
@ -52,5 +53,6 @@ int main(int argc, char **argv)
|
|||
test_type_info();
|
||||
test_guards();
|
||||
test_exceptions();
|
||||
test_demangle();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -2,3 +2,4 @@
|
|||
void log_test(bool predicate, const char *file, int line, const char *message);
|
||||
|
||||
#define TEST(p, m) log_test(p, __FILE__, __LINE__, m)
|
||||
#define TEST_LOC(p, m, file, line) log_test(p, file, line, m)
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
#include "test.h"
|
||||
#include <cxxabi.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <list>
|
||||
|
||||
template <typename T> void test(const char* expected, int line) {
|
||||
const char *mangled = typeid(T).name();
|
||||
int status = 0;
|
||||
using abi::__cxa_demangle;
|
||||
char* demangled = __cxa_demangle(mangled, 0, 0, &status);
|
||||
printf("mangled='%s' demangled='%s', status=%d\n", mangled, demangled,
|
||||
status);
|
||||
free(demangled);
|
||||
TEST_LOC(status == 0, "should be able to demangle", __FILE__, line);
|
||||
TEST_LOC(demangled != 0, "should be able to demangle", __FILE__, line);
|
||||
if (!demangled) {
|
||||
/* Don't dereference NULL in strcmp() */
|
||||
return;
|
||||
}
|
||||
TEST_LOC(strcmp(expected, demangled) == 0, "should be able to demangle",
|
||||
__FILE__, line);
|
||||
TEST_LOC(strcmp(mangled, demangled) != 0, "should be able to demangle",
|
||||
__FILE__, line);
|
||||
}
|
||||
|
||||
|
||||
namespace N {
|
||||
template<typename T, int U>
|
||||
class Templated {
|
||||
virtual ~Templated() {};
|
||||
};
|
||||
}
|
||||
|
||||
void test_demangle(void)
|
||||
{
|
||||
using namespace N;
|
||||
test<int>("int", __LINE__);
|
||||
test<char[4]>("char [4]", __LINE__);
|
||||
test<char[]>("char []", __LINE__);
|
||||
test<Templated<Templated<long, 7>, 8> >(
|
||||
"N::Templated<N::Templated<long, 7>, 8>", __LINE__);
|
||||
test<Templated<void(long), -1> >(
|
||||
"N::Templated<void (long), -1>", __LINE__);
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
#include "test.h"
|
||||
#include "unwind.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
@ -7,12 +8,12 @@
|
|||
|
||||
#define fprintf(...)
|
||||
|
||||
void log(void* ignored)
|
||||
void log_cleanup(void* ignored)
|
||||
{
|
||||
//printf("Cleanup called on %s\n", *(char**)ignored);
|
||||
}
|
||||
#define CLEANUP\
|
||||
__attribute__((cleanup(log))) __attribute__((unused))\
|
||||
__attribute__((cleanup(log_cleanup))) __attribute__((unused))\
|
||||
const char *f = __func__;
|
||||
|
||||
/**
|
||||
|
@ -191,6 +192,136 @@ static void throw_zero()
|
|||
throw 0;
|
||||
}
|
||||
|
||||
struct uncaught_exception_checker
|
||||
{
|
||||
uncaught_exception_checker(bool uncaught) : m_uncaught(uncaught) {}
|
||||
~uncaught_exception_checker() {
|
||||
if (std::uncaught_exception())
|
||||
TEST(m_uncaught, "At least one uncaught exception is in flight");
|
||||
else
|
||||
TEST(!m_uncaught, "No uncaught exceptions are in flight");
|
||||
}
|
||||
bool m_uncaught;
|
||||
};
|
||||
|
||||
void test_rethrown_uncaught_exception()
|
||||
{
|
||||
uncaught_exception_checker outer(false);
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
throw 42;
|
||||
}
|
||||
catch (int)
|
||||
{
|
||||
uncaught_exception_checker inner(true);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
catch (...) {}
|
||||
}
|
||||
|
||||
static void exception_cleanup(_Unwind_Reason_Code, struct _Unwind_Exception *ex)
|
||||
{
|
||||
delete ex;
|
||||
}
|
||||
|
||||
void test_rethrown_uncaught_foreign_exception()
|
||||
{
|
||||
uncaught_exception_checker outer(false);
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
// Throw a foreign exception.
|
||||
_Unwind_Exception *ex = new _Unwind_Exception;
|
||||
ex->exception_class = 1234;
|
||||
ex->exception_cleanup = exception_cleanup;
|
||||
_Unwind_RaiseException(ex);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Note: Uncaught exceptions doesn't report foreign exceptions,
|
||||
// because we have no way of receiving a report that the other
|
||||
// language has caught it.
|
||||
uncaught_exception_checker inner(false);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
catch (...) {}
|
||||
}
|
||||
|
||||
|
||||
void test_uncaught_exception()
|
||||
{
|
||||
uncaught_exception_checker outer(false);
|
||||
try {
|
||||
uncaught_exception_checker inner(true);
|
||||
throw 42;
|
||||
}
|
||||
catch (...) {}
|
||||
}
|
||||
|
||||
struct uncaught_exceptions_checker
|
||||
{
|
||||
uncaught_exceptions_checker(int uncaught) : m_uncaught(uncaught) {}
|
||||
~uncaught_exceptions_checker() {
|
||||
char msg[128];
|
||||
int uncaught = std::uncaught_exceptions();
|
||||
snprintf(msg, sizeof msg, "%d uncaught exception%s in flight",
|
||||
uncaught, uncaught == 1 ? " is" : "s are");
|
||||
TEST(uncaught == m_uncaught, msg);
|
||||
}
|
||||
int m_uncaught;
|
||||
};
|
||||
|
||||
class top {
|
||||
public:
|
||||
~top() {
|
||||
try {
|
||||
uncaught_exceptions_checker uec(4);
|
||||
throw "top";
|
||||
}
|
||||
catch (...) {}
|
||||
}
|
||||
};
|
||||
|
||||
class middle {
|
||||
public:
|
||||
~middle() {
|
||||
try {
|
||||
top f;
|
||||
uncaught_exceptions_checker uec(3);
|
||||
throw "middle";
|
||||
}
|
||||
catch (...) {}
|
||||
}
|
||||
};
|
||||
|
||||
class bottom {
|
||||
public:
|
||||
~bottom() {
|
||||
try {
|
||||
middle f;
|
||||
uncaught_exceptions_checker uec(2);
|
||||
throw "bottom";
|
||||
}
|
||||
catch (...) {}
|
||||
}
|
||||
};
|
||||
|
||||
void test_uncaught_exceptions()
|
||||
{
|
||||
uncaught_exceptions_checker outer(0);
|
||||
try {
|
||||
bottom b;
|
||||
uncaught_exceptions_checker inner(1);
|
||||
throw "test";
|
||||
}
|
||||
catch (...) {}
|
||||
}
|
||||
|
||||
extern "C" void __cxa_bad_cast();
|
||||
|
||||
void test_exceptions(void)
|
||||
|
@ -237,6 +368,10 @@ void test_exceptions(void)
|
|||
TEST(0, "Bad cast was not caught correctly");
|
||||
}
|
||||
test_const();
|
||||
test_uncaught_exception();
|
||||
test_rethrown_uncaught_exception();
|
||||
test_rethrown_uncaught_foreign_exception();
|
||||
test_uncaught_exceptions();
|
||||
|
||||
|
||||
//printf("Test: %s\n",
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include "unwind.h"
|
||||
|
||||
#define EXCEPTION_CLASS(a,b,c,d,e,f,g,h) \
|
||||
((static_cast<uint64_t>(a) << 56) +\
|
||||
(static_cast<uint64_t>(b) << 48) +\
|
||||
(static_cast<uint64_t>(c) << 40) +\
|
||||
(static_cast<uint64_t>(d) << 32) +\
|
||||
(static_cast<uint64_t>(e) << 24) +\
|
||||
(static_cast<uint64_t>(f) << 16) +\
|
||||
(static_cast<uint64_t>(g) << 8) +\
|
||||
(static_cast<uint64_t>(h)))
|
||||
|
||||
// using ld --wrap=_Unwind_RaiseException hook feature
|
||||
extern "C" _Unwind_Reason_Code __real__Unwind_RaiseException (_Unwind_Exception *e);
|
||||
extern "C" _Unwind_Reason_Code __wrap__Unwind_RaiseException (_Unwind_Exception *e);
|
||||
|
||||
extern "C" _Unwind_Reason_Code __wrap__Unwind_RaiseException (_Unwind_Exception *e)
|
||||
{
|
||||
// clobber exception class forcing libcxx own exceptions to be treated
|
||||
// as foreign exception within libcxx itself
|
||||
e->exception_class = EXCEPTION_CLASS('F','O','R','E','I','G','N','\0');
|
||||
__real__Unwind_RaiseException(e);
|
||||
}
|
||||
|
||||
_Unwind_Exception global_e;
|
||||
|
||||
enum test_status {
|
||||
PENDING, PASSED, FAILED
|
||||
};
|
||||
|
||||
const char test_status_str[][8] = {
|
||||
"PENDING", "PASSED", "FAILED"
|
||||
};
|
||||
|
||||
test_status test1_status = PENDING;
|
||||
test_status test2_status = PENDING;
|
||||
test_status test3_status = PENDING;
|
||||
|
||||
void test2_exception_cleanup(_Unwind_Reason_Code code, _Unwind_Exception *e)
|
||||
{
|
||||
fputs("(2) exception_cleanup called\n", stderr);
|
||||
if (e != &global_e) {
|
||||
fprintf(stderr, "(2) ERROR: unexpected ptr: expecting %p, got %p\n", &global_e, e);
|
||||
test2_status = FAILED;
|
||||
}
|
||||
if (test2_status == PENDING)
|
||||
test2_status = PASSED;
|
||||
}
|
||||
|
||||
struct test3_exception
|
||||
{
|
||||
static int counter;
|
||||
~test3_exception()
|
||||
{
|
||||
counter++;
|
||||
fputs("(3) exception dtor\n", stderr);
|
||||
}
|
||||
};
|
||||
int test3_exception::counter = 0;
|
||||
|
||||
int main()
|
||||
{
|
||||
///////////////////////////////////////////////////////////////
|
||||
fputs("(1) foreign exception, exception_cleanup=nullptr\n", stderr);
|
||||
try
|
||||
{
|
||||
global_e.exception_class = 0;
|
||||
global_e.exception_cleanup = 0;
|
||||
__real__Unwind_RaiseException(&global_e);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
test1_status = PASSED;
|
||||
fputs("(1) PASS\n", stderr);
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
fputs("(2) foreign exception, exception_cleanup present\n", stderr);
|
||||
try
|
||||
{
|
||||
global_e.exception_class = 0;
|
||||
global_e.exception_cleanup = test2_exception_cleanup;
|
||||
__real__Unwind_RaiseException(&global_e);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
fprintf(stderr, "(2) %s\n", test_status_str[test2_status]);
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
fputs("(3) C++ exception in foreign environment\n", stderr);
|
||||
int counter_expected;
|
||||
try
|
||||
{
|
||||
// throw was rigged such that the runtime treats C++ exceptions
|
||||
// as foreign ones
|
||||
throw test3_exception();
|
||||
}
|
||||
catch (test3_exception&)
|
||||
{
|
||||
fputs("(3) ERROR: wrong catch\n", stderr);
|
||||
test3_status = FAILED;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
fputs("(3) catch(...)\n", stderr);
|
||||
counter_expected = test3_exception::counter + 1;
|
||||
// one more dtor immediately after we leave catch
|
||||
}
|
||||
if (test3_status == PENDING && test3_exception::counter != counter_expected) {
|
||||
fputs("(3) ERROR: exception dtor didn't run\n", stderr);
|
||||
test3_status = FAILED;
|
||||
}
|
||||
if (test3_status == PENDING)
|
||||
test3_status = PASSED;
|
||||
fprintf(stderr, "(3) %s\n", test_status_str[test3_status]);
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
if (test1_status == PASSED && test2_status == PASSED && test3_status == PASSED)
|
||||
return EXIT_SUCCESS;
|
||||
else
|
||||
return EXIT_FAILURE;
|
||||
}
|
Loading…
Reference in New Issue