diff --git a/llvm/include/llvm/Demangle/Demangle.h b/llvm/include/llvm/Demangle/Demangle.h --- a/llvm/include/llvm/Demangle/Demangle.h +++ b/llvm/include/llvm/Demangle/Demangle.h @@ -11,6 +11,7 @@ #include #include +#include namespace llvm { /// This is a llvm local version of __cxa_demangle. Other than the name and @@ -20,16 +21,52 @@ /// large enough, realloc is used to expand it. /// /// The *status will be set to a value from the following enumeration -enum : int { - demangle_unknown_error = -4, - demangle_invalid_args = -3, - demangle_invalid_mangled_name = -2, - demangle_memory_alloc_failure = -1, - demangle_success = 0, + +const std::error_category &demangleCategory(); + +enum class DemangleError { + InvalidFormat = -5, // When a specific demangler can't handle this string + Unknown = -4, + InvalidArgs = -3, // Null args or other problems with input + InvalidMangledName = + -2, // Looks like a mangled string we can handle, but can't + MemoryAllocFailure = -1, // Any allocation failure. + Success = 0, +}; + +class DemangleErrorCategory : public std::error_category { +public: + const char *name() const noexcept override { return "llvm.demangle"; } + std::string message(int EV) const override { + switch (static_cast(EV)) { + case llvm::DemangleError::InvalidFormat: + return "Invalid mangled format."; + case llvm::DemangleError::InvalidArgs: + return "Invalid arguments."; + case llvm::DemangleError::InvalidMangledName: + return "Invalid mangled name."; + case llvm::DemangleError::MemoryAllocFailure: + return "Failed to allocate memory."; + case llvm::DemangleError::Unknown: + return "Unknown error."; + case llvm::DemangleError::Success: + return "success."; + } + }; + + bool equivalent(const std::error_code &E, int DE) const noexcept override { + return *this == E.category() && static_cast(E.value()) == DE; + } }; +inline std::error_code make_error_code(llvm::DemangleError Err) { + return std::error_code(static_cast(Err), llvm::demangleCategory()); +} + +char *itaniumDemangle(const char *M, std::error_code &E); + char *itaniumDemangle(const char *mangled_name, char *buf, size_t *n, - int *status); + std::error_code &Err); enum MSDemangleFlags { MSDF_None = 0, @@ -130,4 +167,8 @@ }; } // namespace llvm +namespace std { +template <> struct is_error_code_enum : std::true_type {}; +} // namespace std + #endif diff --git a/llvm/include/llvm/Demangle/ItaniumDemangle.h b/llvm/include/llvm/Demangle/ItaniumDemangle.h --- a/llvm/include/llvm/Demangle/ItaniumDemangle.h +++ b/llvm/include/llvm/Demangle/ItaniumDemangle.h @@ -19,6 +19,7 @@ #include "DemangleConfig.h" #include "StringView.h" #include "Utility.h" +#include "Demangle.h" #include #include #include @@ -29,6 +30,7 @@ #include #include #include +#include DEMANGLE_NAMESPACE_BEGIN @@ -2651,7 +2653,7 @@ Node *parseDestructorName(); /// Top-level entry point into the parser. - Node *parse(); + Node *parse(std::error_code& Err); }; const char* parse_discriminator(const char* first, const char* last); @@ -5455,37 +5457,49 @@ // extension ::= ___Z _block_invoke+ // extension ::= ___Z _block_invoke_+ template -Node *AbstractManglingParser::parse() { +Node *AbstractManglingParser::parse(std::error_code& Err) { if (consumeIf("_Z") || consumeIf("__Z")) { Node *Encoding = getDerived().parseEncoding(); - if (Encoding == nullptr) + if (Encoding == nullptr) { + Err = make_error_code(DemangleError::InvalidMangledName); return nullptr; + } if (look() == '.') { Encoding = make(Encoding, StringView(First, Last)); First = Last; } - if (numLeft() != 0) + if (numLeft() != 0) { + Err = make_error_code(DemangleError::InvalidMangledName); return nullptr; + } return Encoding; } if (consumeIf("___Z") || consumeIf("____Z")) { Node *Encoding = getDerived().parseEncoding(); - if (Encoding == nullptr || !consumeIf("_block_invoke")) + if (Encoding == nullptr || !consumeIf("_block_invoke")) { + Err = make_error_code(DemangleError::InvalidMangledName); return nullptr; + } bool RequireNumber = consumeIf('_'); - if (parseNumber().empty() && RequireNumber) + if (parseNumber().empty() && RequireNumber) { + Err = make_error_code(DemangleError::InvalidMangledName); return nullptr; + } if (look() == '.') First = Last; - if (numLeft() != 0) + if (numLeft() != 0) { + Err = make_error_code(DemangleError::InvalidMangledName); return nullptr; + } return make("invocation function for block in ", Encoding); } Node *Ty = getDerived().parseType(); - if (numLeft() != 0) + if (numLeft() != 0) { + Err = make_error_code(DemangleError::InvalidFormat); return nullptr; + } return Ty; } diff --git a/llvm/lib/Demangle/Demangle.cpp b/llvm/lib/Demangle/Demangle.cpp --- a/llvm/lib/Demangle/Demangle.cpp +++ b/llvm/lib/Demangle/Demangle.cpp @@ -48,8 +48,9 @@ bool llvm::nonMicrosoftDemangle(const char *MangledName, std::string &Result) { char *Demangled = nullptr; + std::error_code E; if (isItaniumEncoding(MangledName)) - Demangled = itaniumDemangle(MangledName, nullptr, nullptr, nullptr); + Demangled = itaniumDemangle(MangledName, nullptr, nullptr, E); else if (isRustEncoding(MangledName)) Demangled = rustDemangle(MangledName); else if (isDLangEncoding(MangledName)) @@ -62,3 +63,8 @@ std::free(Demangled); return true; } + +const std::error_category &llvm::demangleCategory() { + static llvm::DemangleErrorCategory E; + return E; +} diff --git a/llvm/lib/Demangle/ItaniumDemangle.cpp b/llvm/lib/Demangle/ItaniumDemangle.cpp --- a/llvm/lib/Demangle/ItaniumDemangle.cpp +++ b/llvm/lib/Demangle/ItaniumDemangle.cpp @@ -366,20 +366,17 @@ using Demangler = itanium_demangle::ManglingParser; char *llvm::itaniumDemangle(const char *MangledName, char *Buf, - size_t *N, int *Status) { + size_t *N, std::error_code& Err) { if (MangledName == nullptr || (Buf != nullptr && N == nullptr)) { - if (Status) - *Status = demangle_invalid_args; + Err = make_error_code(DemangleError::InvalidArgs); return nullptr; } - int InternalStatus = demangle_success; Demangler Parser(MangledName, MangledName + std::strlen(MangledName)); - Node *AST = Parser.parse(); + std::error_code InternalE = make_error_code(DemangleError::Success); + Node *AST = Parser.parse(InternalE); - if (AST == nullptr) - InternalStatus = demangle_invalid_mangled_name; - else { + if (AST != nullptr) { OutputBuffer OB(Buf, N); assert(Parser.ForwardTemplateRefs.empty()); AST->print(OB); @@ -389,9 +386,12 @@ Buf = OB.getBuffer(); } - if (Status) - *Status = InternalStatus; - return InternalStatus == demangle_success ? Buf : nullptr; + Err = InternalE; + return Err == DemangleError::Success ? Buf : nullptr; +} + +char *llvm::itaniumDemangle(const char *M, std::error_code &E) { + return itaniumDemangle(M, nullptr, nullptr, E); } ItaniumPartialDemangler::ItaniumPartialDemangler() @@ -419,7 +419,8 @@ Demangler *Parser = static_cast(Context); size_t Len = std::strlen(MangledName); Parser->reset(MangledName, MangledName + Len); - RootNode = Parser->parse(); + std::error_code E; + RootNode = Parser->parse(E); return RootNode == nullptr; } diff --git a/llvm/lib/Demangle/MicrosoftDemangle.cpp b/llvm/lib/Demangle/MicrosoftDemangle.cpp --- a/llvm/lib/Demangle/MicrosoftDemangle.cpp +++ b/llvm/lib/Demangle/MicrosoftDemangle.cpp @@ -2350,9 +2350,9 @@ if (Flags & MSDF_NoVariableType) OF = OutputFlags(OF | OF_NoVariableType); - int InternalStatus = demangle_success; + int InternalStatus = (int)DemangleError::Success; if (D.Error) - InternalStatus = demangle_invalid_mangled_name; + InternalStatus = (int)DemangleError::InvalidMangledName; else { OutputBuffer OB(Buf, N); AST->output(OB, OF); @@ -2364,5 +2364,5 @@ if (Status) *Status = InternalStatus; - return InternalStatus == demangle_success ? Buf : nullptr; + return InternalStatus == (int)DemangleError::Success ? Buf : nullptr; } diff --git a/llvm/lib/ProfileData/GCOV.cpp b/llvm/lib/ProfileData/GCOV.cpp --- a/llvm/lib/ProfileData/GCOV.cpp +++ b/llvm/lib/ProfileData/GCOV.cpp @@ -337,10 +337,10 @@ if (demangled.empty()) { do { if (Name.startswith("_Z")) { - int status = 0; + std::error_code E; // Name is guaranteed to be NUL-terminated. - char *res = itaniumDemangle(Name.data(), nullptr, nullptr, &status); - if (status == 0) { + char *res = itaniumDemangle(Name.data(), nullptr, nullptr, E); + if (E == DemangleError::Success) { demangled = res; free(res); break; diff --git a/llvm/lib/ProfileData/ItaniumManglingCanonicalizer.cpp b/llvm/lib/ProfileData/ItaniumManglingCanonicalizer.cpp --- a/llvm/lib/ProfileData/ItaniumManglingCanonicalizer.cpp +++ b/llvm/lib/ProfileData/ItaniumManglingCanonicalizer.cpp @@ -287,9 +287,10 @@ // encoding 6memcpy 7memmove // consistent with how they are encoded as local-names inside a C++ mangling. Node *N; + std::error_code E; if (Mangling.startswith("_Z") || Mangling.startswith("__Z") || Mangling.startswith("___Z") || Mangling.startswith("____Z")) - N = Demangler.parse(); + N = Demangler.parse(E); else N = Demangler.make( StringView(Mangling.data(), Mangling.size())); diff --git a/llvm/lib/Support/Unix/Signals.inc b/llvm/lib/Support/Unix/Signals.inc --- a/llvm/lib/Support/Unix/Signals.inc +++ b/llvm/lib/Support/Unix/Signals.inc @@ -617,9 +617,9 @@ if (dlinfo.dli_sname != nullptr) { OS << ' '; - int res; - char *d = itaniumDemangle(dlinfo.dli_sname, nullptr, nullptr, &res); - if (!d) + std::error_code E; + char *d = itaniumDemangle(dlinfo.dli_sname, nullptr, nullptr, E); + if (E != DemangleError::Success) OS << dlinfo.dli_sname; else OS << d; diff --git a/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp b/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp --- a/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp +++ b/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp @@ -81,13 +81,14 @@ std::string Prefix; char *Undecorated = nullptr; + std::error_code E; if (Types) - Undecorated = itaniumDemangle(DecoratedStr, nullptr, nullptr, nullptr); + Undecorated = itaniumDemangle(DecoratedStr, E); if (!Undecorated && strncmp(DecoratedStr, "__imp_", 6) == 0) { Prefix = "import thunk for "; - Undecorated = itaniumDemangle(DecoratedStr + 6, nullptr, nullptr, nullptr); + Undecorated = itaniumDemangle(DecoratedStr + 6, E); } Result = Undecorated ? Prefix + Undecorated : Mangled; diff --git a/llvm/tools/llvm-itanium-demangle-fuzzer/llvm-itanium-demangle-fuzzer.cpp b/llvm/tools/llvm-itanium-demangle-fuzzer/llvm-itanium-demangle-fuzzer.cpp --- a/llvm/tools/llvm-itanium-demangle-fuzzer/llvm-itanium-demangle-fuzzer.cpp +++ b/llvm/tools/llvm-itanium-demangle-fuzzer/llvm-itanium-demangle-fuzzer.cpp @@ -14,9 +14,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { std::string NullTerminatedString((const char *)Data, Size); - int status = 0; - if (char *demangle = llvm::itaniumDemangle(NullTerminatedString.c_str(), nullptr, - nullptr, &status)) + std::error_code E; + if (char *demangle = llvm::itaniumDemangle(NullTerminatedString.c_str(), E)) free(demangle); return 0; diff --git a/llvm/tools/llvm-objdump/MachODump.cpp b/llvm/tools/llvm-objdump/MachODump.cpp --- a/llvm/tools/llvm-objdump/MachODump.cpp +++ b/llvm/tools/llvm-objdump/MachODump.cpp @@ -7280,9 +7280,9 @@ } else if (SymbolName != nullptr && strncmp(SymbolName, "__Z", 3) == 0) { if (info->demangled_name != nullptr) free(info->demangled_name); - int status; + std::error_code E; info->demangled_name = - itaniumDemangle(SymbolName + 1, nullptr, nullptr, &status); + itaniumDemangle(SymbolName + 1, E); if (info->demangled_name != nullptr) { *ReferenceName = info->demangled_name; *ReferenceType = LLVMDisassembler_ReferenceType_DeMangled_Name; @@ -7380,9 +7380,9 @@ } else if (SymbolName != nullptr && strncmp(SymbolName, "__Z", 3) == 0) { if (info->demangled_name != nullptr) free(info->demangled_name); - int status; + std::error_code E; info->demangled_name = - itaniumDemangle(SymbolName + 1, nullptr, nullptr, &status); + itaniumDemangle(SymbolName + 1, E); if (info->demangled_name != nullptr) { *ReferenceName = info->demangled_name; *ReferenceType = LLVMDisassembler_ReferenceType_DeMangled_Name; diff --git a/llvm/tools/llvm-opt-report/OptReport.cpp b/llvm/tools/llvm-opt-report/OptReport.cpp --- a/llvm/tools/llvm-opt-report/OptReport.cpp +++ b/llvm/tools/llvm-opt-report/OptReport.cpp @@ -338,10 +338,10 @@ bool Printed = false; if (!NoDemangle) { - int Status = 0; + std::error_code E; char *Demangled = - itaniumDemangle(FuncName.c_str(), nullptr, nullptr, &Status); - if (Demangled && Status == 0) { + itaniumDemangle(FuncName.c_str(), E); + if (Demangled && E == DemangleError::Success) { OS << Demangled; Printed = true; } diff --git a/llvm/tools/llvm-undname/llvm-undname.cpp b/llvm/tools/llvm-undname/llvm-undname.cpp --- a/llvm/tools/llvm-undname/llvm-undname.cpp +++ b/llvm/tools/llvm-undname/llvm-undname.cpp @@ -77,7 +77,7 @@ size_t NRead; char *ResultBuf = microsoftDemangle(S.c_str(), &NRead, nullptr, nullptr, &Status, Flags); - if (Status == llvm::demangle_success) { + if (Status == 0) { outs() << ResultBuf << "\n"; outs().flush(); if (WarnTrailing && NRead < S.size()) @@ -87,7 +87,7 @@ WithColor::error() << "Invalid mangled name\n"; } std::free(ResultBuf); - return Status == llvm::demangle_success; + return Status == 0; } int main(int argc, char **argv) { diff --git a/llvm/unittests/Demangle/DemangleTest.cpp b/llvm/unittests/Demangle/DemangleTest.cpp --- a/llvm/unittests/Demangle/DemangleTest.cpp +++ b/llvm/unittests/Demangle/DemangleTest.cpp @@ -8,6 +8,7 @@ #include "llvm/Demangle/Demangle.h" #include "gmock/gmock.h" +#include using namespace llvm; @@ -30,3 +31,19 @@ EXPECT_EQ(demangle("_Z3fooILi79EEbU7_ExtIntIXT_EEi"), "bool foo<79>(int _ExtInt<79>)"); } + +TEST(Demangle, demangleWithError) { + std::error_code E; + EXPECT_TRUE(itaniumDemangle("_Z3fooi", E)); + EXPECT_TRUE(E == DemangleError::Success); + + // A string that shouldn't be handled by this demangler + // should return InvaildFormat + EXPECT_FALSE(itaniumDemangle("_", E)); + EXPECT_TRUE(E == DemangleError::InvalidFormat); + + // A string that should be handled by this demangler + // but is broken should return InvalidMangledNamed + EXPECT_FALSE(itaniumDemangle("_Z3fooBroken@Y", E)); + EXPECT_TRUE(E == DemangleError::InvalidMangledName); +} diff --git a/llvm/unittests/Demangle/ItaniumDemangleTest.cpp b/llvm/unittests/Demangle/ItaniumDemangleTest.cpp --- a/llvm/unittests/Demangle/ItaniumDemangleTest.cpp +++ b/llvm/unittests/Demangle/ItaniumDemangleTest.cpp @@ -78,7 +78,8 @@ }; TestParser Parser("_Z1fIiEjl"); - ASSERT_NE(nullptr, Parser.parse()); + std::error_code E; + ASSERT_NE(nullptr, Parser.parse(E)); EXPECT_THAT(Parser.Types, testing::ElementsAre('i', 'j', 'l')); } @@ -110,6 +111,7 @@ // void f(A<_Float16>, _Float16); TestParser Parser("_Z1f1AIDF16_EDF16_"); - ASSERT_NE(nullptr, Parser.parse()); + std::error_code E; + ASSERT_NE(nullptr, Parser.parse(E)); EXPECT_THAT(Parser.Types, testing::ElementsAre("_Float16", "A", "_Float16")); }