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:
joerg 2021-05-30 00:08:19 +00:00
parent effaea5059
commit 224744e92e
11 changed files with 1239 additions and 436 deletions

View File

@ -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,6 +344,7 @@ 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);
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);
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

View File

@ -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

View File

@ -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));
}

View File

@ -20,12 +20,16 @@
* 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,
@ -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_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);

View File

@ -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 *,

View File

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

View File

@ -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)

View File

@ -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__);
}

View File

@ -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",

View File

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