Index: include/llvm/Demangle/ItaniumDemangle.h =================================================================== --- include/llvm/Demangle/ItaniumDemangle.h +++ include/llvm/Demangle/ItaniumDemangle.h @@ -2372,7 +2372,10 @@ if (consumeIf('s')) { First = parse_discriminator(First, Last); - return make(Encoding, make("string literal")); + auto *StringLitName = make("string literal"); + if (!StringLitName) + return nullptr; + return make(Encoding, StringLitName); } if (consumeIf('d')) { @@ -2850,6 +2853,7 @@ if (SoFar) SoFar = make(SoFar, Comp); else SoFar = Comp; if (State) State->EndsWithTemplateArgs = false; + return SoFar != nullptr; }; if (consumeIf("St")) @@ -2870,7 +2874,8 @@ Node *TP = parseTemplateParam(); if (TP == nullptr) return nullptr; - PushComponent(TP); + if (!PushComponent(TP)) + return nullptr; Subs.push_back(SoFar); continue; } @@ -2891,7 +2896,8 @@ Node *DT = parseDecltype(); if (DT == nullptr) return nullptr; - PushComponent(DT); + if (!PushComponent(DT)) + return nullptr; Subs.push_back(SoFar); continue; } @@ -2901,7 +2907,8 @@ Node *S = parseSubstitution(); if (S == nullptr) return nullptr; - PushComponent(S); + if (!PushComponent(S)) + return nullptr; if (SoFar != S) Subs.push_back(S); continue; @@ -2914,7 +2921,8 @@ Node *CtorDtor = parseCtorDtorName(SoFar, State); if (CtorDtor == nullptr) return nullptr; - PushComponent(CtorDtor); + if (!PushComponent(CtorDtor)) + return nullptr; SoFar = parseAbiTags(SoFar); if (SoFar == nullptr) return nullptr; @@ -2926,7 +2934,8 @@ Node *N = parseUnqualifiedName(State); if (N == nullptr) return nullptr; - PushComponent(N); + if (!PushComponent(N)) + return nullptr; Subs.push_back(SoFar); } @@ -3039,6 +3048,8 @@ if (TA == nullptr) return nullptr; SoFar = make(SoFar, TA); + if (!SoFar) + return nullptr; } while (!consumeIf('E')) { @@ -3046,6 +3057,8 @@ if (Qual == nullptr) return nullptr; SoFar = make(SoFar, Qual); + if (!SoFar) + return nullptr; } Node *Base = parseBaseUnresolvedName(); @@ -3078,6 +3091,8 @@ SoFar = make(Qual); else SoFar = Qual; + if (!SoFar) + return nullptr; } while (!consumeIf('E')); } // sr @@ -3092,6 +3107,8 @@ if (TA == nullptr) return nullptr; SoFar = make(SoFar, TA); + if (!SoFar) + return nullptr; } } @@ -3111,6 +3128,8 @@ if (SN.empty()) return nullptr; N = make(N, SN); + if (!N) + return nullptr; } return N; } @@ -3163,11 +3182,15 @@ Node *ExceptionSpec = nullptr; if (consumeIf("Do")) { ExceptionSpec = make("noexcept"); + if (!ExceptionSpec) + return nullptr; } else if (consumeIf("DO")) { Node *E = parseExpr(); if (E == nullptr || !consumeIf('E')) return nullptr; ExceptionSpec = make(E); + if (!ExceptionSpec) + return nullptr; } else if (consumeIf("Dw")) { size_t SpecsBegin = Names.size(); while (!consumeIf('E')) { @@ -3178,6 +3201,8 @@ } ExceptionSpec = make(popTrailingNodeArray(SpecsBegin)); + if (!ExceptionSpec) + return nullptr; } consumeIf("Dx"); // transaction safe @@ -4517,9 +4542,10 @@ return nullptr; Names.push_back(Arg); } - return make( - "sizeof... (", make(popTrailingNodeArray(ArgsBegin)), - ")"); + auto *Pack = make(popTrailingNodeArray(ArgsBegin)); + if (!Pack) + return nullptr; + return make("sizeof... (", Pack, ")"); } } return nullptr; @@ -4915,6 +4941,8 @@ default: return nullptr; } + if (!SpecialSub) + return nullptr; // Itanium C++ ABI 5.1.2: If a name that would use a built-in // has ABI tags, the tags are appended to the substitution; the result is a // substitutable component. @@ -4968,6 +4996,8 @@ // operator types), then we should only look it up in the right context. if (PermitForwardTemplateReferences) { Node *ForwardRef = make(Index); + if (!ForwardRef) + return nullptr; assert(ForwardRef->getKind() == Node::KForwardTemplateReference); ForwardTemplateRefs.push_back( static_cast(ForwardRef)); @@ -5047,6 +5077,8 @@ if (Arg->getKind() == Node::KTemplateArgumentPack) { TableEntry = make( static_cast(TableEntry)->getElements()); + if (!TableEntry) + return nullptr; } TemplateParams.push_back(TableEntry); } else { Index: include/llvm/Support/ItaniumManglingCanonicalizer.h =================================================================== --- include/llvm/Support/ItaniumManglingCanonicalizer.h +++ include/llvm/Support/ItaniumManglingCanonicalizer.h @@ -76,8 +76,14 @@ /// /// Returns Key() if (and only if) the mangling is not a valid Itanium C++ /// ABI mangling. + /// + /// The string denoted by Mangling must live as long as the canonicalizer. Key canonicalize(StringRef Mangling); + /// Find a canonical key for the specified mangling, if one has already been + /// formed. Otherwise returns Key(). + Key lookup(StringRef Mangling); + private: struct Impl; Impl *P; Index: lib/Support/ItaniumManglingCanonicalizer.cpp =================================================================== --- lib/Support/ItaniumManglingCanonicalizer.cpp +++ lib/Support/ItaniumManglingCanonicalizer.cpp @@ -105,7 +105,7 @@ void reset() {} template - std::pair getOrCreateNode(Args &&...As) { + std::pair getOrCreateNode(bool CreateNewNodes, Args &&...As) { llvm::FoldingSetNodeID ID; profileCtor(ID, NodeKind::Kind, As...); @@ -113,6 +113,9 @@ if (NodeHeader *Existing = Nodes.FindNodeOrInsertPos(ID, InsertPos)) return {static_cast(Existing->getNode()), false}; + if (!CreateNewNodes) + return {nullptr, true}; + static_assert(alignof(T) <= alignof(NodeHeader), "underaligned node header for specific node kind"); void *Storage = @@ -125,7 +128,7 @@ template Node *makeNode(Args &&...As) { - return getOrCreateNode(std::forward(As)...).first; + return getOrCreateNode(true, std::forward(As)...).first; } void *allocateNodeArray(size_t sz) { @@ -138,7 +141,8 @@ // of creation. template<> std::pair -FoldingNodeAllocator::getOrCreateNode(size_t &Index) { +FoldingNodeAllocator::getOrCreateNode(bool, + size_t &Index) { return {new (RawAlloc.Allocate(sizeof(ForwardTemplateReference), alignof(ForwardTemplateReference))) ForwardTemplateReference(Index), @@ -149,15 +153,16 @@ Node *MostRecentlyCreated = nullptr; Node *TrackedNode = nullptr; bool TrackedNodeIsUsed = false; + bool CreateNewNodes = true; llvm::SmallDenseMap Remappings; template Node *makeNodeSimple(Args &&...As) { std::pair Result = - getOrCreateNode(std::forward(As)...); + getOrCreateNode(CreateNewNodes, std::forward(As)...); if (Result.second) { // Node is new. Make a note of that. MostRecentlyCreated = Result.first; - } else { + } else if (Result.first) { // Node is pre-existing; check if it's in our remapping table. if (auto *N = Remappings.lookup(Result.first)) { Result.first = N; @@ -185,6 +190,8 @@ void reset() { MostRecentlyCreated = nullptr; } + void setCreateNewNodes(bool CNN) { CreateNewNodes = CNN; } + void addRemapping(Node *A, Node *B) { // Note, we don't need to check whether B is also remapped, because if it // was we would have already remapped it when building it. @@ -230,6 +237,7 @@ ItaniumManglingCanonicalizer::addEquivalence(FragmentKind Kind, StringRef First, StringRef Second) { auto &Alloc = P->Demangler.ASTAllocator; + Alloc.setCreateNewNodes(true); auto Parse = [&](StringRef Str) { P->Demangler.reset(Str.begin(), Str.end()); @@ -298,6 +306,14 @@ ItaniumManglingCanonicalizer::Key ItaniumManglingCanonicalizer::canonicalize(StringRef Mangling) { + P->Demangler.ASTAllocator.setCreateNewNodes(true); + P->Demangler.reset(Mangling.begin(), Mangling.end()); + return reinterpret_cast(P->Demangler.parse()); +} + +ItaniumManglingCanonicalizer::Key +ItaniumManglingCanonicalizer::lookup(StringRef Mangling) { + P->Demangler.ASTAllocator.setCreateNewNodes(false); P->Demangler.reset(Mangling.begin(), Mangling.end()); return reinterpret_cast(P->Demangler.parse()); } Index: unittests/Support/ItaniumManglingCanonicalizerTest.cpp =================================================================== --- unittests/Support/ItaniumManglingCanonicalizerTest.cpp +++ unittests/Support/ItaniumManglingCanonicalizerTest.cpp @@ -7,10 +7,13 @@ // //===----------------------------------------------------------------------===// -#include #include "llvm/Support/ItaniumManglingCanonicalizer.h" + #include "gtest/gtest.h" +#include +#include + using EquivalenceError = llvm::ItaniumManglingCanonicalizer::EquivalenceError; using FragmentKind = llvm::ItaniumManglingCanonicalizer::FragmentKind; @@ -214,7 +217,8 @@ }, }; -TEST(ItaniumManglingCanonicalizerTest, TestTestcases) { +template +static void testTestcases() { for (const auto &Testcase : Testcases) { llvm::ItaniumManglingCanonicalizer Canonicalizer; for (const auto &Equiv : Testcase.Equivalences) { @@ -226,11 +230,21 @@ } using CanonKey = llvm::ItaniumManglingCanonicalizer::Key; + + std::map Keys; + if (CanonicalizeFirst) + for (const auto &Class : Testcase.Classes) + Keys.insert({&Class, Canonicalizer.canonicalize(*Class.begin())}); + std::map Found; for (const auto &Class : Testcase.Classes) { - CanonKey ClassKey = {}; + CanonKey ClassKey = Keys[&Class]; for (llvm::StringRef Str : Class) { - CanonKey ThisKey = Canonicalizer.canonicalize(Str); + // Force a copy to be made when calling lookup to test that it doesn't + // retain any part of the provided string. + CanonKey ThisKey = CanonicalizeFirst + ? Canonicalizer.lookup(std::string(Str)) + : Canonicalizer.canonicalize(Str); EXPECT_NE(ThisKey, CanonKey()) << "couldn't canonicalize " << Str; if (ClassKey) { EXPECT_EQ(ThisKey, ClassKey) @@ -245,6 +259,14 @@ } } +TEST(ItaniumManglingCanonicalizerTest, TestCanonicalize) { + testTestcases(); +} + +TEST(ItaniumManglingCanonicalizerTest, TestLookup) { + testTestcases(); +} + TEST(ItaniumManglingCanonicalizerTest, TestInvalidManglings) { llvm::ItaniumManglingCanonicalizer Canonicalizer; EXPECT_EQ(Canonicalizer.addEquivalence(FragmentKind::Type, "", "1X"),