diff --git a/lib/libcxxabi/include/__cxxabi_config.h b/lib/libcxxabi/include/__cxxabi_config.h index c97dd656e1..e8aa37e6d5 100644 --- a/lib/libcxxabi/include/__cxxabi_config.h +++ b/lib/libcxxabi/include/__cxxabi_config.h @@ -32,7 +32,7 @@ #endif #if defined(_WIN32) - #if defined(_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS) + #if defined(_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS) || (defined(__MINGW32__) && !defined(_LIBCXXABI_BUILDING_LIBRARY)) #define _LIBCXXABI_HIDDEN #define _LIBCXXABI_DATA_VIS #define _LIBCXXABI_FUNC_VIS diff --git a/lib/libcxxabi/src/aix_state_tab_eh.inc b/lib/libcxxabi/src/aix_state_tab_eh.inc index 128a0ab34a..3bb09ed275 100644 --- a/lib/libcxxabi/src/aix_state_tab_eh.inc +++ b/lib/libcxxabi/src/aix_state_tab_eh.inc @@ -14,10 +14,6 @@ #include #include -#if !__has_cpp_attribute(clang::optnone) -#error This file requires clang::optnone attribute support -#endif - /* The legacy IBM xlC and xlclang++ compilers use the state table for EH instead of the range table. Destructors, or addresses of the possible catch @@ -563,7 +559,8 @@ __xlcxx_personality_v0(int version, _Unwind_Action actions, uint64_t exceptionCl uintptr_t *currentSP = reinterpret_cast(_Unwind_GetGR(context, 1)); uintptr_t *callersSP = reinterpret_cast(currentSP[0]); callersSP[3] = reinterpret_cast(unwind_exception); - _LIBCXXABI_TRACE_STATETAB("Handshake: set unwind_exception=%p in stack=%p\n", reinterpret_cast(unwind_exception), reinterpret_cast(callersSP)); + _LIBCXXABI_TRACE_STATETAB("Handshake: save unwind_exception=%p in stack=%p\n", + reinterpret_cast(unwind_exception), reinterpret_cast(callersSP)); // Jump to the handler. _Unwind_SetIP(context, results.landingPad); return _URC_INSTALL_CONTEXT; @@ -641,38 +638,68 @@ _LIBCXXABI_FUNC_VIS void __xlc_throw_badexception() { __cxa_throw(newexception, const_cast(&typeid(std::bad_exception)), 0); } -// force_a_stackframe -// This function is called by __xlc_exception_handle() to ensure a stack frame -// is created for __xlc_exception_handle(). -__attribute__((noinline, optnone)) -static void force_a_stackframe() {} +// skip_non_cxx_eh_aware_frames +// This function skips non-C++ EH aware stack frames by unwinding from the +// stack frame pointed by 'Sp' and returns the first C++ EH aware stack frame +// found. 'Pc' is an instruction address inside the function that owns the +// stack frame pointed to by 'Sp'. +static uintptr_t* skip_non_cxx_eh_aware_frames(uint32_t* Pc, uintptr_t* Sp) { + uint32_t* currentPc = Pc; + uintptr_t* currentStack = Sp; + + // Loop until a C++ EH aware frame is found or the return address is 0, + // which is the return address of the startup function '__start'. + while (currentPc != 0) { + uint32_t* p = currentPc; + + // Keep looking forward until a word of 0 is found. The traceback + // table starts at the following word. + while (*p) + ++p; + tbtable* TBTable = reinterpret_cast(p + 1); + + // A stack frame with a C++ state table is C++ EH aware. + if (TBTable->tb.lang == TB_CPLUSPLUS && TBTable->tb.has_ctl) + return currentStack; + + // Move up one stack frame. + currentStack = reinterpret_cast(currentStack[0]); + // Get the value of the LR (saved, prior to incrementing the SP, by the + // prolog of the function just inspected) from the frame. + currentPc = reinterpret_cast(currentStack[2]); + } + // This should not happen. + _LIBCXXABI_TRACE_STATETAB0("skip_non_cxx_eh_aware_frames() reached the end of stack frames, aborting\n"); + abort(); +} // __xlc_exception_handle // This function is for xlclang++. It returns the address of the exception // object stored in the reserved field in the stack of the caller of the // function that calls __xlc_exception_handle() (within the link area for the // call to the latter). The address is stored by the personality routine for -// xlclang++ compiled code. The implementation of __xlc_exception_handle() -// assumes a stack frame is created for it. The following ensures this -// assumption holds true: 1) a call to force_a_stackframe() is made inside -// __xlc_exception_handle() to make it non-leaf; and 2) optimizations are -// disabled for this function with attribute 'optnone'. Note: this function -// may not work as expected if these are changed. -__attribute__((optnone)) +// xlclang++ compiled code. If __xlc_exception_handle() is called by +// non-C++ EH aware functions, their frames are skipped until a C++ EH aware +// frame is found. +// Note: make sure __xlc_excpetion_handle() is a non-leaf function. Currently +// it calls skip_non_cxx_eh_aware_frames(), which in turn calls abort(). _LIBCXXABI_FUNC_VIS uintptr_t __xlc_exception_handle() { - // Make a call to force_a_stackframe() so that the compiler creates a stack - // frame for this function. - force_a_stackframe(); - // Get the SP of this function, i.e., __xlc_exception_handle(). - uintptr_t *lastStack; - asm("mr %0, 1" : "=r"(lastStack)); - // Get the SP of the caller of __xlc_exception_handle(). - uintptr_t *callerStack = reinterpret_cast(lastStack[0]); - // Get the SP of the caller of the caller. - uintptr_t *callerStack2 = reinterpret_cast(callerStack[0]); - uintptr_t exceptionObject = callerStack2[3]; - _LIBCXXABI_TRACE_STATETAB("Handshake: exceptionObject=%p from stack=%p\n", reinterpret_cast(exceptionObject), reinterpret_cast(callerStack2)); + uintptr_t* lastStack = reinterpret_cast(__builtin_frame_address(0)); + // Move one frame up to the frame of the caller of __xlc_exception_handle(). + lastStack = reinterpret_cast(lastStack[0]); + // Get the return address of this function, i.e., __xlc_exception_handle(). + uint32_t* returnAddress = reinterpret_cast(__builtin_return_address(0)); + + // Skip non-C++ EH aware frames and get the first C++ EH aware frame. + uintptr_t* callerStack = skip_non_cxx_eh_aware_frames(returnAddress, lastStack); + + // Get the SP of the caller of the C++ EH aware caller. + callerStack = reinterpret_cast(callerStack[0]); + // Retrieve the exception object in the stack slot saved by the personality. + uintptr_t exceptionObject = callerStack[3]; + _LIBCXXABI_TRACE_STATETAB("Handshake: retrieve exceptionObject=%p from stack=%p\n", + reinterpret_cast(exceptionObject), reinterpret_cast(callerStack)); return exceptionObject; } diff --git a/lib/libcxxabi/src/cxa_aux_runtime.cpp b/lib/libcxxabi/src/cxa_aux_runtime.cpp index a42990c7ef..5e6040d75a 100644 --- a/lib/libcxxabi/src/cxa_aux_runtime.cpp +++ b/lib/libcxxabi/src/cxa_aux_runtime.cpp @@ -10,6 +10,7 @@ //===----------------------------------------------------------------------===// #include "cxxabi.h" +#include #include #include diff --git a/lib/libcxxabi/src/cxa_demangle.cpp b/lib/libcxxabi/src/cxa_demangle.cpp index 7baac68007..03085cb590 100644 --- a/lib/libcxxabi/src/cxa_demangle.cpp +++ b/lib/libcxxabi/src/cxa_demangle.cpp @@ -10,6 +10,7 @@ // file does not yet support: // - C++ modules TS +#include "demangle/DemangleConfig.h" #include "demangle/ItaniumDemangle.h" #include "__cxxabi_config.h" #include @@ -19,6 +20,7 @@ #include #include #include +#include #include using namespace itanium_demangle; @@ -77,8 +79,8 @@ struct DumpVisitor { } void printStr(const char *S) { fprintf(stderr, "%s", S); } - void print(StringView SV) { - fprintf(stderr, "\"%.*s\"", (int)SV.size(), SV.begin()); + void print(std::string_view SV) { + fprintf(stderr, "\"%.*s\"", (int)SV.size(), &*SV.begin()); } void print(const Node *N) { if (N) diff --git a/lib/libcxxabi/src/cxa_guard_impl.h b/lib/libcxxabi/src/cxa_guard_impl.h index 47fe2b20bd..e00d54b3a7 100644 --- a/lib/libcxxabi/src/cxa_guard_impl.h +++ b/lib/libcxxabi/src/cxa_guard_impl.h @@ -255,7 +255,7 @@ struct InitByteNoThreads { if (*init_byte_address == COMPLETE_BIT) return true; if (*init_byte_address & PENDING_BIT) - ABORT_WITH_MESSAGE("__cxa_guard_acquire detected recursive initialization"); + ABORT_WITH_MESSAGE("__cxa_guard_acquire detected recursive initialization: do you have a function-local static variable whose initialization depends on that function?"); *init_byte_address = PENDING_BIT; return false; } @@ -325,7 +325,7 @@ public: // Check for possible recursive initialization. if (has_thread_id_support && (*init_byte_address & PENDING_BIT)) { if (*thread_id_address == current_thread_id.get()) - ABORT_WITH_MESSAGE("__cxa_guard_acquire detected recursive initialization"); + ABORT_WITH_MESSAGE("__cxa_guard_acquire detected recursive initialization: do you have a function-local static variable whose initialization depends on that function?"); } // Wait until the pending bit is not set. @@ -460,7 +460,7 @@ public: // Check for recursive initialization if (has_thread_id_support && thread_id.load(std::_AO_Relaxed) == current_thread_id.get()) { - ABORT_WITH_MESSAGE("__cxa_guard_acquire detected recursive initialization"); + ABORT_WITH_MESSAGE("__cxa_guard_acquire detected recursive initialization: do you have a function-local static variable whose initialization depends on that function?"); } if ((last_val & WAITING_BIT) == 0) { diff --git a/lib/libcxxabi/src/demangle/DemangleConfig.h b/lib/libcxxabi/src/demangle/DemangleConfig.h index 9d818535b0..d5e11432d9 100644 --- a/lib/libcxxabi/src/demangle/DemangleConfig.h +++ b/lib/libcxxabi/src/demangle/DemangleConfig.h @@ -11,6 +11,14 @@ #ifndef LIBCXXABI_DEMANGLE_DEMANGLE_CONFIG_H #define LIBCXXABI_DEMANGLE_DEMANGLE_CONFIG_H +// Must be defined before pulling in headers from libc++. Allow downstream +// build systems to override this value. +// https://libcxx.llvm.org/UsingLibcxx.html#enabling-the-safe-libc-mode +#ifndef _LIBCPP_VERBOSE_ABORT +#define _LIBCPP_VERBOSE_ABORT(...) abort_message(__VA_ARGS__) +#include "../abort_message.h" +#endif + #include #ifdef _MSC_VER diff --git a/lib/libcxxabi/src/demangle/ItaniumDemangle.h b/lib/libcxxabi/src/demangle/ItaniumDemangle.h index 66213c63f2..28562f0214 100644 --- a/lib/libcxxabi/src/demangle/ItaniumDemangle.h +++ b/lib/libcxxabi/src/demangle/ItaniumDemangle.h @@ -17,8 +17,9 @@ #define DEMANGLE_ITANIUMDEMANGLE_H #include "DemangleConfig.h" -#include "StringView.h" +#include "StringViewExtras.h" #include "Utility.h" +#include <__cxxabi_config.h> #include #include #include @@ -27,8 +28,15 @@ #include #include #include +#include +#include #include +#ifdef _LIBCXXABI_COMPILER_CLANG +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-template" +#endif + DEMANGLE_NAMESPACE_BEGIN template class PODSmallVector { @@ -286,7 +294,7 @@ public: // implementation. virtual void printRight(OutputBuffer &) const {} - virtual StringView getBaseName() const { return StringView(); } + virtual std::string_view getBaseName() const { return {}; } // Silence compiler warnings, this dtor will never be called. virtual ~Node() = default; @@ -345,10 +353,10 @@ struct NodeArrayNode : Node { class DotSuffix final : public Node { const Node *Prefix; - const StringView Suffix; + const std::string_view Suffix; public: - DotSuffix(const Node *Prefix_, StringView Suffix_) + DotSuffix(const Node *Prefix_, std::string_view Suffix_) : Node(KDotSuffix), Prefix(Prefix_), Suffix(Suffix_) {} template void match(Fn F) const { F(Prefix, Suffix); } @@ -363,15 +371,15 @@ public: class VendorExtQualType final : public Node { const Node *Ty; - StringView Ext; + std::string_view Ext; const Node *TA; public: - VendorExtQualType(const Node *Ty_, StringView Ext_, const Node *TA_) + VendorExtQualType(const Node *Ty_, std::string_view Ext_, const Node *TA_) : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_), TA(TA_) {} const Node *getTy() const { return Ty; } - StringView getExt() const { return Ext; } + std::string_view getExt() const { return Ext; } const Node *getTA() const { return TA; } template void match(Fn F) const { F(Ty, Ext, TA); } @@ -462,10 +470,10 @@ public: class PostfixQualifiedType final : public Node { const Node *Ty; - const StringView Postfix; + const std::string_view Postfix; public: - PostfixQualifiedType(const Node *Ty_, StringView Postfix_) + PostfixQualifiedType(const Node *Ty_, std::string_view Postfix_) : Node(KPostfixQualifiedType), Ty(Ty_), Postfix(Postfix_) {} template void match(Fn F) const { F(Ty, Postfix); } @@ -477,15 +485,15 @@ public: }; class NameType final : public Node { - const StringView Name; + const std::string_view Name; public: - NameType(StringView Name_) : Node(KNameType), Name(Name_) {} + NameType(std::string_view Name_) : Node(KNameType), Name(Name_) {} template void match(Fn F) const { F(Name); } - StringView getName() const { return Name; } - StringView getBaseName() const override { return Name; } + std::string_view getName() const { return Name; } + std::string_view getBaseName() const override { return Name; } void printLeft(OutputBuffer &OB) const override { OB += Name; } }; @@ -511,10 +519,10 @@ public: }; class ElaboratedTypeSpefType : public Node { - StringView Kind; + std::string_view Kind; Node *Child; public: - ElaboratedTypeSpefType(StringView Kind_, Node *Child_) + ElaboratedTypeSpefType(std::string_view Kind_, Node *Child_) : Node(KElaboratedTypeSpefType), Kind(Kind_), Child(Child_) {} template void match(Fn F) const { F(Kind, Child); } @@ -528,15 +536,17 @@ public: struct AbiTagAttr : Node { Node *Base; - StringView Tag; + std::string_view Tag; - AbiTagAttr(Node* Base_, StringView Tag_) - : Node(KAbiTagAttr, Base_->RHSComponentCache, - Base_->ArrayCache, Base_->FunctionCache), + AbiTagAttr(Node *Base_, std::string_view Tag_) + : Node(KAbiTagAttr, Base_->RHSComponentCache, Base_->ArrayCache, + Base_->FunctionCache), Base(Base_), Tag(Tag_) {} template void match(Fn F) const { F(Base, Tag); } + std::string_view getBaseName() const override { return Base->getBaseName(); } + void printLeft(OutputBuffer &OB) const override { Base->printLeft(OB); OB += "[abi:"; @@ -562,12 +572,12 @@ public: class ObjCProtoName : public Node { const Node *Ty; - StringView Protocol; + std::string_view Protocol; friend class PointerType; public: - ObjCProtoName(const Node *Ty_, StringView Protocol_) + ObjCProtoName(const Node *Ty_, std::string_view Protocol_) : Node(KObjCProtoName), Ty(Ty_), Protocol(Protocol_) {} template void match(Fn F) const { F(Ty, Protocol); } @@ -944,11 +954,11 @@ public: }; class SpecialName final : public Node { - const StringView Special; + const std::string_view Special; const Node *Child; public: - SpecialName(StringView Special_, const Node *Child_) + SpecialName(std::string_view Special_, const Node *Child_) : Node(KSpecialName), Special(Special_), Child(Child_) {} template void match(Fn F) const { F(Special, Child); } @@ -987,7 +997,7 @@ struct NestedName : Node { template void match(Fn F) const { F(Qual, Name); } - StringView getBaseName() const override { return Name->getBaseName(); } + std::string_view getBaseName() const override { return Name->getBaseName(); } void printLeft(OutputBuffer &OB) const override { Qual->print(OB); @@ -1027,7 +1037,7 @@ struct ModuleEntity : Node { template void match(Fn F) const { F(Module, Name); } - StringView getBaseName() const override { return Name->getBaseName(); } + std::string_view getBaseName() const override { return Name->getBaseName(); } void printLeft(OutputBuffer &OB) const override { Name->print(OB); @@ -1063,7 +1073,7 @@ public: template void match(Fn F) const { F(Qualifier, Name); } - StringView getBaseName() const override { return Name->getBaseName(); } + std::string_view getBaseName() const override { return Name->getBaseName(); } void printLeft(OutputBuffer &OB) const override { Qualifier->print(OB); @@ -1485,7 +1495,7 @@ struct NameWithTemplateArgs : Node { template void match(Fn F) const { F(Name, TemplateArgs); } - StringView getBaseName() const override { return Name->getBaseName(); } + std::string_view getBaseName() const override { return Name->getBaseName(); } void printLeft(OutputBuffer &OB) const override { Name->print(OB); @@ -1502,7 +1512,7 @@ public: template void match(Fn F) const { F(Child); } - StringView getBaseName() const override { return Child->getBaseName(); } + std::string_view getBaseName() const override { return Child->getBaseName(); } void printLeft(OutputBuffer &OB) const override { OB += "::"; @@ -1538,20 +1548,20 @@ protected: return unsigned(SSK) >= unsigned(SpecialSubKind::string); } - StringView getBaseName() const override { + std::string_view getBaseName() const override { switch (SSK) { case SpecialSubKind::allocator: - return StringView("allocator"); + return {"allocator"}; case SpecialSubKind::basic_string: - return StringView("basic_string"); + return {"basic_string"}; case SpecialSubKind::string: - return StringView("basic_string"); + return {"basic_string"}; case SpecialSubKind::istream: - return StringView("basic_istream"); + return {"basic_istream"}; case SpecialSubKind::ostream: - return StringView("basic_ostream"); + return {"basic_ostream"}; case SpecialSubKind::iostream: - return StringView("basic_iostream"); + return {"basic_iostream"}; } DEMANGLE_UNREACHABLE; } @@ -1575,12 +1585,12 @@ public: template void match(Fn F) const { F(SSK); } - StringView getBaseName() const override { - auto SV = ExpandedSpecialSubstitution::getBaseName (); + std::string_view getBaseName() const override { + std::string_view SV = ExpandedSpecialSubstitution::getBaseName(); if (isInstantiation()) { // The instantiations are typedefs that drop the "basic_" prefix. - assert(SV.startsWith("basic_")); - SV = SV.dropFront(sizeof("basic_") - 1); + assert(starts_with(SV, "basic_")); + SV.remove_prefix(sizeof("basic_") - 1); } return SV; } @@ -1628,10 +1638,11 @@ public: }; class UnnamedTypeName : public Node { - const StringView Count; + const std::string_view Count; public: - UnnamedTypeName(StringView Count_) : Node(KUnnamedTypeName), Count(Count_) {} + UnnamedTypeName(std::string_view Count_) + : Node(KUnnamedTypeName), Count(Count_) {} template void match(Fn F) const { F(Count); } @@ -1645,11 +1656,11 @@ public: class ClosureTypeName : public Node { NodeArray TemplateParams; NodeArray Params; - StringView Count; + std::string_view Count; public: ClosureTypeName(NodeArray TemplateParams_, NodeArray Params_, - StringView Count_) + std::string_view Count_) : Node(KClosureTypeName), TemplateParams(TemplateParams_), Params(Params_), Count(Count_) {} @@ -1696,12 +1707,12 @@ public: class BinaryExpr : public Node { const Node *LHS; - const StringView InfixOperator; + const std::string_view InfixOperator; const Node *RHS; public: - BinaryExpr(const Node *LHS_, StringView InfixOperator_, const Node *RHS_, - Prec Prec_) + BinaryExpr(const Node *LHS_, std::string_view InfixOperator_, + const Node *RHS_, Prec Prec_) : Node(KBinaryExpr, Prec_), LHS(LHS_), InfixOperator(InfixOperator_), RHS(RHS_) {} @@ -1750,10 +1761,10 @@ public: class PostfixExpr : public Node { const Node *Child; - const StringView Operator; + const std::string_view Operator; public: - PostfixExpr(const Node *Child_, StringView Operator_, Prec Prec_) + PostfixExpr(const Node *Child_, std::string_view Operator_, Prec Prec_) : Node(KPostfixExpr, Prec_), Child(Child_), Operator(Operator_) {} template void match(Fn F) const { @@ -1791,11 +1802,12 @@ public: class MemberExpr : public Node { const Node *LHS; - const StringView Kind; + const std::string_view Kind; const Node *RHS; public: - MemberExpr(const Node *LHS_, StringView Kind_, const Node *RHS_, Prec Prec_) + MemberExpr(const Node *LHS_, std::string_view Kind_, const Node *RHS_, + Prec Prec_) : Node(KMemberExpr, Prec_), LHS(LHS_), Kind(Kind_), RHS(RHS_) {} template void match(Fn F) const { @@ -1812,13 +1824,14 @@ public: class SubobjectExpr : public Node { const Node *Type; const Node *SubExpr; - StringView Offset; + std::string_view Offset; NodeArray UnionSelectors; bool OnePastTheEnd; public: - SubobjectExpr(const Node *Type_, const Node *SubExpr_, StringView Offset_, - NodeArray UnionSelectors_, bool OnePastTheEnd_) + SubobjectExpr(const Node *Type_, const Node *SubExpr_, + std::string_view Offset_, NodeArray UnionSelectors_, + bool OnePastTheEnd_) : Node(KSubobjectExpr), Type(Type_), SubExpr(SubExpr_), Offset(Offset_), UnionSelectors(UnionSelectors_), OnePastTheEnd(OnePastTheEnd_) {} @@ -1835,7 +1848,7 @@ public: OB += "0"; } else if (Offset[0] == 'n') { OB += "-"; - OB += Offset.dropFront(); + OB += std::string_view(Offset.data() + 1, Offset.size() - 1); } else { OB += Offset; } @@ -1844,12 +1857,12 @@ public: }; class EnclosingExpr : public Node { - const StringView Prefix; + const std::string_view Prefix; const Node *Infix; - const StringView Postfix; + const std::string_view Postfix; public: - EnclosingExpr(StringView Prefix_, const Node *Infix_, + EnclosingExpr(std::string_view Prefix_, const Node *Infix_, Prec Prec_ = Prec::Primary) : Node(KEnclosingExpr, Prec_), Prefix(Prefix_), Infix(Infix_) {} @@ -1868,12 +1881,13 @@ public: class CastExpr : public Node { // cast_kind(from) - const StringView CastKind; + const std::string_view CastKind; const Node *To; const Node *From; public: - CastExpr(StringView CastKind_, const Node *To_, const Node *From_, Prec Prec_) + CastExpr(std::string_view CastKind_, const Node *To_, const Node *From_, + Prec Prec_) : Node(KCastExpr, Prec_), CastKind(CastKind_), To(To_), From(From_) {} template void match(Fn F) const { @@ -1996,11 +2010,11 @@ public: }; class PrefixExpr : public Node { - StringView Prefix; + std::string_view Prefix; Node *Child; public: - PrefixExpr(StringView Prefix_, Node *Child_, Prec Prec_) + PrefixExpr(std::string_view Prefix_, Node *Child_, Prec Prec_) : Node(KPrefixExpr, Prec_), Prefix(Prefix_), Child(Child_) {} template void match(Fn F) const { @@ -2014,10 +2028,11 @@ public: }; class FunctionParam : public Node { - StringView Number; + std::string_view Number; public: - FunctionParam(StringView Number_) : Node(KFunctionParam), Number(Number_) {} + FunctionParam(std::string_view Number_) + : Node(KFunctionParam), Number(Number_) {} template void match(Fn F) const { F(Number); } @@ -2052,11 +2067,11 @@ public: class PointerToMemberConversionExpr : public Node { const Node *Type; const Node *SubExpr; - StringView Offset; + std::string_view Offset; public: PointerToMemberConversionExpr(const Node *Type_, const Node *SubExpr_, - StringView Offset_, Prec Prec_) + std::string_view Offset_, Prec Prec_) : Node(KPointerToMemberConversionExpr, Prec_), Type(Type_), SubExpr(SubExpr_), Offset(Offset_) {} @@ -2141,11 +2156,11 @@ public: class FoldExpr : public Node { const Node *Pack, *Init; - StringView OperatorName; + std::string_view OperatorName; bool IsLeftFold; public: - FoldExpr(bool IsLeftFold_, StringView OperatorName_, const Node *Pack_, + FoldExpr(bool IsLeftFold_, std::string_view OperatorName_, const Node *Pack_, const Node *Init_) : Node(KFoldExpr), Pack(Pack_), Init(Init_), OperatorName(OperatorName_), IsLeftFold(IsLeftFold_) {} @@ -2209,7 +2224,7 @@ public: template void match(Fn F) const { F(Value); } void printLeft(OutputBuffer &OB) const override { - OB += Value ? StringView("true") : StringView("false"); + OB += Value ? std::string_view("true") : std::string_view("false"); } }; @@ -2247,10 +2262,10 @@ public: class EnumLiteral : public Node { // ty(integer) const Node *Ty; - StringView Integer; + std::string_view Integer; public: - EnumLiteral(const Node *Ty_, StringView Integer_) + EnumLiteral(const Node *Ty_, std::string_view Integer_) : Node(KEnumLiteral), Ty(Ty_), Integer(Integer_) {} template void match(Fn F) const { F(Ty, Integer); } @@ -2261,18 +2276,18 @@ public: OB.printClose(); if (Integer[0] == 'n') - OB << "-" << Integer.dropFront(1); + OB << '-' << std::string_view(Integer.data() + 1, Integer.size() - 1); else OB << Integer; } }; class IntegerLiteral : public Node { - StringView Type; - StringView Value; + std::string_view Type; + std::string_view Value; public: - IntegerLiteral(StringView Type_, StringView Value_) + IntegerLiteral(std::string_view Type_, std::string_view Value_) : Node(KIntegerLiteral), Type(Type_), Value(Value_) {} template void match(Fn F) const { F(Type, Value); } @@ -2284,10 +2299,9 @@ public: OB.printClose(); } - if (Value[0] == 'n') { - OB += '-'; - OB += Value.dropFront(1); - } else + if (Value[0] == 'n') + OB << '-' << std::string_view(Value.data() + 1, Value.size() - 1); + else OB += Value; if (Type.size() <= 3) @@ -2310,29 +2324,26 @@ constexpr Node::Kind getFloatLiteralKind(long double *) { } template class FloatLiteralImpl : public Node { - const StringView Contents; + const std::string_view Contents; static constexpr Kind KindForClass = float_literal_impl::getFloatLiteralKind((Float *)nullptr); public: - FloatLiteralImpl(StringView Contents_) + FloatLiteralImpl(std::string_view Contents_) : Node(KindForClass), Contents(Contents_) {} template void match(Fn F) const { F(Contents); } void printLeft(OutputBuffer &OB) const override { - const char *first = Contents.begin(); - const char *last = Contents.end() + 1; - const size_t N = FloatData::mangled_size; - if (static_cast(last - first) > N) { - last = first + N; + if (Contents.size() >= N) { union { Float value; char buf[sizeof(Float)]; }; - const char *t = first; + const char *t = Contents.data(); + const char *last = t + N; char *e = buf; for (; t != last; ++t, ++e) { unsigned d1 = isdigit(*t) ? static_cast(*t - '0') @@ -2347,7 +2358,7 @@ public: #endif char num[FloatData::max_demangled_size] = {0}; int n = snprintf(num, sizeof(num), FloatData::spec, value); - OB += StringView(num, num + n); + OB += std::string_view(num, n); } } }; @@ -2474,8 +2485,8 @@ template struct AbstractManglingParser { return res; } - bool consumeIf(StringView S) { - if (StringView(First, Last).startsWith(S)) { + bool consumeIf(std::string_view S) { + if (starts_with(std::string_view(First, Last - First), S)) { First += S.size(); return true; } @@ -2500,10 +2511,10 @@ template struct AbstractManglingParser { size_t numLeft() const { return static_cast(Last - First); } - StringView parseNumber(bool AllowNegative = false); + std::string_view parseNumber(bool AllowNegative = false); Qualifiers parseCVQualifiers(); bool parsePositiveInteger(size_t *Out); - StringView parseBareSourceName(); + std::string_view parseBareSourceName(); bool parseSeqId(size_t *Out); Node *parseSubstitution(); @@ -2514,9 +2525,9 @@ template struct AbstractManglingParser { /// Parse the production. Node *parseExpr(); - Node *parsePrefixExpr(StringView Kind, Node::Prec Prec); - Node *parseBinaryExpr(StringView Kind, Node::Prec Prec); - Node *parseIntegerLiteral(StringView Lit); + Node *parsePrefixExpr(std::string_view Kind, Node::Prec Prec); + Node *parseBinaryExpr(std::string_view Kind, Node::Prec Prec); + Node *parseIntegerLiteral(std::string_view Lit); Node *parseExprPrimary(); template Node *parseFloatingLiteral(); Node *parseFunctionParam(); @@ -2624,17 +2635,18 @@ template struct AbstractManglingParser { bool operator!=(const char *Peek) const { return !this->operator==(Peek); } public: - StringView getSymbol() const { - StringView Res = Name; + std::string_view getSymbol() const { + std::string_view Res = Name; if (Kind < Unnameable) { - assert(Res.startsWith("operator") && + assert(starts_with(Res, "operator") && "operator name does not start with 'operator'"); - Res = Res.dropFront(sizeof("operator") - 1); - Res.consumeFront(' '); + Res.remove_prefix(sizeof("operator") - 1); + if (starts_with(Res, ' ')) + Res.remove_prefix(1); } return Res; } - StringView getName() const { return Name; } + std::string_view getName() const { return Name; } OIKind getKind() const { return Kind; } bool getFlag() const { return Flag; } Node::Prec getPrecedence() const { return Prec; } @@ -2854,7 +2866,7 @@ AbstractManglingParser::parseUnnamedTypeName(NameState *State) { TemplateParams.clear(); if (consumeIf("Ut")) { - StringView Count = parseNumber(); + std::string_view Count = parseNumber(); if (!consumeIf('_')) return nullptr; return make(Count); @@ -2866,7 +2878,7 @@ AbstractManglingParser::parseUnnamedTypeName(NameState *State) { size_t ParamsBegin = Names.size(); while (look() == 'T' && - StringView("yptn").find(look(1)) != StringView::npos) { + std::string_view("yptn").find(look(1)) != std::string_view::npos) { Node *T = parseTemplateParamDecl(); if (!T) return nullptr; @@ -2909,7 +2921,7 @@ AbstractManglingParser::parseUnnamedTypeName(NameState *State) { } NodeArray Params = popTrailingNodeArray(ParamsBegin); - StringView Count = parseNumber(); + std::string_view Count = parseNumber(); if (!consumeIf('_')) return nullptr; return make(TempParams, Params, Count); @@ -2931,9 +2943,9 @@ Node *AbstractManglingParser::parseSourceName(NameState *) { return nullptr; if (numLeft() < Length || Length == 0) return nullptr; - StringView Name(First, First + Length); + std::string_view Name(First, Length); First += Length; - if (Name.startsWith("_GLOBAL__N")) + if (starts_with(Name, "_GLOBAL__N")) return make("(anonymous namespace)"); return make(Name); } @@ -3447,7 +3459,7 @@ Node *AbstractManglingParser::parseUnresolvedName(bool Global) { template Node *AbstractManglingParser::parseAbiTags(Node *N) { while (consumeIf('B')) { - StringView SN = parseBareSourceName(); + std::string_view SN = parseBareSourceName(); if (SN.empty()) return nullptr; N = make(N, SN); @@ -3459,16 +3471,16 @@ Node *AbstractManglingParser::parseAbiTags(Node *N) { // ::= [n] template -StringView +std::string_view AbstractManglingParser::parseNumber(bool AllowNegative) { const char *Tmp = First; if (AllowNegative) consumeIf('n'); if (numLeft() == 0 || !std::isdigit(*First)) - return StringView(); + return std::string_view(); while (numLeft() != 0 && std::isdigit(*First)) ++First; - return StringView(Tmp, First); + return std::string_view(Tmp, First - Tmp); } // ::= [0-9]* @@ -3485,11 +3497,11 @@ bool AbstractManglingParser::parsePositiveInteger(size_t *Out) { } template -StringView AbstractManglingParser::parseBareSourceName() { +std::string_view AbstractManglingParser::parseBareSourceName() { size_t Int = 0; if (parsePositiveInteger(&Int) || numLeft() < Int) - return StringView(); - StringView R(First, First + Int); + return {}; + std::string_view R(First, Int); First += Int; return R; } @@ -3673,7 +3685,7 @@ Node *AbstractManglingParser::parsePointerToMemberType() { // ::= Te # dependent elaborated type specifier using 'enum' template Node *AbstractManglingParser::parseClassEnumType() { - StringView ElabSpef; + std::string_view ElabSpef; if (consumeIf("Ts")) ElabSpef = "struct"; else if (consumeIf("Tu")) @@ -3697,17 +3709,18 @@ Node *AbstractManglingParser::parseClassEnumType() { template Node *AbstractManglingParser::parseQualifiedType() { if (consumeIf('U')) { - StringView Qual = parseBareSourceName(); + std::string_view Qual = parseBareSourceName(); if (Qual.empty()) return nullptr; // extension ::= U # objc-type - if (Qual.startsWith("objcproto")) { - StringView ProtoSourceName = Qual.dropFront(std::strlen("objcproto")); - StringView Proto; + if (starts_with(Qual, "objcproto")) { + constexpr size_t Len = sizeof("objcproto") - 1; + std::string_view ProtoSourceName(Qual.data() + Len, Qual.size() - Len); + std::string_view Proto; { - ScopedOverride SaveFirst(First, ProtoSourceName.begin()), - SaveLast(Last, ProtoSourceName.end()); + ScopedOverride SaveFirst(First, ProtoSourceName.data()), + SaveLast(Last, &*ProtoSourceName.rbegin() + 1); Proto = parseBareSourceName(); } if (Proto.empty()) @@ -3875,7 +3888,7 @@ Node *AbstractManglingParser::parseType() { // ::= u # vendor extended type case 'u': { ++First; - StringView Res = parseBareSourceName(); + std::string_view Res = parseBareSourceName(); if (Res.empty()) return nullptr; // Typically, s are not considered substitution candidates, @@ -4123,8 +4136,9 @@ Node *AbstractManglingParser::parseType() { } template -Node *AbstractManglingParser::parsePrefixExpr(StringView Kind, - Node::Prec Prec) { +Node * +AbstractManglingParser::parsePrefixExpr(std::string_view Kind, + Node::Prec Prec) { Node *E = getDerived().parseExpr(); if (E == nullptr) return nullptr; @@ -4132,8 +4146,9 @@ Node *AbstractManglingParser::parsePrefixExpr(StringView Kind, } template -Node *AbstractManglingParser::parseBinaryExpr(StringView Kind, - Node::Prec Prec) { +Node * +AbstractManglingParser::parseBinaryExpr(std::string_view Kind, + Node::Prec Prec) { Node *LHS = getDerived().parseExpr(); if (LHS == nullptr) return nullptr; @@ -4144,9 +4159,9 @@ Node *AbstractManglingParser::parseBinaryExpr(StringView Kind, } template -Node * -AbstractManglingParser::parseIntegerLiteral(StringView Lit) { - StringView Tmp = parseNumber(true); +Node *AbstractManglingParser::parseIntegerLiteral( + std::string_view Lit) { + std::string_view Tmp = parseNumber(true); if (!Tmp.empty() && consumeIf('E')) return make(Lit, Tmp); return nullptr; @@ -4176,7 +4191,7 @@ Node *AbstractManglingParser::parseFunctionParam() { return make("this"); if (consumeIf("fp")) { parseCVQualifiers(); - StringView Num = parseNumber(); + std::string_view Num = parseNumber(); if (!consumeIf('_')) return nullptr; return make(Num); @@ -4187,7 +4202,7 @@ Node *AbstractManglingParser::parseFunctionParam() { if (!consumeIf('p')) return nullptr; parseCVQualifiers(); - StringView Num = parseNumber(); + std::string_view Num = parseNumber(); if (!consumeIf('_')) return nullptr; return make(Num); @@ -4341,7 +4356,7 @@ Node *AbstractManglingParser::parseExprPrimary() { Node *T = getDerived().parseType(); if (T == nullptr) return nullptr; - StringView N = parseNumber(/*AllowNegative=*/true); + std::string_view N = parseNumber(/*AllowNegative=*/true); if (N.empty()) return nullptr; if (!consumeIf('E')) @@ -4464,7 +4479,7 @@ AbstractManglingParser::parsePointerToMemberConversionExpr( Node *Expr = getDerived().parseExpr(); if (!Expr) return nullptr; - StringView Offset = getDerived().parseNumber(true); + std::string_view Offset = getDerived().parseNumber(true); if (!consumeIf('E')) return nullptr; return make(Ty, Expr, Offset, Prec); @@ -4482,7 +4497,7 @@ Node *AbstractManglingParser::parseSubobjectExpr() { Node *Expr = getDerived().parseExpr(); if (!Expr) return nullptr; - StringView Offset = getDerived().parseNumber(true); + std::string_view Offset = getDerived().parseNumber(true); size_t SelectorsBegin = Names.size(); while (consumeIf('_')) { Node *Selector = make(parseNumber()); @@ -5141,7 +5156,7 @@ Node *AbstractManglingParser::parseFloatingLiteral() { const size_t N = FloatData::mangled_size; if (numLeft() <= N) return nullptr; - StringView Data(First, First + N); + std::string_view Data(First, N); for (char C : Data) if (!std::isxdigit(C)) return nullptr; @@ -5461,7 +5476,8 @@ Node *AbstractManglingParser::parse() { if (Encoding == nullptr) return nullptr; if (look() == '.') { - Encoding = make(Encoding, StringView(First, Last)); + Encoding = + make(Encoding, std::string_view(First, Last - First)); First = Last; } if (numLeft() != 0) @@ -5497,4 +5513,8 @@ struct ManglingParser : AbstractManglingParser, Alloc> { DEMANGLE_NAMESPACE_END +#ifdef _LIBCXXABI_COMPILER_CLANG +#pragma clang diagnostic pop +#endif + #endif // DEMANGLE_ITANIUMDEMANGLE_H diff --git a/lib/libcxxabi/src/demangle/StringView.h b/lib/libcxxabi/src/demangle/StringView.h deleted file mode 100644 index 90890e3771..0000000000 --- a/lib/libcxxabi/src/demangle/StringView.h +++ /dev/null @@ -1,122 +0,0 @@ -//===--- StringView.h -------------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// FIXME: Use std::string_view instead when we support C++17. -// There are two copies of this file in the source tree. The one under -// libcxxabi is the original and the one under llvm is the copy. Use -// cp-to-llvm.sh to update the copy. See README.txt for more details. -// -//===----------------------------------------------------------------------===// - -#ifndef DEMANGLE_STRINGVIEW_H -#define DEMANGLE_STRINGVIEW_H - -#include "DemangleConfig.h" -#include -#include - -DEMANGLE_NAMESPACE_BEGIN - -class StringView { - const char *First; - const char *Last; - -public: - static const size_t npos = ~size_t(0); - - template - StringView(const char (&Str)[N]) : First(Str), Last(Str + N - 1) {} - StringView(const char *First_, const char *Last_) - : First(First_), Last(Last_) {} - StringView(const char *First_, size_t Len) - : First(First_), Last(First_ + Len) {} - StringView(const char *Str) : First(Str), Last(Str + std::strlen(Str)) {} - StringView() : First(nullptr), Last(nullptr) {} - - StringView substr(size_t Pos, size_t Len = npos) const { - assert(Pos <= size()); - if (Len > size() - Pos) - Len = size() - Pos; - return StringView(begin() + Pos, Len); - } - - size_t find(char C, size_t From = 0) const { - // Avoid calling memchr with nullptr. - if (From < size()) { - // Just forward to memchr, which is faster than a hand-rolled loop. - if (const void *P = ::memchr(First + From, C, size() - From)) - return size_t(static_cast(P) - First); - } - return npos; - } - - StringView dropFront(size_t N = 1) const { - if (N >= size()) - N = size(); - return StringView(First + N, Last); - } - - StringView dropBack(size_t N = 1) const { - if (N >= size()) - N = size(); - return StringView(First, Last - N); - } - - char front() const { - assert(!empty()); - return *begin(); - } - - char back() const { - assert(!empty()); - return *(end() - 1); - } - - char popFront() { - assert(!empty()); - return *First++; - } - - bool consumeFront(char C) { - if (!startsWith(C)) - return false; - *this = dropFront(1); - return true; - } - - bool consumeFront(StringView S) { - if (!startsWith(S)) - return false; - *this = dropFront(S.size()); - return true; - } - - bool startsWith(char C) const { return !empty() && *begin() == C; } - - bool startsWith(StringView Str) const { - if (Str.size() > size()) - return false; - return std::strncmp(Str.begin(), begin(), Str.size()) == 0; - } - - const char &operator[](size_t Idx) const { return *(begin() + Idx); } - - const char *begin() const { return First; } - const char *end() const { return Last; } - size_t size() const { return static_cast(Last - First); } - bool empty() const { return First == Last; } -}; - -inline bool operator==(const StringView &LHS, const StringView &RHS) { - return LHS.size() == RHS.size() && - std::strncmp(LHS.begin(), RHS.begin(), LHS.size()) == 0; -} - -DEMANGLE_NAMESPACE_END - -#endif diff --git a/lib/libcxxabi/src/demangle/StringViewExtras.h b/lib/libcxxabi/src/demangle/StringViewExtras.h new file mode 100644 index 0000000000..0ad1f8c8a2 --- /dev/null +++ b/lib/libcxxabi/src/demangle/StringViewExtras.h @@ -0,0 +1,38 @@ +//===--- StringViewExtras.h -------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// There are two copies of this file in the source tree. The one under +// libcxxabi is the original and the one under llvm is the copy. Use +// cp-to-llvm.sh to update the copy. See README.txt for more details. +// +//===----------------------------------------------------------------------===// + +#ifndef DEMANGLE_STRINGVIEW_H +#define DEMANGLE_STRINGVIEW_H + +#include "DemangleConfig.h" + +#include + +DEMANGLE_NAMESPACE_BEGIN + +inline bool starts_with(std::string_view self, char C) noexcept { + return !self.empty() && *self.begin() == C; +} + +inline bool starts_with(std::string_view haystack, + std::string_view needle) noexcept { + if (needle.size() > haystack.size()) + return false; + haystack.remove_suffix(haystack.size() - needle.size()); + return haystack == needle; +} + +DEMANGLE_NAMESPACE_END + +#endif diff --git a/lib/libcxxabi/src/demangle/Utility.h b/lib/libcxxabi/src/demangle/Utility.h index c9b211b544..8370633ace 100644 --- a/lib/libcxxabi/src/demangle/Utility.h +++ b/lib/libcxxabi/src/demangle/Utility.h @@ -16,13 +16,16 @@ #ifndef DEMANGLE_UTILITY_H #define DEMANGLE_UTILITY_H -#include "StringView.h" +#include "DemangleConfig.h" + #include +#include #include #include #include #include #include +#include DEMANGLE_NAMESPACE_BEGIN @@ -64,7 +67,8 @@ class OutputBuffer { if (isNeg) *--TempPtr = '-'; - return operator+=(StringView(TempPtr, Temp.data() + Temp.size())); + return operator+=( + std::string_view(TempPtr, Temp.data() + Temp.size() - TempPtr)); } public: @@ -77,7 +81,9 @@ public: OutputBuffer(const OutputBuffer &) = delete; OutputBuffer &operator=(const OutputBuffer &) = delete; - operator StringView() const { return StringView(Buffer, CurrentPosition); } + operator std::string_view() const { + return std::string_view(Buffer, CurrentPosition); + } /// If a ParameterPackExpansion (or similar type) is encountered, the offset /// into the pack that we're currently printing. @@ -99,10 +105,10 @@ public: *this += Close; } - OutputBuffer &operator+=(StringView R) { + OutputBuffer &operator+=(std::string_view R) { if (size_t Size = R.size()) { grow(Size); - std::memcpy(Buffer + CurrentPosition, R.begin(), Size); + std::memcpy(Buffer + CurrentPosition, &*R.begin(), Size); CurrentPosition += Size; } return *this; @@ -114,18 +120,18 @@ public: return *this; } - OutputBuffer &prepend(StringView R) { + OutputBuffer &prepend(std::string_view R) { size_t Size = R.size(); grow(Size); std::memmove(Buffer + Size, Buffer, CurrentPosition); - std::memcpy(Buffer, R.begin(), Size); + std::memcpy(Buffer, &*R.begin(), Size); CurrentPosition += Size; return *this; } - OutputBuffer &operator<<(StringView R) { return (*this += R); } + OutputBuffer &operator<<(std::string_view R) { return (*this += R); } OutputBuffer &operator<<(char C) { return (*this += C); } diff --git a/lib/libcxxabi/src/fallback_malloc.cpp b/lib/libcxxabi/src/fallback_malloc.cpp index 591efbefc8..f9fb1bc463 100644 --- a/lib/libcxxabi/src/fallback_malloc.cpp +++ b/lib/libcxxabi/src/fallback_malloc.cpp @@ -15,10 +15,10 @@ #endif #endif +#include <__memory/aligned_alloc.h> #include #include // for malloc, calloc, free #include // for memset -#include // for std::__libcpp_aligned_{alloc,free} // A small, simple heap manager based (loosely) on // the startup heap manager from FreeBSD, optimized for space. diff --git a/lib/libcxxabi/src/private_typeinfo.cpp b/lib/libcxxabi/src/private_typeinfo.cpp index e1086661c0..83d1f9f130 100644 --- a/lib/libcxxabi/src/private_typeinfo.cpp +++ b/lib/libcxxabi/src/private_typeinfo.cpp @@ -41,6 +41,7 @@ // Defining _LIBCXXABI_FORGIVING_DYNAMIC_CAST does not help since can_catch() calls // is_equal() with use_strcmp=false so the string names are not compared. +#include #include #ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST @@ -656,77 +657,138 @@ __dynamic_cast(const void *static_ptr, const __class_type_info *static_type, // Find out if we can use a giant short cut in the search if (is_equal(dynamic_type, dst_type, false)) { - // 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'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) { - // We get here only if there is some kind of visibility problem - // in client code. - static_assert(std::atomic::is_always_lock_free, ""); - static std::atomic 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); + // 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::is_always_lock_free, ""); + static std::atomic 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; + // Query the search. + if (info.path_dst_ptr_to_static_ptr == public_path) + dst_ptr = dynamic_ptr; + } } else { - // 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) + if (src2dst_offset >= 0) { - static_assert(std::atomic::is_always_lock_free, ""); - static std::atomic 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); + // 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(static_ptr) - src2dst_offset; + if (reinterpret_cast(dst_ptr_to_static) >= reinterpret_cast(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; + } + } } -#endif // _LIBCXXABI_FORGIVING_DYNAMIC_CAST - // Query the search. - switch (info.number_to_static_ptr) + + if (!dst_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; + // 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::is_always_lock_free, ""); + static std::atomic 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; + } } } return const_cast(dst_ptr); diff --git a/lib/libcxxabi/src/stdlib_new_delete.cpp b/lib/libcxxabi/src/stdlib_new_delete.cpp index 4a664e15a5..080f932ccc 100644 --- a/lib/libcxxabi/src/stdlib_new_delete.cpp +++ b/lib/libcxxabi/src/stdlib_new_delete.cpp @@ -4,30 +4,40 @@ // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // -// -// This file implements the new and delete operators. //===----------------------------------------------------------------------===// #include "__cxxabi_config.h" -#include +#include <__memory/aligned_alloc.h> #include +#include -#if !defined(_THROW_BAD_ALLOC) || !defined(_LIBCXXABI_WEAK) -#error The _THROW_BAD_ALLOC and _LIBCXXABI_WEAK libc++ macros must \ - already be defined by libc++. +// Perform a few sanity checks on libc++ and libc++abi macros to ensure that +// the code below can be an exact copy of the code in libcxx/src/new.cpp. +#if !defined(_THROW_BAD_ALLOC) +# error The _THROW_BAD_ALLOC macro should be already defined by libc++ #endif + +#ifndef _LIBCPP_WEAK +# error The _LIBCPP_WEAK macro should be already defined by libc++ +#endif + +#if defined(_LIBCXXABI_NO_EXCEPTIONS) != defined(_LIBCPP_HAS_NO_EXCEPTIONS) +# error libc++ and libc++abi seem to disagree on whether exceptions are enabled +#endif + +// ------------------ 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. -_LIBCXXABI_WEAK +_LIBCPP_WEAK void * operator new(std::size_t size) _THROW_BAD_ALLOC { if (size == 0) size = 1; void* p; - while ((p = ::malloc(size)) == nullptr) + while ((p = std::malloc(size)) == nullptr) { // If malloc fails and there is a new_handler, // call it to try free up memory. @@ -35,7 +45,7 @@ operator new(std::size_t size) _THROW_BAD_ALLOC if (nh) nh(); else -#ifndef _LIBCXXABI_NO_EXCEPTIONS +#ifndef _LIBCPP_HAS_NO_EXCEPTIONS throw std::bad_alloc(); #else break; @@ -44,87 +54,87 @@ operator new(std::size_t size) _THROW_BAD_ALLOC return p; } -_LIBCXXABI_WEAK +_LIBCPP_WEAK void* operator new(size_t size, const std::nothrow_t&) noexcept { void* p = nullptr; -#ifndef _LIBCXXABI_NO_EXCEPTIONS +#ifndef _LIBCPP_HAS_NO_EXCEPTIONS try { -#endif // _LIBCXXABI_NO_EXCEPTIONS +#endif // _LIBCPP_HAS_NO_EXCEPTIONS p = ::operator new(size); -#ifndef _LIBCXXABI_NO_EXCEPTIONS +#ifndef _LIBCPP_HAS_NO_EXCEPTIONS } catch (...) { } -#endif // _LIBCXXABI_NO_EXCEPTIONS +#endif // _LIBCPP_HAS_NO_EXCEPTIONS return p; } -_LIBCXXABI_WEAK +_LIBCPP_WEAK void* operator new[](size_t size) _THROW_BAD_ALLOC { return ::operator new(size); } -_LIBCXXABI_WEAK +_LIBCPP_WEAK void* operator new[](size_t size, const std::nothrow_t&) noexcept { void* p = nullptr; -#ifndef _LIBCXXABI_NO_EXCEPTIONS +#ifndef _LIBCPP_HAS_NO_EXCEPTIONS try { -#endif // _LIBCXXABI_NO_EXCEPTIONS +#endif // _LIBCPP_HAS_NO_EXCEPTIONS p = ::operator new[](size); -#ifndef _LIBCXXABI_NO_EXCEPTIONS +#ifndef _LIBCPP_HAS_NO_EXCEPTIONS } catch (...) { } -#endif // _LIBCXXABI_NO_EXCEPTIONS +#endif // _LIBCPP_HAS_NO_EXCEPTIONS return p; } -_LIBCXXABI_WEAK +_LIBCPP_WEAK void operator delete(void* ptr) noexcept { - ::free(ptr); + std::free(ptr); } -_LIBCXXABI_WEAK +_LIBCPP_WEAK void operator delete(void* ptr, const std::nothrow_t&) noexcept { ::operator delete(ptr); } -_LIBCXXABI_WEAK +_LIBCPP_WEAK void operator delete(void* ptr, size_t) noexcept { ::operator delete(ptr); } -_LIBCXXABI_WEAK +_LIBCPP_WEAK void operator delete[] (void* ptr) noexcept { ::operator delete(ptr); } -_LIBCXXABI_WEAK +_LIBCPP_WEAK void operator delete[] (void* ptr, const std::nothrow_t&) noexcept { ::operator delete[](ptr); } -_LIBCXXABI_WEAK +_LIBCPP_WEAK void operator delete[] (void* ptr, size_t) noexcept { @@ -133,7 +143,7 @@ operator delete[] (void* ptr, size_t) noexcept #if !defined(_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION) -_LIBCXXABI_WEAK +_LIBCPP_WEAK void * operator new(std::size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC { @@ -155,7 +165,7 @@ operator new(std::size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC if (nh) nh(); else { -#ifndef _LIBCXXABI_NO_EXCEPTIONS +#ifndef _LIBCPP_HAS_NO_EXCEPTIONS throw std::bad_alloc(); #else break; @@ -165,87 +175,87 @@ operator new(std::size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC return p; } -_LIBCXXABI_WEAK +_LIBCPP_WEAK void* operator new(size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept { void* p = nullptr; -#ifndef _LIBCXXABI_NO_EXCEPTIONS +#ifndef _LIBCPP_HAS_NO_EXCEPTIONS try { -#endif // _LIBCXXABI_NO_EXCEPTIONS +#endif // _LIBCPP_HAS_NO_EXCEPTIONS p = ::operator new(size, alignment); -#ifndef _LIBCXXABI_NO_EXCEPTIONS +#ifndef _LIBCPP_HAS_NO_EXCEPTIONS } catch (...) { } -#endif // _LIBCXXABI_NO_EXCEPTIONS +#endif // _LIBCPP_HAS_NO_EXCEPTIONS return p; } -_LIBCXXABI_WEAK +_LIBCPP_WEAK void* operator new[](size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC { return ::operator new(size, alignment); } -_LIBCXXABI_WEAK +_LIBCPP_WEAK void* operator new[](size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept { void* p = nullptr; -#ifndef _LIBCXXABI_NO_EXCEPTIONS +#ifndef _LIBCPP_HAS_NO_EXCEPTIONS try { -#endif // _LIBCXXABI_NO_EXCEPTIONS +#endif // _LIBCPP_HAS_NO_EXCEPTIONS p = ::operator new[](size, alignment); -#ifndef _LIBCXXABI_NO_EXCEPTIONS +#ifndef _LIBCPP_HAS_NO_EXCEPTIONS } catch (...) { } -#endif // _LIBCXXABI_NO_EXCEPTIONS +#endif // _LIBCPP_HAS_NO_EXCEPTIONS return p; } -_LIBCXXABI_WEAK +_LIBCPP_WEAK void operator delete(void* ptr, std::align_val_t) noexcept { std::__libcpp_aligned_free(ptr); } -_LIBCXXABI_WEAK +_LIBCPP_WEAK void operator delete(void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept { ::operator delete(ptr, alignment); } -_LIBCXXABI_WEAK +_LIBCPP_WEAK void operator delete(void* ptr, size_t, std::align_val_t alignment) noexcept { ::operator delete(ptr, alignment); } -_LIBCXXABI_WEAK +_LIBCPP_WEAK void operator delete[] (void* ptr, std::align_val_t alignment) noexcept { ::operator delete(ptr, alignment); } -_LIBCXXABI_WEAK +_LIBCPP_WEAK void operator delete[] (void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept { ::operator delete[](ptr, alignment); } -_LIBCXXABI_WEAK +_LIBCPP_WEAK void operator delete[] (void* ptr, size_t, std::align_val_t alignment) noexcept { @@ -253,3 +263,4 @@ operator delete[] (void* ptr, size_t, std::align_val_t alignment) noexcept } #endif // !_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION +// ------------------ END COPY ------------------