From 0bcddcd0140f9daf54ba0b74b4afc3736c225fe0 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Wed, 11 Nov 2015 23:13:19 +0200 Subject: [PATCH] C++: Limit template instantiation depth A recursive template generates infinite expansions. Consider the following example: template struct Base { }; template struct Derived : Base< typename Derived::type>::type, typename Derived::type>::type >::type {}; R is instantiated as Base::type, which causes another instantiation of R into Base> etc... This is not a solution, but a workaround. Task-number: QTCREATORBUG-15141 Change-Id: Ib04f70275e07919e2cb6c7fb61a2045bd52f4a7d Reviewed-by: Nikolai Kosjar --- src/libs/cplusplus/LookupContext.cpp | 6 ++++++ src/libs/cplusplus/LookupContext.h | 1 + .../checksymbols/tst_checksymbols.cpp | 21 +++++++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/src/libs/cplusplus/LookupContext.cpp b/src/libs/cplusplus/LookupContext.cpp index 0364b59c725..401d54f48b3 100644 --- a/src/libs/cplusplus/LookupContext.cpp +++ b/src/libs/cplusplus/LookupContext.cpp @@ -1549,6 +1549,7 @@ CreateBindings::CreateBindings(Document::Ptr thisDocument, const Snapshot &snaps : _snapshot(snapshot) , _control(QSharedPointer(new Control)) , _expandTemplates(false) + , _depth(0) { _globalNamespace = allocLookupScope(/*parent = */ 0, /*name = */ 0); _currentLookupScope = _globalNamespace; @@ -1978,8 +1979,13 @@ void CreateBindings::initializeSubst(Clone &cloner, { const unsigned argumentCountOfSpecialization = specialization->templateParameterCount(); + if (_depth > 15) + return; + + ++_depth; for (unsigned i = 0; i < argumentCountOfSpecialization; ++i) resolveTemplateArgument(cloner, subst, origin, specialization, instantiation, i); + --_depth; } } // namespace CPlusPlus diff --git a/src/libs/cplusplus/LookupContext.h b/src/libs/cplusplus/LookupContext.h index 8d4016dbbbb..8410c9000b7 100644 --- a/src/libs/cplusplus/LookupContext.h +++ b/src/libs/cplusplus/LookupContext.h @@ -209,6 +209,7 @@ private: LookupScope *_globalNamespace; LookupScope *_currentLookupScope; bool _expandTemplates; + int _depth; }; class CPLUSPLUS_EXPORT LookupContext diff --git a/tests/auto/cplusplus/checksymbols/tst_checksymbols.cpp b/tests/auto/cplusplus/checksymbols/tst_checksymbols.cpp index a04cdd16658..3b16861c8b1 100644 --- a/tests/auto/cplusplus/checksymbols/tst_checksymbols.cpp +++ b/tests/auto/cplusplus/checksymbols/tst_checksymbols.cpp @@ -225,6 +225,8 @@ private slots: void test_checksymbols_infiniteLoop_data(); void test_checksymbols_infiniteLoop(); + void test_checksymbols_infiniteLoop_BUG15141(); + void test_parentOfBlock(); void findField(); @@ -1122,6 +1124,25 @@ void tst_CheckSymbols::test_checksymbols_infiniteLoop() TestCase::runCheckSymbols(document1, snapshot); } +void tst_CheckSymbols::test_checksymbols_infiniteLoop_BUG15141() +{ + QByteArray source = + "template \n" + "struct Base\n" + "{\n" + "};\n" + "\n" + "template\n" + "struct Derived :\n" + " Base<\n" + " typename Derived::type>::type,\n" + " typename Derived::type>::type\n" + " >::type\n" + "{};\n"; + + BaseTestCase tc(source); +} + void tst_CheckSymbols::test_parentOfBlock() { const QByteArray source = "void C::f()\n"