From 480a5672b046ef0017af8bf59b6284895c22123d Mon Sep 17 00:00:00 2001 From: amai2012 Date: Wed, 1 Jul 2015 00:04:01 +0200 Subject: [PATCH] #6298 stack overflow in Scope::findFunctionInBase (endless recursion). Fix handling of circular class hierarchy --- lib/symboldatabase.cpp | 22 ++++++++++++++++++++-- lib/symboldatabase.h | 9 ++++++++- test/testclass.cpp | 4 ++-- test/testsymboldatabase.cpp | 16 ++++++++++++++++ test/testunusedprivfunc.cpp | 2 +- 5 files changed, 47 insertions(+), 6 deletions(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 03378b056..bd5b17a57 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -844,8 +844,16 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti // fill in base class info for (std::list::iterator it = typeList.begin(); it != typeList.end(); ++it) { // finish filling in base class info - for (unsigned int i = 0; i < it->derivedFrom.size(); ++i) - it->derivedFrom[i].type = findType(it->derivedFrom[i].nameTok, it->enclosingScope); + for (unsigned int i = 0; i < it->derivedFrom.size(); ++i) { + const Type* found = findType(it->derivedFrom[i].nameTok, it->enclosingScope); + if (found && found->findDependency(&(*it))) { + // circular dependency + //_tokenizer->syntaxError(nullptr); + } + else { + it->derivedFrom[i].type = found; + } + } } // fill in friend info @@ -2054,6 +2062,16 @@ bool Type::hasCircularDependencies(std::set* anchestors) const return false; } +bool Type::findDependency(const Type* anchestor) const { + if (this==anchestor) + return true; + for (std::vector::const_iterator parent=derivedFrom.begin(); parent!=derivedFrom.end(); ++parent) { + if (parent->type && parent->type->findDependency(anchestor)) + return true; + } + return false; +} + bool Variable::arrayDimensions(const Library* lib) { const Library::Container* container = lib->detectContainer(_start); diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index 91516f2c2..4152e953d 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -122,7 +122,14 @@ public: * @param anchestors list of anchestors. For internal usage only, clients should not supply this argument. * @return true if there is a circular dependency */ - bool hasCircularDependencies(std::set* anchestors = 0) const; + bool hasCircularDependencies(std::set* anchestors = nullptr) const; + + /** + * Check for dependency + * @param anchestor potential anchestor + * @return true if there is a dependency + */ + bool findDependency(const Type* anchestor) const; }; /** @brief Information about a member variable. */ diff --git a/test/testclass.cpp b/test/testclass.cpp index 0f6d7896c..88989709e 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -4929,14 +4929,14 @@ private: "int MixerParticipant::GetAudioFrame() {\n" " return 0;\n" "}"); - ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:2]: (performance, inconclusive) Technically the member function 'MixerParticipant::GetAudioFrame' can be static.\n", errout.str()); + ASSERT_EQUALS("", errout.str()); checkConst("class MixerParticipant : public MixerParticipant {\n" " bool InitializeFileReader() {\n" " printf(\"music\");\n" " }\n" "};"); - ASSERT_EQUALS("[test.cpp:2]: (performance, inconclusive) Technically the member function 'MixerParticipant::InitializeFileReader' can be static.\n", errout.str()); + ASSERT_EQUALS("", errout.str()); // Based on an example from SVN source code causing an endless recursion within CheckClass::isConstMemberFunc() // A more complete example including a template declaration like diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index cea84d455..9662261df 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -260,6 +260,7 @@ private: TEST_CASE(functionPrototype); // ticket #5867 TEST_CASE(lambda); // ticket #5867 + TEST_CASE(circularDependencies); // 6298 } void array() const { @@ -2914,6 +2915,21 @@ private: ASSERT_EQUALS(Scope::eLambda, scope->type); } } + // #6298 "stack overflow in Scope::findFunctionInBase (endless recursion)" + void circularDependencies() { + check("template class E,class D> class C : E {\n" + " public:\n" + " int f();\n" + "};\n" + "class E : C {\n" + " public:\n" + " int f() { return C< ::D,int>::f(); }\n" + "};\n" + "int main() {\n" + " E c;\n" + " c.f();\n" + "}"); + } }; REGISTER_TEST(TestSymbolDatabase) diff --git a/test/testunusedprivfunc.cpp b/test/testunusedprivfunc.cpp index 60205e2aa..f5d345f7b 100644 --- a/test/testunusedprivfunc.cpp +++ b/test/testunusedprivfunc.cpp @@ -722,7 +722,7 @@ private: " C a;\n" "}"); - ASSERT_EQUALS("[test.cpp:10]: (style) Unused private function: 'InfiniteA::foo'\n", errout.str()); + ASSERT_EQUALS("", errout.str()); } void staticVariable() {