libcxxabi: update to LLVM 18

release/18.x branch, commit 78b99c73ee4b96fe9ce0e294d4632326afb2db42
This commit is contained in:
Andrew Kelley 2024-04-26 14:41:45 -07:00
parent 6295415da7
commit bc6ebc6f25
18 changed files with 1164 additions and 538 deletions

View File

@ -36,6 +36,9 @@ class type_info; // forward declaration
// runtime routines use C calling conventions, but are in __cxxabiv1 namespace
namespace __cxxabiv1 {
struct __cxa_exception;
extern "C" {
// 2.4.2 Allocating the Exception Object
@ -43,11 +46,19 @@ extern _LIBCXXABI_FUNC_VIS void *
__cxa_allocate_exception(size_t thrown_size) throw();
extern _LIBCXXABI_FUNC_VIS void
__cxa_free_exception(void *thrown_exception) throw();
// This function is an LLVM extension, which mirrors the same extension in libsupc++ and libcxxrt
extern _LIBCXXABI_FUNC_VIS __cxa_exception*
__cxa_init_primary_exception(void* object, std::type_info* tinfo, void(_LIBCXXABI_DTOR_FUNC* dest)(void*)) throw();
// 2.4.3 Throwing the Exception Object
extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void
__cxa_throw(void *thrown_exception, std::type_info *tinfo,
#ifdef __USING_WASM_EXCEPTIONS__
// In Wasm, a destructor returns its argument
void *(_LIBCXXABI_DTOR_FUNC *dest)(void *));
#else
void (_LIBCXXABI_DTOR_FUNC *dest)(void *));
#endif
// 2.5.3 Exception Handlers
extern _LIBCXXABI_FUNC_VIS void *

View File

@ -14,4 +14,15 @@
extern "C" _LIBCXXABI_HIDDEN _LIBCXXABI_NORETURN void
abort_message(const char *format, ...) __attribute__((format(printf, 1, 2)));
#ifndef _LIBCXXABI_ASSERT
# define _LIBCXXABI_ASSERT(expr, msg) \
do { \
if (!(expr)) { \
char const* __msg = (msg); \
::abort_message("%s:%d: %s", __FILE__, __LINE__, __msg); \
} \
} while (false)
#endif
#endif // __ABORT_MESSAGE_H_

View File

@ -740,6 +740,6 @@ __catchThrownException(void (*cdfunc)(void), // function which may fail
return 0;
}
} // extern "C"
} // extern "C"
} // __cxxabiv1

View File

@ -10,14 +10,17 @@
// file does not yet support:
// - C++ modules TS
#include "abort_message.h"
#define DEMANGLE_ASSERT(expr, msg) _LIBCXXABI_ASSERT(expr, msg)
#include "demangle/DemangleConfig.h"
#include "demangle/ItaniumDemangle.h"
#include "__cxxabi_config.h"
#include <cassert>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <exception>
#include <functional>
#include <numeric>
#include <string_view>
@ -394,7 +397,7 @@ __cxa_demangle(const char *MangledName, char *Buf, size_t *N, int *Status) {
InternalStatus = demangle_invalid_mangled_name;
else {
OutputBuffer O(Buf, N);
assert(Parser.ForwardTemplateRefs.empty());
DEMANGLE_ASSERT(Parser.ForwardTemplateRefs.empty(), "");
AST->print(O);
O += '\0';
if (N != nullptr)

View File

@ -206,6 +206,19 @@ void __cxa_free_exception(void *thrown_object) throw() {
__aligned_free_with_fallback((void *)raw_buffer);
}
__cxa_exception* __cxa_init_primary_exception(void* object, std::type_info* tinfo,
void(_LIBCXXABI_DTOR_FUNC* dest)(void*)) throw() {
__cxa_exception* exception_header = cxa_exception_from_thrown_object(object);
exception_header->referenceCount = 0;
exception_header->unexpectedHandler = std::get_unexpected();
exception_header->terminateHandler = std::get_terminate();
exception_header->exceptionType = tinfo;
exception_header->exceptionDestructor = dest;
setOurExceptionClass(&exception_header->unwindHeader);
exception_header->unwindHeader.exception_cleanup = exception_cleanup_func;
return exception_header;
}
// This function shall allocate a __cxa_dependent_exception and
// return a pointer to it. (Really to the object, not past its' end).
@ -254,23 +267,21 @@ will call terminate, assuming that there was no handler for the
exception.
*/
void
#ifdef __USING_WASM_EXCEPTIONS__
// In Wasm, a destructor returns its argument
__cxa_throw(void *thrown_object, std::type_info *tinfo, void *(_LIBCXXABI_DTOR_FUNC *dest)(void *)) {
#else
__cxa_throw(void *thrown_object, std::type_info *tinfo, void (_LIBCXXABI_DTOR_FUNC *dest)(void *)) {
__cxa_eh_globals *globals = __cxa_get_globals();
__cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
#endif
__cxa_eh_globals* globals = __cxa_get_globals();
globals->uncaughtExceptions += 1; // Not atomically, since globals are thread-local
exception_header->unexpectedHandler = std::get_unexpected();
exception_header->terminateHandler = std::get_terminate();
exception_header->exceptionType = tinfo;
exception_header->exceptionDestructor = dest;
setOurExceptionClass(&exception_header->unwindHeader);
exception_header->referenceCount = 1; // This is a newly allocated exception, no need for thread safety.
globals->uncaughtExceptions += 1; // Not atomically, since globals are thread-local
exception_header->unwindHeader.exception_cleanup = exception_cleanup_func;
__cxa_exception* exception_header = __cxa_init_primary_exception(thrown_object, tinfo, dest);
exception_header->referenceCount = 1; // This is a newly allocated exception, no need for thread safety.
#if __has_feature(address_sanitizer)
// Inform the ASan runtime that now might be a good time to clean stuff up.
__asan_handle_no_return();
// Inform the ASan runtime that now might be a good time to clean stuff up.
__asan_handle_no_return();
#endif
#ifdef __USING_SJLJ_EXCEPTIONS__
@ -771,6 +782,6 @@ __cxa_uncaught_exceptions() throw()
return globals->uncaughtExceptions;
}
} // extern "C"
} // extern "C"
} // abi

View File

@ -43,7 +43,12 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
// Manage the exception object itself.
std::type_info *exceptionType;
#ifdef __USING_WASM_EXCEPTIONS__
// In Wasm, a destructor returns its argument
void *(_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
#else
void (_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
#endif
std::unexpected_handler unexpectedHandler;
std::terminate_handler terminateHandler;

View File

@ -48,6 +48,6 @@ _LIBCXXABI_FUNC_VIS void __cxa_guard_abort(guard_type *raw_guard_object) {
SelectedImplementation imp(raw_guard_object);
imp.cxa_guard_abort();
}
} // extern "C"
} // extern "C"
} // __cxxabiv1

View File

@ -49,7 +49,7 @@ __cxa_uncaught_exception() throw() { return false; }
unsigned int
__cxa_uncaught_exceptions() throw() { return 0; }
} // extern "C"
} // extern "C"
// provide dummy implementations for the 'no exceptions' case.
uint64_t __getExceptionClass (const _Unwind_Exception*) { return 0; }

View File

@ -70,7 +70,7 @@ extern "C" EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD,
+------------------+--+-----+-----+------------------------+--------------------------+
| callSiteTableLength | (ULEB128) | Call Site Table length, used to find Action table |
+---------------------+-----------+---------------------------------------------------+
#ifndef __USING_SJLJ_EXCEPTIONS__
#if !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__USING_WASM_EXCEPTIONS__)
+---------------------+-----------+------------------------------------------------+
| Beginning of Call Site Table The current ip lies within the |
| ... (start, length) range of one of these |
@ -84,7 +84,7 @@ extern "C" EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD,
| +-------------+---------------------------------+------------------------------+ |
| ... |
+----------------------------------------------------------------------------------+
#else // __USING_SJLJ_EXCEPTIONS__
#else // __USING_SJLJ_EXCEPTIONS__ || __USING_WASM_EXCEPTIONS__
+---------------------+-----------+------------------------------------------------+
| Beginning of Call Site Table The current ip is a 1-based index into |
| ... this table. Or it is -1 meaning no |
@ -97,7 +97,7 @@ extern "C" EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD,
| +-------------+---------------------------------+------------------------------+ |
| ... |
+----------------------------------------------------------------------------------+
#endif // __USING_SJLJ_EXCEPTIONS__
#endif // __USING_SJLJ_EXCEPTIONS__ || __USING_WASM_EXCEPTIONS__
+---------------------------------------------------------------------+
| Beginning of Action Table ttypeIndex == 0 : cleanup |
| ... ttypeIndex > 0 : catch |
@ -547,7 +547,7 @@ void
set_registers(_Unwind_Exception* unwind_exception, _Unwind_Context* context,
const scan_results& results)
{
#if defined(__USING_SJLJ_EXCEPTIONS__)
#if defined(__USING_SJLJ_EXCEPTIONS__) || defined(__USING_WASM_EXCEPTIONS__)
#define __builtin_eh_return_data_regno(regno) regno
#elif defined(__ibmxl__)
// IBM xlclang++ compiler does not support __builtin_eh_return_data_regno.
@ -642,7 +642,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
// Get beginning current frame's code (as defined by the
// emitted dwarf code)
uintptr_t funcStart = _Unwind_GetRegionStart(context);
#ifdef __USING_SJLJ_EXCEPTIONS__
#if defined(__USING_SJLJ_EXCEPTIONS__) || defined(__USING_WASM_EXCEPTIONS__)
if (ip == uintptr_t(-1))
{
// no action
@ -652,18 +652,17 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
else if (ip == 0)
call_terminate(native_exception, unwind_exception);
// ip is 1-based index into call site table
#else // !__USING_SJLJ_EXCEPTIONS__
#else // !__USING_SJLJ_EXCEPTIONS__ && !__USING_WASM_EXCEPTIONS__
uintptr_t ipOffset = ip - funcStart;
#endif // !defined(_USING_SLJL_EXCEPTIONS__)
#endif // !__USING_SJLJ_EXCEPTIONS__ && !__USING_WASM_EXCEPTIONS__
const uint8_t* classInfo = NULL;
// Note: See JITDwarfEmitter::EmitExceptionTable(...) for corresponding
// dwarf emission
// Parse LSDA header.
uint8_t lpStartEncoding = *lsda++;
const uint8_t* lpStart =
(const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding, base);
if (lpStart == 0)
lpStart = (const uint8_t*)funcStart;
const uint8_t* lpStart = lpStartEncoding == DW_EH_PE_omit
? (const uint8_t*)funcStart
: (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding, base);
uint8_t ttypeEncoding = *lsda++;
if (ttypeEncoding != DW_EH_PE_omit)
{
@ -676,8 +675,8 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
// Walk call-site table looking for range that
// includes current PC.
uint8_t callSiteEncoding = *lsda++;
#ifdef __USING_SJLJ_EXCEPTIONS__
(void)callSiteEncoding; // When using SjLj exceptions, callSiteEncoding is never used
#if defined(__USING_SJLJ_EXCEPTIONS__) || defined(__USING_WASM_EXCEPTIONS__)
(void)callSiteEncoding; // When using SjLj/Wasm exceptions, callSiteEncoding is never used
#endif
uint32_t callSiteTableLength = static_cast<uint32_t>(readULEB128(&lsda));
const uint8_t* callSiteTableStart = lsda;
@ -687,7 +686,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
while (callSitePtr < callSiteTableEnd)
{
// There is one entry per call site.
#ifndef __USING_SJLJ_EXCEPTIONS__
#if !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__USING_WASM_EXCEPTIONS__)
// The call sites are non-overlapping in [start, start+length)
// The call sites are ordered in increasing value of start
uintptr_t start = readEncodedPointer(&callSitePtr, callSiteEncoding);
@ -695,15 +694,15 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
uintptr_t landingPad = readEncodedPointer(&callSitePtr, callSiteEncoding);
uintptr_t actionEntry = readULEB128(&callSitePtr);
if ((start <= ipOffset) && (ipOffset < (start + length)))
#else // __USING_SJLJ_EXCEPTIONS__
#else // __USING_SJLJ_EXCEPTIONS__ || __USING_WASM_EXCEPTIONS__
// ip is 1-based index into this table
uintptr_t landingPad = readULEB128(&callSitePtr);
uintptr_t actionEntry = readULEB128(&callSitePtr);
if (--ip == 0)
#endif // __USING_SJLJ_EXCEPTIONS__
#endif // __USING_SJLJ_EXCEPTIONS__ || __USING_WASM_EXCEPTIONS__
{
// Found the call site containing ip.
#ifndef __USING_SJLJ_EXCEPTIONS__
#if !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__USING_WASM_EXCEPTIONS__)
if (landingPad == 0)
{
// No handler here
@ -711,9 +710,9 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
return;
}
landingPad = (uintptr_t)lpStart + landingPad;
#else // __USING_SJLJ_EXCEPTIONS__
#else // __USING_SJLJ_EXCEPTIONS__ || __USING_WASM_EXCEPTIONS__
++landingPad;
#endif // __USING_SJLJ_EXCEPTIONS__
#endif // __USING_SJLJ_EXCEPTIONS__ || __USING_WASM_EXCEPTIONS__
results.landingPad = landingPad;
if (actionEntry == 0)
{
@ -841,7 +840,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
action += actionOffset;
} // there is no break out of this loop, only return
}
#ifndef __USING_SJLJ_EXCEPTIONS__
#if !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__USING_WASM_EXCEPTIONS__)
else if (ipOffset < start)
{
// There is no call site for this ip
@ -849,7 +848,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
// Possible stack corruption.
call_terminate(native_exception, unwind_exception);
}
#endif // !__USING_SJLJ_EXCEPTIONS__
#endif // !__USING_SJLJ_EXCEPTIONS__ && !__USING_WASM_EXCEPTIONS__
} // there might be some tricky cases which break out of this loop
// It is possible that no eh table entry specify how to handle
@ -906,7 +905,9 @@ _UA_CLEANUP_PHASE
*/
#if !defined(_LIBCXXABI_ARM_EHABI)
#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
#ifdef __USING_WASM_EXCEPTIONS__
_Unwind_Reason_Code __gxx_personality_wasm0
#elif defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
static _Unwind_Reason_Code __gxx_personality_imp
#else
_LIBCXXABI_FUNC_VIS _Unwind_Reason_Code
@ -973,6 +974,11 @@ __gxx_personality_v0
exc->languageSpecificData = results.languageSpecificData;
exc->catchTemp = reinterpret_cast<void*>(results.landingPad);
exc->adjustedPtr = results.adjustedPtr;
#ifdef __USING_WASM_EXCEPTIONS__
// Wasm only uses a single phase (_UA_SEARCH_PHASE), so save the
// results here.
set_registers(unwind_exception, context, results);
#endif
}
return _URC_HANDLER_FOUND;
}
@ -1304,7 +1310,7 @@ _LIBCXXABI_FUNC_VIS _Unwind_Reason_Code __xlcxx_personality_v1(
__attribute__((__alias__("__gxx_personality_v0")));
#endif
} // extern "C"
} // extern "C"
} // __cxxabiv1

View File

@ -416,6 +416,6 @@ __cxa_vec_delete3(void *array_address, size_t element_size, size_t padding_size,
}
} // extern "C"
} // extern "C"
} // abi

View File

@ -19,7 +19,7 @@
#include "../abort_message.h"
#endif
#include <ciso646>
#include <version>
#ifdef _MSC_VER
// snprintf is implemented in VS 2015
@ -99,6 +99,11 @@
#define DEMANGLE_FALLTHROUGH
#endif
#ifndef DEMANGLE_ASSERT
#include <cassert>
#define DEMANGLE_ASSERT(__expr, __msg) assert((__expr) && (__msg))
#endif
#define DEMANGLE_NAMESPACE_BEGIN namespace { namespace itanium_demangle {
#define DEMANGLE_NAMESPACE_END } }

File diff suppressed because it is too large Load Diff

View File

@ -19,6 +19,7 @@ NODE(QualType)
NODE(ConversionOperatorType)
NODE(PostfixQualifiedType)
NODE(ElaboratedTypeSpefType)
NODE(TransformedType)
NODE(NameType)
NODE(AbiTagAttr)
NODE(EnableIfAttr)
@ -36,6 +37,7 @@ NODE(SpecialName)
NODE(CtorVtableSpecialName)
NODE(QualifiedName)
NODE(NestedName)
NODE(MemberLikeFriendName)
NODE(LocalName)
NODE(ModuleName)
NODE(ModuleEntity)
@ -44,7 +46,9 @@ NODE(PixelVectorType)
NODE(BinaryFPType)
NODE(BitIntType)
NODE(SyntheticTemplateParamName)
NODE(TemplateParamQualifiedArg)
NODE(TypeTemplateParamDecl)
NODE(ConstrainedTypeTemplateParamDecl)
NODE(NonTypeTemplateParamDecl)
NODE(TemplateTemplateParamDecl)
NODE(TemplateParamPackDecl)
@ -91,5 +95,10 @@ NODE(DoubleLiteral)
NODE(LongDoubleLiteral)
NODE(BracedExpr)
NODE(BracedRangeExpr)
NODE(RequiresExpr)
NODE(ExprRequirement)
NODE(TypeRequirement)
NODE(NestedRequirement)
NODE(ExplicitObjectParameter)
#undef NODE

View File

@ -19,11 +19,9 @@
#include "DemangleConfig.h"
#include <array>
#include <cassert>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <exception>
#include <limits>
#include <string_view>
@ -49,7 +47,7 @@ class OutputBuffer {
BufferCapacity = Need;
Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity));
if (Buffer == nullptr)
std::terminate();
std::abort();
}
}
@ -160,7 +158,7 @@ public:
}
void insert(size_t Pos, const char *S, size_t N) {
assert(Pos <= CurrentPosition);
DEMANGLE_ASSERT(Pos <= CurrentPosition, "");
if (N == 0)
return;
grow(N);
@ -173,7 +171,7 @@ public:
void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; }
char back() const {
assert(CurrentPosition);
DEMANGLE_ASSERT(CurrentPosition, "");
return Buffer[CurrentPosition - 1];
}

View File

@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "fallback_malloc.h"
#include "abort_message.h"
#include <__threading_support>
#ifndef _LIBCXXABI_HAS_NO_THREADS
@ -16,7 +17,7 @@
#endif
#include <__memory/aligned_alloc.h>
#include <assert.h>
#include <__assert>
#include <stdlib.h> // for malloc, calloc, free
#include <string.h> // for memset
@ -142,7 +143,7 @@ void* fallback_malloc(size_t len) {
// Check the invariant that all heap_nodes pointers 'p' are aligned
// so that 'p + 1' has an alignment of at least RequiredAlignment
assert(reinterpret_cast<size_t>(p + 1) % RequiredAlignment == 0);
_LIBCXXABI_ASSERT(reinterpret_cast<size_t>(p + 1) % RequiredAlignment == 0, "");
// Calculate the number of extra padding elements needed in order
// to split 'p' and create a properly aligned heap_node from the tail
@ -163,7 +164,7 @@ void* fallback_malloc(size_t len) {
q->next_node = 0;
q->len = static_cast<heap_size>(aligned_nelems);
void* ptr = q + 1;
assert(reinterpret_cast<size_t>(ptr) % RequiredAlignment == 0);
_LIBCXXABI_ASSERT(reinterpret_cast<size_t>(ptr) % RequiredAlignment == 0, "");
return ptr;
}
@ -176,7 +177,7 @@ void* fallback_malloc(size_t len) {
prev->next_node = p->next_node;
p->next_node = 0;
void* ptr = p + 1;
assert(reinterpret_cast<size_t>(ptr) % RequiredAlignment == 0);
_LIBCXXABI_ASSERT(reinterpret_cast<size_t>(ptr) % RequiredAlignment == 0, "");
return ptr;
}
}

View File

@ -42,6 +42,7 @@
// is_equal() with use_strcmp=false so the string names are not compared.
#include <cstdint>
#include <cassert>
#include <string.h>
#ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST
@ -75,6 +76,242 @@ static inline ptrdiff_t update_offset_to_base(const char* vtable,
namespace __cxxabiv1
{
namespace {
struct derived_object_info {
const void* dynamic_ptr;
const __class_type_info* dynamic_type;
std::ptrdiff_t offset_to_derived;
};
/// A helper function that gets (dynamic_ptr, dynamic_type, offset_to_derived) from static_ptr.
void dyn_cast_get_derived_info(derived_object_info* info, const void* static_ptr)
{
#if __has_feature(cxx_abi_relative_vtable)
// The vtable address will point to the first virtual function, which is 8
// bytes after the start of the vtable (4 for the offset from top + 4 for
// the typeinfo component).
const int32_t* vtable =
*reinterpret_cast<const int32_t* const*>(static_ptr);
info->offset_to_derived = static_cast<std::ptrdiff_t>(vtable[-2]);
info->dynamic_ptr = static_cast<const char*>(static_ptr) + info->offset_to_derived;
// The typeinfo component is now a relative offset to a proxy.
int32_t offset_to_ti_proxy = vtable[-1];
const uint8_t* ptr_to_ti_proxy =
reinterpret_cast<const uint8_t*>(vtable) + offset_to_ti_proxy;
info->dynamic_type = *(reinterpret_cast<const __class_type_info* const*>(ptr_to_ti_proxy));
#else
void **vtable = *static_cast<void ** const *>(static_ptr);
info->offset_to_derived = reinterpret_cast<ptrdiff_t>(vtable[-2]);
info->dynamic_ptr = static_cast<const char*>(static_ptr) + info->offset_to_derived;
info->dynamic_type = static_cast<const __class_type_info*>(vtable[-1]);
#endif
}
/// A helper function for __dynamic_cast that casts a base sub-object pointer
/// to the object's dynamic type.
///
/// This function returns the casting result directly. No further processing
/// required.
///
/// Specifically, this function can only be called if the following pre-
/// condition holds:
/// * The dynamic type of the object pointed to by `static_ptr` is exactly
/// the same as `dst_type`.
const void* dyn_cast_to_derived(const void* static_ptr,
const void* dynamic_ptr,
const __class_type_info* static_type,
const __class_type_info* dst_type,
std::ptrdiff_t offset_to_derived,
std::ptrdiff_t src2dst_offset)
{
// We're downcasting from src_type to the complete object's dynamic type.
// This is a really hot path that can be further optimized with the
// `src2dst_offset` hint.
// In such a case, dynamic_ptr already gives the casting result if the
// casting ever succeeds. All we have to do now is to check static_ptr
// points to a public base sub-object of dynamic_ptr.
if (src2dst_offset >= 0)
{
// The static type is a unique public non-virtual base type of
// dst_type at offset `src2dst_offset` from the origin of dst.
// Note that there might be other non-public static_type bases. The
// hint only guarantees that the public base is non-virtual and
// unique. So we have to check whether static_ptr points to that
// unique public base sub-object.
if (offset_to_derived != -src2dst_offset)
return nullptr;
return dynamic_ptr;
}
if (src2dst_offset == -2)
{
// static_type is not a public base of dst_type.
return nullptr;
}
// If src2dst_offset == -3, then:
// src_type is a multiple public base type but never a virtual
// base type. We can't conclude that static_ptr points to those
// public base sub-objects because there might be other non-
// public static_type bases. The search is inevitable.
// Fallback to the slow path to check that static_type is a public
// base type of dynamic_type.
// Using giant short cut. Add that information to info.
__dynamic_cast_info info = {dst_type, static_ptr, static_type, src2dst_offset, 0, 0, 0, 0, 0, 0, 0, 0,
1, // number_of_dst_type
false, false, false, true, nullptr};
// Do the search
dst_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, false);
#ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST
// The following if should always be false because we should
// definitely find (static_ptr, static_type), either on a public
// or private path
if (info.path_dst_ptr_to_static_ptr == unknown)
{
// We get here only if there is some kind of visibility problem
// in client code.
static_assert(std::atomic<size_t>::is_always_lock_free, "");
static std::atomic<size_t> error_count(0);
size_t error_count_snapshot = error_count.fetch_add(1, std::memory_order_relaxed);
if ((error_count_snapshot & (error_count_snapshot-1)) == 0)
syslog(LOG_ERR, "dynamic_cast error 1: Both of the following type_info's "
"should have public visibility. At least one of them is hidden. %s"
", %s.\n", static_type->name(), dst_type->name());
// Redo the search comparing type_info's using strcmp
info = {dst_type, static_ptr, static_type, src2dst_offset, 0, 0, 0, 0, 0, 0,
0, 0, 0, false, false, false, true, nullptr};
info.number_of_dst_type = 1;
dst_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, true);
}
#endif // _LIBCXXABI_FORGIVING_DYNAMIC_CAST
// Query the search.
if (info.path_dst_ptr_to_static_ptr != public_path)
return nullptr;
return dynamic_ptr;
}
/// A helper function for __dynamic_cast that tries to perform a downcast
/// before giving up and falling back to the slow path.
const void* dyn_cast_try_downcast(const void* static_ptr,
const void* dynamic_ptr,
const __class_type_info* dst_type,
const __class_type_info* dynamic_type,
std::ptrdiff_t src2dst_offset)
{
if (src2dst_offset < 0)
{
// We can only optimize the case if the static type is a unique public
// base of dst_type. Give up.
return nullptr;
}
// Pretend there is a dst_type object that leads to static_ptr. Later we
// will check whether this imagined dst_type object exists. If it exists
// then it will be the casting result.
const void* dst_ptr_to_static = reinterpret_cast<const char*>(static_ptr) - src2dst_offset;
if (reinterpret_cast<std::intptr_t>(dst_ptr_to_static) < reinterpret_cast<std::intptr_t>(dynamic_ptr))
{
// The imagined dst_type object does not exist. Bail-out quickly.
return nullptr;
}
// Try to search a path from dynamic_type to dst_type.
__dynamic_cast_info dynamic_to_dst_info = {dynamic_type,
dst_ptr_to_static,
dst_type,
src2dst_offset,
0,
0,
0,
0,
0,
0,
0,
0,
1, // number_of_dst_type
false,
false,
false,
true,
nullptr};
dynamic_type->search_above_dst(&dynamic_to_dst_info, dynamic_ptr, dynamic_ptr, public_path, false);
if (dynamic_to_dst_info.path_dst_ptr_to_static_ptr != unknown) {
// We have found at least one path from dynamic_ptr to dst_ptr. The
// downcast can succeed.
return dst_ptr_to_static;
}
return nullptr;
}
const void* dyn_cast_slow(const void* static_ptr,
const void* dynamic_ptr,
const __class_type_info* static_type,
const __class_type_info* dst_type,
const __class_type_info* dynamic_type,
std::ptrdiff_t src2dst_offset)
{
// Not using giant short cut. Do the search
// Initialize info struct for this search.
__dynamic_cast_info info = {dst_type, static_ptr, static_type, src2dst_offset, 0, 0, 0, 0, 0, 0,
0, 0, 0, false, false, false, true, nullptr};
dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, false);
#ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST
// The following if should always be false because we should
// definitely find (static_ptr, static_type), either on a public
// or private path
if (info.path_dst_ptr_to_static_ptr == unknown &&
info.path_dynamic_ptr_to_static_ptr == unknown)
{
static_assert(std::atomic<size_t>::is_always_lock_free, "");
static std::atomic<size_t> error_count(0);
size_t error_count_snapshot = error_count.fetch_add(1, std::memory_order_relaxed);
if ((error_count_snapshot & (error_count_snapshot-1)) == 0)
syslog(LOG_ERR, "dynamic_cast error 2: One or more of the following type_info's "
"has hidden visibility or is defined in more than one translation "
"unit. They should all have public visibility. "
"%s, %s, %s.\n", static_type->name(), dynamic_type->name(),
dst_type->name());
// Redo the search comparing type_info's using strcmp
info = {dst_type, static_ptr, static_type, src2dst_offset, 0, 0, 0, 0, 0, 0,
0, 0, 0, false, false, false, true, nullptr};
dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, true);
}
#endif // _LIBCXXABI_FORGIVING_DYNAMIC_CAST
// Query the search.
switch (info.number_to_static_ptr)
{
case 0:
if (info.number_to_dst_ptr == 1 &&
info.path_dynamic_ptr_to_static_ptr == public_path &&
info.path_dynamic_ptr_to_dst_ptr == public_path)
return info.dst_ptr_not_leading_to_static_ptr;
break;
case 1:
if (info.path_dst_ptr_to_static_ptr == public_path ||
(
info.number_to_dst_ptr == 0 &&
info.path_dynamic_ptr_to_static_ptr == public_path &&
info.path_dynamic_ptr_to_dst_ptr == public_path
)
)
return info.dst_ptr_leading_to_static_ptr;
break;
}
return nullptr;
}
} // namespace
// __shim_type_info
__shim_type_info::~__shim_type_info()
@ -233,7 +470,8 @@ __class_type_info::can_catch(const __shim_type_info* thrown_type,
if (thrown_class_type == 0)
return false;
// bullet 2
__dynamic_cast_info info = {thrown_class_type, 0, this, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,};
assert(adjustedPtr && "catching a class without an object?");
__dynamic_cast_info info = {thrown_class_type, 0, this, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, true, nullptr};
info.number_of_dst_type = 1;
thrown_class_type->has_unambiguous_public_base(&info, adjustedPtr, public_path);
if (info.path_dst_ptr_to_static_ptr == public_path)
@ -248,32 +486,46 @@ __class_type_info::can_catch(const __shim_type_info* thrown_type,
#pragma clang diagnostic pop
#endif
// When we have an object to inspect - we just pass the pointer to the sub-
// object that matched the static_type we just checked. If that is different
// from any previously recorded pointer to that object type, then we have
// an ambiguous case.
// When we have no object to inspect, we need to account for virtual bases
// explicitly.
// info->vbase_cookie is a pointer to the name of the innermost virtual base
// type, or nullptr if there is no virtual base on the path so far.
// adjustedPtr points to the subobject we just found.
// If vbase_cookie != any previously recorded (including the case of nullptr
// representing an already-found static sub-object) then we have an ambiguous
// case. Assuming that the vbase_cookie values agree; if then we have a
// different offset (adjustedPtr) from any previously recorded, this indicates
// an ambiguous case within the virtual base.
void
__class_type_info::process_found_base_class(__dynamic_cast_info* info,
void* adjustedPtr,
int path_below) const
{
if (info->dst_ptr_leading_to_static_ptr == 0)
{
// First time here
info->dst_ptr_leading_to_static_ptr = adjustedPtr;
info->path_dst_ptr_to_static_ptr = path_below;
info->number_to_static_ptr = 1;
}
else if (info->dst_ptr_leading_to_static_ptr == adjustedPtr)
{
// We've been here before. Update path to "most public"
if (info->path_dst_ptr_to_static_ptr == not_public_path)
info->path_dst_ptr_to_static_ptr = path_below;
}
else
{
// We've detected an ambiguous cast from (thrown_class_type, adjustedPtr)
// to a static_type
info->number_to_static_ptr += 1;
info->path_dst_ptr_to_static_ptr = not_public_path;
info->search_done = true;
}
if (info->number_to_static_ptr == 0) {
// First time we found this base
info->dst_ptr_leading_to_static_ptr = adjustedPtr;
info->path_dst_ptr_to_static_ptr = path_below;
// stash the virtual base cookie.
info->dst_ptr_not_leading_to_static_ptr = info->vbase_cookie;
info->number_to_static_ptr = 1;
} else if (info->dst_ptr_not_leading_to_static_ptr == info->vbase_cookie &&
info->dst_ptr_leading_to_static_ptr == adjustedPtr) {
// We've been here before. Update path to "most public"
if (info->path_dst_ptr_to_static_ptr == not_public_path)
info->path_dst_ptr_to_static_ptr = path_below;
} else {
// We've detected an ambiguous cast from (thrown_class_type, adjustedPtr)
// to a static_type.
info->number_to_static_ptr += 1;
info->path_dst_ptr_to_static_ptr = not_public_path;
info->search_done = true;
}
}
void
@ -301,16 +553,30 @@ __base_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info,
void* adjustedPtr,
int path_below) const
{
ptrdiff_t offset_to_base = 0;
if (adjustedPtr != nullptr)
{
offset_to_base = __offset_flags >> __offset_shift;
if (__offset_flags & __virtual_mask)
{
const char* vtable = *static_cast<const char*const*>(adjustedPtr);
offset_to_base = update_offset_to_base(vtable, offset_to_base);
}
bool is_virtual = __offset_flags & __virtual_mask;
ptrdiff_t offset_to_base = 0;
if (info->have_object) {
/* We have an object to inspect, we can look through its vtables to
find the layout. */
offset_to_base = __offset_flags >> __offset_shift;
if (is_virtual) {
const char* vtable = *static_cast<const char* const*>(adjustedPtr);
offset_to_base = update_offset_to_base(vtable, offset_to_base);
}
} else if (!is_virtual) {
/* We have no object; however, for non-virtual bases, (since we do not
need to inspect any content) we can pretend to have an object based
at '0'. */
offset_to_base = __offset_flags >> __offset_shift;
} else {
/* No object to inspect, and the next base is virtual.
We cannot indirect through the vtable to find the actual object offset.
So, update vbase_cookie to the new innermost virtual base using the
pointer to the typeinfo name as a key. */
info->vbase_cookie = static_cast<const void*>(__base_type->name());
// .. and reset the pointer.
adjustedPtr = nullptr;
}
__base_type->has_unambiguous_public_base(
info,
static_cast<char*>(adjustedPtr) + offset_to_base,
@ -431,14 +697,22 @@ __pointer_type_info::can_catch(const __shim_type_info* thrown_type,
dynamic_cast<const __class_type_info*>(thrown_pointer_type->__pointee);
if (thrown_class_type == 0)
return false;
__dynamic_cast_info info = {thrown_class_type, 0, catch_class_type, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,};
bool have_object = adjustedPtr != nullptr;
__dynamic_cast_info info = {thrown_class_type, 0, catch_class_type, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
have_object, nullptr};
info.number_of_dst_type = 1;
thrown_class_type->has_unambiguous_public_base(&info, adjustedPtr, public_path);
if (info.path_dst_ptr_to_static_ptr == public_path)
{
if (adjustedPtr != NULL)
adjustedPtr = const_cast<void*>(info.dst_ptr_leading_to_static_ptr);
return true;
// In the case of a thrown null pointer, we have no object but we might
// well have computed the offset to where a public sub-object would be.
// However, we do not want to return that offset to the user; we still
// want them to catch a null ptr.
if (have_object)
adjustedPtr = const_cast<void*>(info.dst_ptr_leading_to_static_ptr);
else
adjustedPtr = nullptr;
return true;
}
return false;
}
@ -623,174 +897,46 @@ extern "C" _LIBCXXABI_FUNC_VIS void *
__dynamic_cast(const void *static_ptr, const __class_type_info *static_type,
const __class_type_info *dst_type,
std::ptrdiff_t src2dst_offset) {
// Possible future optimization: Take advantage of src2dst_offset
// Get (dynamic_ptr, dynamic_type) from static_ptr
#if __has_feature(cxx_abi_relative_vtable)
// The vtable address will point to the first virtual function, which is 8
// bytes after the start of the vtable (4 for the offset from top + 4 for the typeinfo component).
const int32_t* vtable =
*reinterpret_cast<const int32_t* const*>(static_ptr);
int32_t offset_to_derived = vtable[-2];
const void* dynamic_ptr = static_cast<const char*>(static_ptr) + offset_to_derived;
// The typeinfo component is now a relative offset to a proxy.
int32_t offset_to_ti_proxy = vtable[-1];
const uint8_t* ptr_to_ti_proxy =
reinterpret_cast<const uint8_t*>(vtable) + offset_to_ti_proxy;
const __class_type_info* dynamic_type =
*(reinterpret_cast<const __class_type_info* const*>(ptr_to_ti_proxy));
#else
void **vtable = *static_cast<void ** const *>(static_ptr);
ptrdiff_t offset_to_derived = reinterpret_cast<ptrdiff_t>(vtable[-2]);
const void* dynamic_ptr = static_cast<const char*>(static_ptr) + offset_to_derived;
const __class_type_info* dynamic_type = static_cast<const __class_type_info*>(vtable[-1]);
#endif
derived_object_info derived_info;
dyn_cast_get_derived_info(&derived_info, static_ptr);
// Initialize answer to nullptr. This will be changed from the search
// results if a non-null answer is found. Regardless, this is what will
// be returned.
const void* dst_ptr = 0;
// Initialize info struct for this search.
__dynamic_cast_info info = {dst_type, static_ptr, static_type, src2dst_offset, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,};
// Find out if we can use a giant short cut in the search
if (is_equal(dynamic_type, dst_type, false))
if (is_equal(derived_info.dynamic_type, dst_type, false))
{
// We're downcasting from src_type to the complete object's dynamic
// type. This is a really hot path that can be further optimized
// with the `src2dst_offset` hint.
// In such a case, dynamic_ptr already gives the casting result if the
// casting ever succeeds. All we have to do now is to check
// static_ptr points to a public base sub-object of dynamic_ptr.
if (src2dst_offset >= 0)
{
// The static type is a unique public non-virtual base type of
// dst_type at offset `src2dst_offset` from the origin of dst.
// Note that there might be other non-public static_type bases. The
// hint only guarantees that the public base is non-virtual and
// unique. So we have to check whether static_ptr points to that
// unique public base sub-object.
if (offset_to_derived == -src2dst_offset)
dst_ptr = dynamic_ptr;
}
else if (src2dst_offset == -2)
{
// static_type is not a public base of dst_type.
dst_ptr = nullptr;
}
else
{
// If src2dst_offset == -3, then:
// src_type is a multiple public base type but never a virtual
// base type. We can't conclude that static_ptr points to those
// public base sub-objects because there might be other non-
// public static_type bases. The search is inevitable.
// Fallback to the slow path to check that static_type is a public
// base type of dynamic_type.
// Using giant short cut. Add that information to info.
info.number_of_dst_type = 1;
// Do the search
dynamic_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, false);
#ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST
// The following if should always be false because we should
// definitely find (static_ptr, static_type), either on a public
// or private path
if (info.path_dst_ptr_to_static_ptr == unknown)
{
// We get here only if there is some kind of visibility problem
// in client code.
static_assert(std::atomic<size_t>::is_always_lock_free, "");
static std::atomic<size_t> error_count(0);
size_t error_count_snapshot = error_count.fetch_add(1, std::memory_order_relaxed);
if ((error_count_snapshot & (error_count_snapshot-1)) == 0)
syslog(LOG_ERR, "dynamic_cast error 1: Both of the following type_info's "
"should have public visibility. At least one of them is hidden. %s"
", %s.\n", static_type->name(), dynamic_type->name());
// Redo the search comparing type_info's using strcmp
info = {dst_type, static_ptr, static_type, src2dst_offset, 0};
info.number_of_dst_type = 1;
dynamic_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, true);
}
#endif // _LIBCXXABI_FORGIVING_DYNAMIC_CAST
// Query the search.
if (info.path_dst_ptr_to_static_ptr == public_path)
dst_ptr = dynamic_ptr;
}
dst_ptr = dyn_cast_to_derived(static_ptr,
derived_info.dynamic_ptr,
static_type,
dst_type,
derived_info.offset_to_derived,
src2dst_offset);
}
else
{
if (src2dst_offset >= 0)
{
// Optimize toward downcasting: dst_type has one unique public
// static_type bases. Let's first try to do a downcast before
// falling back to the slow path. The downcast succeeds if there
// is at least one path regardless of visibility from
// dynamic_type to dst_type.
const void* dst_ptr_to_static = reinterpret_cast<const char*>(static_ptr) - src2dst_offset;
if (reinterpret_cast<std::intptr_t>(dst_ptr_to_static) >= reinterpret_cast<std::intptr_t>(dynamic_ptr))
{
// Try to search a path from dynamic_type to dst_type.
__dynamic_cast_info dynamic_to_dst_info = {dynamic_type, dst_ptr_to_static, dst_type, src2dst_offset};
dynamic_to_dst_info.number_of_dst_type = 1;
dynamic_type->search_above_dst(&dynamic_to_dst_info, dynamic_ptr, dynamic_ptr, public_path, false);
if (dynamic_to_dst_info.path_dst_ptr_to_static_ptr != unknown) {
// We have found at least one path from dynamic_ptr to
// dst_ptr. The downcast can succeed.
dst_ptr = dst_ptr_to_static;
}
}
}
// Optimize toward downcasting: let's first try to do a downcast before
// falling back to the slow path.
dst_ptr = dyn_cast_try_downcast(static_ptr,
derived_info.dynamic_ptr,
dst_type,
derived_info.dynamic_type,
src2dst_offset);
if (!dst_ptr)
{
// Not using giant short cut. Do the search
dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, false);
#ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST
// The following if should always be false because we should
// definitely find (static_ptr, static_type), either on a public
// or private path
if (info.path_dst_ptr_to_static_ptr == unknown &&
info.path_dynamic_ptr_to_static_ptr == unknown)
{
static_assert(std::atomic<size_t>::is_always_lock_free, "");
static std::atomic<size_t> error_count(0);
size_t error_count_snapshot = error_count.fetch_add(1, std::memory_order_relaxed);
if ((error_count_snapshot & (error_count_snapshot-1)) == 0)
syslog(LOG_ERR, "dynamic_cast error 2: One or more of the following type_info's "
"has hidden visibility or is defined in more than one translation "
"unit. They should all have public visibility. "
"%s, %s, %s.\n", static_type->name(), dynamic_type->name(),
dst_type->name());
// Redo the search comparing type_info's using strcmp
info = {dst_type, static_ptr, static_type, src2dst_offset, 0};
dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, true);
}
#endif // _LIBCXXABI_FORGIVING_DYNAMIC_CAST
// Query the search.
switch (info.number_to_static_ptr)
{
case 0:
if (info.number_to_dst_ptr == 1 &&
info.path_dynamic_ptr_to_static_ptr == public_path &&
info.path_dynamic_ptr_to_dst_ptr == public_path)
dst_ptr = info.dst_ptr_not_leading_to_static_ptr;
break;
case 1:
if (info.path_dst_ptr_to_static_ptr == public_path ||
(
info.number_to_dst_ptr == 0 &&
info.path_dynamic_ptr_to_static_ptr == public_path &&
info.path_dynamic_ptr_to_dst_ptr == public_path
)
)
dst_ptr = info.dst_ptr_leading_to_static_ptr;
break;
}
dst_ptr = dyn_cast_slow(static_ptr,
derived_info.dynamic_ptr,
static_type,
dst_type,
derived_info.dynamic_type,
src2dst_offset);
}
}
return const_cast<void*>(dst_ptr);
}
@ -1075,7 +1221,7 @@ __vmi_class_type_info::search_below_dst(__dynamic_cast_info* info,
if (info->search_done)
break;
// If we just found a dst_type with a public path to (static_ptr, static_type),
// then the only reason to continue the search is to make sure sure
// then the only reason to continue the search is to make sure
// no other dst_type points to (static_ptr, static_type).
// If !diamond, then we don't need to search here.
// if we just found a dst_type with a private path to (static_ptr, static_type),

View File

@ -110,6 +110,13 @@ struct _LIBCXXABI_HIDDEN __dynamic_cast_info
bool found_any_static_type;
// Set whenever a search can be stopped
bool search_done;
// Data that modifies the search mechanism.
// There is no object (seen when we throw a null pointer to object).
bool have_object;
// Virtual base
const void* vbase_cookie;
};
// Has no base class

View File

@ -7,7 +7,10 @@
//===----------------------------------------------------------------------===//
#include "__cxxabi_config.h"
#include "abort_message.h"
#include "include/overridable_function.h" // from libc++
#include <__memory/aligned_alloc.h>
#include <cstddef>
#include <cstdlib>
#include <new>
@ -25,241 +28,216 @@
# error libc++ and libc++abi seem to disagree on whether exceptions are enabled
#endif
inline void __throw_bad_alloc_shim() {
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
throw std::bad_alloc();
#else
abort_message("bad_alloc was thrown in -fno-exceptions mode");
#endif
}
#define _LIBCPP_ASSERT_SHIM(expr, str) \
do { \
if (!expr) \
abort_message(str); \
} while (false)
// ------------------ BEGIN COPY ------------------
// Implement all new and delete operators as weak definitions
// in this shared library, so that they can be overridden by programs
// that define non-weak copies of the functions.
_LIBCPP_WEAK
void *
operator new(std::size_t size) _THROW_BAD_ALLOC
{
if (size == 0)
size = 1;
void* p;
while ((p = std::malloc(size)) == nullptr)
{
// If malloc fails and there is a new_handler,
// call it to try free up memory.
std::new_handler nh = std::get_new_handler();
if (nh)
nh();
else
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
throw std::bad_alloc();
static void* operator_new_impl(std::size_t size) {
if (size == 0)
size = 1;
void* p;
while ((p = std::malloc(size)) == nullptr) {
// If malloc fails and there is a new_handler,
// call it to try free up memory.
std::new_handler nh = std::get_new_handler();
if (nh)
nh();
else
break;
}
return p;
}
_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* operator new(std::size_t size) _THROW_BAD_ALLOC {
void* p = operator_new_impl(size);
if (p == nullptr)
__throw_bad_alloc_shim();
return p;
}
_LIBCPP_WEAK void* operator new(size_t size, const std::nothrow_t&) noexcept {
#ifdef _LIBCPP_HAS_NO_EXCEPTIONS
# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
_LIBCPP_ASSERT_SHIM(
!std::__is_function_overridden(static_cast<void* (*)(std::size_t)>(&operator new)),
"libc++ was configured with exceptions disabled and `operator new(size_t)` has been overridden, "
"but `operator new(size_t, nothrow_t)` has not been overridden. This is problematic because "
"`operator new(size_t, nothrow_t)` must call `operator new(size_t)`, which will terminate in case "
"it fails to allocate, making it impossible for `operator new(size_t, nothrow_t)` to fulfill its "
"contract (since it should return nullptr upon failure). Please make sure you override "
"`operator new(size_t, nothrow_t)` as well.");
# endif
return operator_new_impl(size);
#else
break;
void* p = nullptr;
try {
p = ::operator new(size);
} catch (...) {
}
return p;
#endif
}
return p;
}
_LIBCPP_WEAK
void*
operator new(size_t size, const std::nothrow_t&) noexcept
{
void* p = nullptr;
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
try
{
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
p = ::operator new(size);
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
}
catch (...)
{
}
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
return p;
_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* operator new[](size_t size) _THROW_BAD_ALLOC {
return ::operator new(size);
}
_LIBCPP_WEAK
void*
operator new[](size_t size) _THROW_BAD_ALLOC
{
return ::operator new(size);
_LIBCPP_WEAK void* operator new[](size_t size, const std::nothrow_t&) noexcept {
#ifdef _LIBCPP_HAS_NO_EXCEPTIONS
# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
_LIBCPP_ASSERT_SHIM(
!std::__is_function_overridden(static_cast<void* (*)(std::size_t)>(&operator new[])),
"libc++ was configured with exceptions disabled and `operator new[](size_t)` has been overridden, "
"but `operator new[](size_t, nothrow_t)` has not been overridden. This is problematic because "
"`operator new[](size_t, nothrow_t)` must call `operator new[](size_t)`, which will terminate in case "
"it fails to allocate, making it impossible for `operator new[](size_t, nothrow_t)` to fulfill its "
"contract (since it should return nullptr upon failure). Please make sure you override "
"`operator new[](size_t, nothrow_t)` as well.");
# endif
return operator_new_impl(size);
#else
void* p = nullptr;
try {
p = ::operator new[](size);
} catch (...) {
}
return p;
#endif
}
_LIBCPP_WEAK
void*
operator new[](size_t size, const std::nothrow_t&) noexcept
{
void* p = nullptr;
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
try
{
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
p = ::operator new[](size);
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
}
catch (...)
{
}
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
return p;
}
_LIBCPP_WEAK void operator delete(void* ptr) noexcept { std::free(ptr); }
_LIBCPP_WEAK
void
operator delete(void* ptr) noexcept
{
std::free(ptr);
}
_LIBCPP_WEAK void operator delete(void* ptr, const std::nothrow_t&) noexcept { ::operator delete(ptr); }
_LIBCPP_WEAK
void
operator delete(void* ptr, const std::nothrow_t&) noexcept
{
::operator delete(ptr);
}
_LIBCPP_WEAK void operator delete(void* ptr, size_t) noexcept { ::operator delete(ptr); }
_LIBCPP_WEAK
void
operator delete(void* ptr, size_t) noexcept
{
::operator delete(ptr);
}
_LIBCPP_WEAK void operator delete[](void* ptr) noexcept { ::operator delete(ptr); }
_LIBCPP_WEAK
void
operator delete[] (void* ptr) noexcept
{
::operator delete(ptr);
}
_LIBCPP_WEAK void operator delete[](void* ptr, const std::nothrow_t&) noexcept { ::operator delete[](ptr); }
_LIBCPP_WEAK
void
operator delete[] (void* ptr, const std::nothrow_t&) noexcept
{
::operator delete[](ptr);
}
_LIBCPP_WEAK
void
operator delete[] (void* ptr, size_t) noexcept
{
::operator delete[](ptr);
}
_LIBCPP_WEAK void operator delete[](void* ptr, size_t) noexcept { ::operator delete[](ptr); }
#if !defined(_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION)
_LIBCPP_WEAK
void *
operator new(std::size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC
{
if (size == 0)
size = 1;
if (static_cast<size_t>(alignment) < sizeof(void*))
alignment = std::align_val_t(sizeof(void*));
static void* operator_new_aligned_impl(std::size_t size, std::align_val_t alignment) {
if (size == 0)
size = 1;
if (static_cast<size_t>(alignment) < sizeof(void*))
alignment = std::align_val_t(sizeof(void*));
// Try allocating memory. If allocation fails and there is a new_handler,
// call it to try free up memory, and try again until it succeeds, or until
// the new_handler decides to terminate.
//
// If allocation fails and there is no new_handler, we throw bad_alloc
// (or return nullptr if exceptions are disabled).
void* p;
while ((p = std::__libcpp_aligned_alloc(static_cast<std::size_t>(alignment), size)) == nullptr)
{
std::new_handler nh = std::get_new_handler();
if (nh)
nh();
else {
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
throw std::bad_alloc();
#else
break;
#endif
}
}
return p;
// Try allocating memory. If allocation fails and there is a new_handler,
// call it to try free up memory, and try again until it succeeds, or until
// the new_handler decides to terminate.
void* p;
while ((p = std::__libcpp_aligned_alloc(static_cast<std::size_t>(alignment), size)) == nullptr) {
std::new_handler nh = std::get_new_handler();
if (nh)
nh();
else
break;
}
return p;
}
_LIBCPP_WEAK
void*
operator new(size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept
{
void* p = nullptr;
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
try
{
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
p = ::operator new(size, alignment);
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
}
catch (...)
{
}
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
return p;
_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void*
operator new(std::size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC {
void* p = operator_new_aligned_impl(size, alignment);
if (p == nullptr)
__throw_bad_alloc_shim();
return p;
}
_LIBCPP_WEAK
void*
operator new[](size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC
{
return ::operator new(size, alignment);
_LIBCPP_WEAK void* operator new(size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept {
# ifdef _LIBCPP_HAS_NO_EXCEPTIONS
# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
_LIBCPP_ASSERT_SHIM(
!std::__is_function_overridden(static_cast<void* (*)(std::size_t, std::align_val_t)>(&operator new)),
"libc++ was configured with exceptions disabled and `operator new(size_t, align_val_t)` has been overridden, "
"but `operator new(size_t, align_val_t, nothrow_t)` has not been overridden. This is problematic because "
"`operator new(size_t, align_val_t, nothrow_t)` must call `operator new(size_t, align_val_t)`, which will "
"terminate in case it fails to allocate, making it impossible for `operator new(size_t, align_val_t, nothrow_t)` "
"to fulfill its contract (since it should return nullptr upon failure). Please make sure you override "
"`operator new(size_t, align_val_t, nothrow_t)` as well.");
# endif
return operator_new_aligned_impl(size, alignment);
# else
void* p = nullptr;
try {
p = ::operator new(size, alignment);
} catch (...) {
}
return p;
# endif
}
_LIBCPP_WEAK
void*
operator new[](size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept
{
void* p = nullptr;
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
try
{
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
p = ::operator new[](size, alignment);
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
}
catch (...)
{
}
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
return p;
_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void*
operator new[](size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC {
return ::operator new(size, alignment);
}
_LIBCPP_WEAK
void
operator delete(void* ptr, std::align_val_t) noexcept
{
std::__libcpp_aligned_free(ptr);
_LIBCPP_WEAK void* operator new[](size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept {
# ifdef _LIBCPP_HAS_NO_EXCEPTIONS
# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
_LIBCPP_ASSERT_SHIM(
!std::__is_function_overridden(static_cast<void* (*)(std::size_t, std::align_val_t)>(&operator new[])),
"libc++ was configured with exceptions disabled and `operator new[](size_t, align_val_t)` has been overridden, "
"but `operator new[](size_t, align_val_t, nothrow_t)` has not been overridden. This is problematic because "
"`operator new[](size_t, align_val_t, nothrow_t)` must call `operator new[](size_t, align_val_t)`, which will "
"terminate in case it fails to allocate, making it impossible for `operator new[](size_t, align_val_t, "
"nothrow_t)` to fulfill its contract (since it should return nullptr upon failure). Please make sure you "
"override "
"`operator new[](size_t, align_val_t, nothrow_t)` as well.");
# endif
return operator_new_aligned_impl(size, alignment);
# else
void* p = nullptr;
try {
p = ::operator new[](size, alignment);
} catch (...) {
}
return p;
# endif
}
_LIBCPP_WEAK
void
operator delete(void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept
{
::operator delete(ptr, alignment);
_LIBCPP_WEAK void operator delete(void* ptr, std::align_val_t) noexcept { std::__libcpp_aligned_free(ptr); }
_LIBCPP_WEAK void operator delete(void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept {
::operator delete(ptr, alignment);
}
_LIBCPP_WEAK
void
operator delete(void* ptr, size_t, std::align_val_t alignment) noexcept
{
::operator delete(ptr, alignment);
_LIBCPP_WEAK void operator delete(void* ptr, size_t, std::align_val_t alignment) noexcept {
::operator delete(ptr, alignment);
}
_LIBCPP_WEAK
void
operator delete[] (void* ptr, std::align_val_t alignment) noexcept
{
::operator delete(ptr, alignment);
_LIBCPP_WEAK void operator delete[](void* ptr, std::align_val_t alignment) noexcept {
::operator delete(ptr, alignment);
}
_LIBCPP_WEAK
void
operator delete[] (void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept
{
::operator delete[](ptr, alignment);
_LIBCPP_WEAK void operator delete[](void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept {
::operator delete[](ptr, alignment);
}
_LIBCPP_WEAK
void
operator delete[] (void* ptr, size_t, std::align_val_t alignment) noexcept
{
::operator delete[](ptr, alignment);
_LIBCPP_WEAK void operator delete[](void* ptr, size_t, std::align_val_t alignment) noexcept {
::operator delete[](ptr, alignment);
}
#endif // !_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION