This revision was automatically updated to reflect the committed changes. Closed by commit rG73f05841992c: msabi: Fix exponential mangling time for certain pathological inputs (authored by thakis). Herald added a project: clang.
Changed prior to commit: https://reviews.llvm.org/D62746?vs=202472&id=202542#toc Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D62746/new/ https://reviews.llvm.org/D62746 Files: clang/lib/AST/MicrosoftMangle.cpp clang/test/CodeGenCXX/mangle-ms-back-references-pr13207.cpp
Index: clang/test/CodeGenCXX/mangle-ms-back-references-pr13207.cpp =================================================================== --- clang/test/CodeGenCXX/mangle-ms-back-references-pr13207.cpp +++ clang/test/CodeGenCXX/mangle-ms-back-references-pr13207.cpp @@ -191,3 +191,44 @@ // CHECK: "??$fun_tmpl_recurse@H$1??$fun_tmpl_recurse@H$1?ident@fn_space@@YA?AURetVal@2@H@Z@fn_space@@YA?AURetVal@1@H@Z@fn_space@@YA?AURetVal@0@H@Z" // CHECK: "??$fun_tmpl_recurse@H$1?ident@fn_space@@YA?AURetVal@2@H@Z@fn_space@@YA?AURetVal@0@H@Z" } + + +template <class T1, class T2, class T3, class T4, class T5, class T6, class T7, + class T8, class T9, class T10> +struct Fooob {}; + +using A0 = Fooob<int, int, int, int, int, int, int, int, int, int>; +using A1 = Fooob<A0, A0, A0, A0, A0, A0, A0, A0, A0, A0>; +using A2 = Fooob<A1, A1, A1, A1, A1, A1, A1, A1, A1, A1>; +using A3 = Fooob<A2, A2, A2, A2, A2, A2, A2, A2, A2, A2>; +using A4 = Fooob<A3, A3, A3, A3, A3, A3, A3, A3, A3, A3>; +using A5 = Fooob<A4, A4, A4, A4, A4, A4, A4, A4, A4, A4>; +using A6 = Fooob<A5, A5, A5, A5, A5, A5, A5, A5, A5, A5>; +using A7 = Fooob<A6, A6, A6, A6, A6, A6, A6, A6, A6, A6>; +using A8 = Fooob<A7, A7, A7, A7, A7, A7, A7, A7, A7, A7>; +using A9 = Fooob<A8, A8, A8, A8, A8, A8, A8, A8, A8, A8>; +using A10 = Fooob<A9, A9, A9, A9, A9, A9, A9, A9, A9, A9>; + +// This should take milliseconds, not minutes. +void f(A9 a) {} +// CHECK: "?f@@YAXU?$Fooob@U?$Fooob@U?$Fooob@U?$Fooob@U?$Fooob@U?$Fooob@U?$Fooob@U?$Fooob@U?$Fooob@U?$Fooob@HHHHHHHHHH@@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@@Z" + + +template <class T1, class T2, class T3, class T4, class T5, class T6, class T7, + class T8, class T9, class T10, class T11, class T12, class T13, + class T14, class T15, class T16, class T17, class T18, class T19, + class T20> +struct Food {}; + +using B0 = Food<int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int>; +using B1 = Food<B0, B0, B0, B0, B0, B0, B0, B0, B0, B0, B0, B0, B0, B0, B0, B0, B0, B0, B0, B0>; +using B2 = Food<B1, B0, B0, B0, B0, B0, B0, B0, B0, B0, B1, B1, B1, B1, B1, B1, B1, B1, B1, B1>; +using B3 = Food<B2, B1, B0, B0, B0, B0, B0, B0, B0, B0, B2, B2, B2, B2, B2, B2, B2, B2, B2, B2>; +using B4 = Food<B3, B2, B1, B0, B0, B0, B0, B0, B0, B0, B3, B3, B3, B3, B3, B3, B3, B3, B3, B3>; +using B5 = Food<B4, B3, B2, B1, B0, B0, B0, B0, B0, B0, B4, B4, B4, B4, B4, B4, B4, B4, B4, B4>; +using B6 = Food<B5, B4, B3, B2, B1, B0, B0, B0, B0, B0, B5, B5, B5, B5, B5, B5, B5, B5, B5, B5>; + +// This too should take milliseconds, not minutes. +void f(B6 a) {} + +// CHECK: "?f@@YAXU?$Food@U?$Food@U?$Food@U?$Food@U?$Food@U?$Food@U?$Food@HHHHHHHHHHHHHHHHHHHH@@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U?$Food@HHHHHHHHHHHHHHHHHHHH@@U2@U2@U2@U2@U2@U2@U2@U2@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U?$Food@U?$Food@HHHHHHHHHHHHHHHHHHHH@@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U?$Food@HHHHHHHHHHHHHHHHHHHH@@U3@U3@U3@U3@U3@U3@U3@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U?$Food@U?$Food@U?$Food@HHHHHHHHHHHHHHHHHHHH@@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U?$Food@HHHHHHHHHHHHHHHHHHHH@@U2@U2@U2@U2@U2@U2@U2@U2@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U?$Food@U?$Food@HHHHHHHHHHHHHHHHHHHH@@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U?$Food@HHHHHHHHHHHHHHHHHHHH@@U4@U4@U4@U4@U4@U4@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U?$Food@U?$Food@U?$Food@U?$Food@HHHHHHHHHHHHHHHHHHHH@@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U?$Food@HHHHHHHHHHHHHHHHHHHH@@U2@U2@U2@U2@U2@U2@U2@U2@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U?$Food@U?$Food@HHHHHHHHHHHHHHHHHHHH@@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U?$Food@HHHHHHHHHHHHHHHHHHHH@@U3@U3@U3@U3@U3@U3@U3@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U?$Food@U?$Food@U?$Food@HHHHHHHHHHHHHHHHHHHH@@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U?$Food@HHHHHHHHHHHHHHHHHHHH@@U2@U2@U2@U2@U2@U2@U2@U2@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U?$Food@U?$Food@HHHHHHHHHHHHHHHHHHHH@@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U?$Food@HHHHHHHHHHHHHHHHHHHH@@U5@U5@U5@U5@U5@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U?$Food@U?$Food@U?$Food@U?$Food@U?$Food@HHHHHHHHHHHHHHHHHHHH@@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U?$Food@HHHHHHHHHHHHHHHHHHHH@@U2@U2@U2@U2@U2@U2@U2@U2@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U?$Food@U?$Food@HHHHHHHHHHHHHHHHHHHH@@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U?$Food@HHHHHHHHHHHHHHHHHHHH@@U3@U3@U3@U3@U3@U3@U3@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U?$Food@U?$Food@U?$Food@HHHHHHHHHHHHHHHHHHHH@@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U?$Food@HHHHHHHHHHHHHHHHHHHH@@U2@U2@U2@U2@U2@U2@U2@U2@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U?$Food@U?$Food@HHHHHHHHHHHHHHHHHHHH@@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U?$Food@HHHHHHHHHHHHHHHHHHHH@@U4@U4@U4@U4@U4@U4@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U?$Food@U?$Food@U?$Food@U?$Food@HHHHHHHHHHHHHHHHHHHH@@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U?$Food@HHHHHHHHHHHHHHHHHHHH@@U2@U2@U2@U2@U2@U2@U2@U2@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U?$Food@U?$Food@HHHHHHHHHHHHHHHHHHHH@@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U?$Food@HHHHHHHHHHHHHHHHHHHH@@U3@U3@U3@U3@U3@U3@U3@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U?$Food@U?$Food@U?$Food@HHHHHHHHHHHHHHHHHHHH@@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U?$Food@HHHHHHHHHHHHHHHHHHHH@@U2@U2@U2@U2@U2@U2@U2@U2@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U?$Food@U?$Food@HHHHHHHHHHHHHHHHHHHH@@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@U?$Food@HHHHHHHHHHHHHHHHHHHH@@U6@U6@U6@U6@U1@U1@U1@U1@U1@U1@U1@U1@U1@U1@@@@Z" Index: clang/lib/AST/MicrosoftMangle.cpp =================================================================== --- clang/lib/AST/MicrosoftMangle.cpp +++ clang/lib/AST/MicrosoftMangle.cpp @@ -265,7 +265,8 @@ BackRefVec NameBackReferences; typedef llvm::DenseMap<const void *, unsigned> ArgBackRefMap; - ArgBackRefMap TypeBackReferences; + ArgBackRefMap FunArgBackReferences; + ArgBackRefMap TemplateArgBackReferences; typedef std::set<std::pair<int, bool>> PassObjectSizeArgsSet; PassObjectSizeArgsSet PassObjectSizeArgs; @@ -343,7 +344,7 @@ const TemplateArgumentList &TemplateArgs); void mangleObjCMethodName(const ObjCMethodDecl *MD); - void mangleArgumentType(QualType T, SourceRange Range); + void mangleFunctionArgumentType(QualType T, SourceRange Range); void manglePassObjectSizeArg(const PassObjectSizeAttr *POSA); bool isArtificialTagType(QualType T) const; @@ -793,7 +794,7 @@ // the X<Y> part is aliased. However, if you need to mangle // void foo(A::X<A::Y>, A::X<B::Y>), // the A::X<> part is not aliased. - // That said, from the mangler's perspective we have a structure like this: + // That is, from the mangler's perspective we have a structure like this: // namespace[s] -> type[ -> template-parameters] // but from the Clang perspective we have // type [ -> template-parameters] @@ -803,12 +804,30 @@ // the mangled type name as a key to check the mangling of different types // for aliasing. - llvm::SmallString<64> TemplateMangling; - llvm::raw_svector_ostream Stream(TemplateMangling); - MicrosoftCXXNameMangler Extra(Context, Stream); - Extra.mangleTemplateInstantiationName(TD, *TemplateArgs); - - mangleSourceName(TemplateMangling); + // It's important to key cache reads off ND, not TD -- the same TD can + // be used with different TemplateArgs, but ND uniquely identifies + // TD / TemplateArg pairs. + ArgBackRefMap::iterator Found = TemplateArgBackReferences.find(ND); + if (Found == TemplateArgBackReferences.end()) { + // Mangle full template name into temporary buffer. + llvm::SmallString<64> TemplateMangling; + llvm::raw_svector_ostream Stream(TemplateMangling); + MicrosoftCXXNameMangler Extra(Context, Stream); + Extra.mangleTemplateInstantiationName(TD, *TemplateArgs); + + // Use the string backref vector to possibly get a back reference. + mangleSourceName(TemplateMangling); + + // Memoize back reference for this type. + BackRefVec::iterator StringFound = + llvm::find(NameBackReferences, TemplateMangling); + if (StringFound != NameBackReferences.end()) { + TemplateArgBackReferences[ND] = + StringFound - NameBackReferences.begin(); + } + } else { + Out << Found->second; + } return; } @@ -1282,11 +1301,13 @@ // Always start with the unqualified name. // Templates have their own context for back references. - ArgBackRefMap OuterArgsContext; + ArgBackRefMap OuterFunArgsContext; + ArgBackRefMap OuterTemplateArgsContext; BackRefVec OuterTemplateContext; PassObjectSizeArgsSet OuterPassObjectSizeArgs; NameBackReferences.swap(OuterTemplateContext); - TypeBackReferences.swap(OuterArgsContext); + FunArgBackReferences.swap(OuterFunArgsContext); + TemplateArgBackReferences.swap(OuterTemplateArgsContext); PassObjectSizeArgs.swap(OuterPassObjectSizeArgs); mangleUnscopedTemplateName(TD); @@ -1294,7 +1315,8 @@ // Restore the previous back reference contexts. NameBackReferences.swap(OuterTemplateContext); - TypeBackReferences.swap(OuterArgsContext); + FunArgBackReferences.swap(OuterFunArgsContext); + TemplateArgBackReferences.swap(OuterTemplateArgsContext); PassObjectSizeArgs.swap(OuterPassObjectSizeArgs); } @@ -1699,8 +1721,8 @@ } } -void MicrosoftCXXNameMangler::mangleArgumentType(QualType T, - SourceRange Range) { +void MicrosoftCXXNameMangler::mangleFunctionArgumentType(QualType T, + SourceRange Range) { // MSVC will backreference two canonically equivalent types that have slightly // different manglings when mangled alone. @@ -1730,9 +1752,9 @@ TypePtr = T.getCanonicalType().getAsOpaquePtr(); } - ArgBackRefMap::iterator Found = TypeBackReferences.find(TypePtr); + ArgBackRefMap::iterator Found = FunArgBackReferences.find(TypePtr); - if (Found == TypeBackReferences.end()) { + if (Found == FunArgBackReferences.end()) { size_t OutSizeBefore = Out.tell(); mangleType(T, Range, QMM_Drop); @@ -1741,9 +1763,9 @@ // Only types longer than 1 character are considered // and only 10 back references slots are available: bool LongerThanOneChar = (Out.tell() - OutSizeBefore > 1); - if (LongerThanOneChar && TypeBackReferences.size() < 10) { - size_t Size = TypeBackReferences.size(); - TypeBackReferences[TypePtr] = Size; + if (LongerThanOneChar && FunArgBackReferences.size() < 10) { + size_t Size = FunArgBackReferences.size(); + FunArgBackReferences[TypePtr] = Size; } } else { Out << Found->second; @@ -1757,16 +1779,16 @@ auto Iter = PassObjectSizeArgs.insert({Type, Dynamic}).first; auto *TypePtr = (const void *)&*Iter; - ArgBackRefMap::iterator Found = TypeBackReferences.find(TypePtr); + ArgBackRefMap::iterator Found = FunArgBackReferences.find(TypePtr); - if (Found == TypeBackReferences.end()) { + if (Found == FunArgBackReferences.end()) { std::string Name = Dynamic ? "__pass_dynamic_object_size" : "__pass_object_size"; mangleArtificialTagType(TTK_Enum, Name + llvm::utostr(Type), {"__clang"}); - if (TypeBackReferences.size() < 10) { - size_t Size = TypeBackReferences.size(); - TypeBackReferences[TypePtr] = Size; + if (FunArgBackReferences.size() < 10) { + size_t Size = FunArgBackReferences.size(); + FunArgBackReferences[TypePtr] = Size; } } else { Out << Found->second; @@ -2192,12 +2214,12 @@ Out << 'X'; } else if (StructorType == Ctor_CopyingClosure) { // Copy constructor closure always takes an unqualified reference. - mangleArgumentType(getASTContext().getLValueReferenceType( - Proto->getParamType(0) - ->getAs<LValueReferenceType>() - ->getPointeeType(), - /*SpelledAsLValue=*/true), - Range); + mangleFunctionArgumentType(getASTContext().getLValueReferenceType( + Proto->getParamType(0) + ->getAs<LValueReferenceType>() + ->getPointeeType(), + /*SpelledAsLValue=*/true), + Range); Out << '@'; } else { llvm_unreachable("unexpected constructor closure!"); @@ -2239,7 +2261,7 @@ } else { // Happens for function pointer type arguments for example. for (unsigned I = 0, E = Proto->getNumParams(); I != E; ++I) { - mangleArgumentType(Proto->getParamType(I), Range); + mangleFunctionArgumentType(Proto->getParamType(I), Range); // Mangle each pass_object_size parameter as if it's a parameter of enum // type passed directly after the parameter with the pass_object_size // attribute. The aforementioned enum's name is __pass_object_size, and we @@ -2731,10 +2753,12 @@ if (T->qual_empty() && !T->isSpecialized()) return mangleType(T->getBaseType(), Range, QMM_Drop); - ArgBackRefMap OuterArgsContext; + ArgBackRefMap OuterFunArgsContext; + ArgBackRefMap OuterTemplateArgsContext; BackRefVec OuterTemplateContext; - TypeBackReferences.swap(OuterArgsContext); + FunArgBackReferences.swap(OuterFunArgsContext); + TemplateArgBackReferences.swap(OuterTemplateArgsContext); NameBackReferences.swap(OuterTemplateContext); mangleTagTypeKind(TTK_Struct); @@ -2758,7 +2782,8 @@ Out << '@'; - TypeBackReferences.swap(OuterArgsContext); + FunArgBackReferences.swap(OuterFunArgsContext); + TemplateArgBackReferences.swap(OuterTemplateArgsContext); NameBackReferences.swap(OuterTemplateContext); }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits