aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2024-01-25 17:05:41 +0000
committerDimitry Andric <dim@FreeBSD.org>2024-01-25 17:05:41 +0000
commit156745f575946b366c430fc2bc7b9a90d5925b29 (patch)
treee6c05ad7994d2d78c857a4397dace716751f4858
parent672085f2aef23a8ab5b73f97279f3b9a5f207d8a (diff)
downloadsrc-vendor/libcxxrt.tar.gz
src-vendor/libcxxrt.zip
Import libcxxrt master 03c83f5a57be8c5b1a29a68de5638744f17d28bavendor/libcxxrt/2024-01-25-fd484be8d1e94a1fcf6bc5c67e5c07b65ada19b6vendor/libcxxrt
Interesting fixes: 03c83f5 add __cxa_init_primary_exception (#23) 5d8a158 Fix two bugs in __cxa_end_cleanup() b00c6c5 Insert padding in __cxa_dependent_exception 45ca8b1 Insert padding in __cxa_exception struct for compatibility f2e5509 Fix unlock in two-word version and add missing comment. 6229590 Add an option for disabling emergency buffers. (#14)
-rw-r--r--cxxabi.h15
-rw-r--r--exception.cc60
-rw-r--r--guard.cc9
3 files changed, 73 insertions, 11 deletions
diff --git a/cxxabi.h b/cxxabi.h
index 411c4c749ccf..e021f85c905a 100644
--- a/cxxabi.h
+++ b/cxxabi.h
@@ -78,6 +78,13 @@ struct __cxa_exception
{
#if __LP64__
/**
+ * Now _Unwind_Exception is marked with __attribute__((aligned)), which
+ * implies __cxa_exception is also aligned. Insert padding in the
+ * beginning of the struct, rather than before unwindHeader.
+ */
+ void *reserve;
+
+ /**
* Reference count. Used to support the C++11 exception_ptr class. This
* is prepended to the structure in 64-bit mode and squeezed in to the
* padding left before the 64-bit aligned _Unwind_Exception at the end in
@@ -196,6 +203,14 @@ __cxa_eh_globals *__cxa_get_globals_fast(void);
std::type_info * __cxa_current_exception_type();
+
+void *__cxa_allocate_exception(size_t thrown_size);
+
+void __cxa_free_exception(void* thrown_exception);
+
+__cxa_exception *__cxa_init_primary_exception(
+ void *object, std::type_info* tinfo, void (*dest)(void *));
+
/**
* Throws an exception returned by __cxa_current_primary_exception(). This
* exception may have been caught in another thread.
diff --git a/exception.cc b/exception.cc
index 57c818839e80..15f93aeb23dc 100644
--- a/exception.cc
+++ b/exception.cc
@@ -162,6 +162,7 @@ struct __cxa_thread_info
terminate_handler terminateHandler;
/** The unexpected exception handler for this thread. */
unexpected_handler unexpectedHandler;
+#ifndef LIBCXXRT_NO_EMERGENCY_MALLOC
/**
* The number of emergency buffers held by this thread. This is 0 in
* normal operation - the emergency buffers are only used when malloc()
@@ -170,6 +171,7 @@ struct __cxa_thread_info
* in ABI spec [3.3.1]).
*/
int emergencyBuffersHeld;
+#endif
/**
* The exception currently running in a cleanup.
*/
@@ -197,6 +199,7 @@ struct __cxa_thread_info
struct __cxa_dependent_exception
{
#if __LP64__
+ void *reserve;
void *primaryException;
#endif
std::type_info *exceptionType;
@@ -219,6 +222,17 @@ struct __cxa_dependent_exception
#endif
_Unwind_Exception unwindHeader;
};
+static_assert(sizeof(__cxa_exception) == sizeof(__cxa_dependent_exception),
+ "__cxa_exception and __cxa_dependent_exception should have the same size");
+static_assert(offsetof(__cxa_exception, referenceCount) ==
+ offsetof(__cxa_dependent_exception, primaryException),
+ "referenceCount and primaryException should have the same offset");
+static_assert(offsetof(__cxa_exception, unwindHeader) ==
+ offsetof(__cxa_dependent_exception, unwindHeader),
+ "unwindHeader fields should have the same offset");
+static_assert(offsetof(__cxa_dependent_exception, unwindHeader) ==
+ offsetof(__cxa_dependent_exception, adjustedPtr) + 8,
+ "there should be no padding before unwindHeader");
namespace std
@@ -433,6 +447,23 @@ extern "C" __cxa_eh_globals *ABI_NAMESPACE::__cxa_get_globals_fast(void)
return &(thread_info_fast()->globals);
}
+#ifdef LIBCXXRT_NO_EMERGENCY_MALLOC
+static char *alloc_or_die(size_t size)
+{
+ char *buffer = static_cast<char*>(calloc(1, size));
+
+ if (buffer == nullptr)
+ {
+ fputs("Out of memory attempting to allocate exception\n", stderr);
+ std::terminate();
+ }
+ return buffer;
+}
+static void free_exception(char *e)
+{
+ free(e);
+}
+#else
/**
* An emergency allocation reserved for when malloc fails. This is treated as
* 16 buffers of 1KB each.
@@ -572,6 +603,7 @@ static void free_exception(char *e)
free(e);
}
}
+#endif
/**
* Allocates an exception structure. Returns a pointer to the space that can
@@ -759,6 +791,21 @@ static void throw_exception(__cxa_exception *ex)
report_failure(err, ex);
}
+extern "C" __cxa_exception *__cxa_init_primary_exception(
+ void *object, std::type_info* tinfo, void (*dest)(void *)) {
+ __cxa_exception *ex = reinterpret_cast<__cxa_exception*>(object) - 1;
+
+ ex->referenceCount = 0;
+ ex->exceptionType = tinfo;
+
+ ex->exceptionDestructor = dest;
+
+ ex->unwindHeader.exception_class = exception_class;
+ ex->unwindHeader.exception_cleanup = exception_cleanup;
+
+ return ex;
+}
+
/**
* ABI function for throwing an exception. Takes the object to be thrown (the
@@ -769,15 +816,8 @@ extern "C" void __cxa_throw(void *thrown_exception,
std::type_info *tinfo,
void(*dest)(void*))
{
- __cxa_exception *ex = reinterpret_cast<__cxa_exception*>(thrown_exception) - 1;
-
+ __cxa_exception *ex = __cxa_init_primary_exception(thrown_exception, tinfo, dest);
ex->referenceCount = 1;
- ex->exceptionType = tinfo;
-
- ex->exceptionDestructor = dest;
-
- ex->unwindHeader.exception_class = exception_class;
- ex->unwindHeader.exception_cleanup = exception_cleanup;
throw_exception(ex);
}
@@ -1563,8 +1603,10 @@ asm (
".type __cxa_end_cleanup, \"function\" \n"
"__cxa_end_cleanup: \n"
" push {r1, r2, r3, r4} \n"
+" mov r4, lr \n"
" bl __cxa_get_cleanup \n"
-" push {r1, r2, r3, r4} \n"
+" mov lr, r4 \n"
+" pop {r1, r2, r3, r4} \n"
" b _Unwind_Resume \n"
" bl abort \n"
".popsection \n"
diff --git a/guard.cc b/guard.cc
index 515992563a10..cb58aa7da28e 100644
--- a/guard.cc
+++ b/guard.cc
@@ -69,7 +69,12 @@
* progress). The bit to use depends on the byte order of the target.
*
* On many 32-bit platforms, 64-bit atomics are unavailable (or slow) and so we
- * treat the two halves of the 64-bit word as independent values and
+ * treat the two halves of the 64-bit word as independent values and establish
+ * an ordering on them such that the guard word is never modified unless the
+ * lock word is in the locked state. This means that we can do double-checked
+ * locking by loading the guard word and, if it is not initialised, trying to
+ * transition the lock word from the unlocked to locked state, and then
+ * manipulate the guard word.
*/
namespace
{
@@ -227,7 +232,7 @@ namespace
// If another thread did manage to initialise this, release
// the lock and notify the caller that initialisation is
// done.
- lock_word.store(initialised, memory_order::release);
+ lock_word.store(0, memory_order::release);
return GuardState::InitDone;
}
return GuardState::InitLockSucceeded;