In case of a loop within the class hierarchie Function::isImplicitlyVirtual_rec() was entering an endless loop. Tracking the previously analyzed types shall prevent this.

This commit is contained in:
Alexander Mai 2014-03-22 08:49:28 +01:00
parent 1df5ccf315
commit 37befc75ef
4 changed files with 57 additions and 5 deletions

View File

@ -2029,7 +2029,7 @@ bool Function::isImplicitlyVirtual(bool defaultVal) const
return false; return false;
} }
bool Function::isImplicitlyVirtual_rec(const ::Type* baseType, bool& safe) const bool Function::isImplicitlyVirtual_rec(const ::Type* baseType, bool& safe, std::deque< const ::Type* > *anchestors) const
{ {
// check each base class // check each base class
for (std::size_t i = 0; i < baseType->derivedFrom.size(); ++i) { for (std::size_t i = 0; i < baseType->derivedFrom.size(); ++i) {
@ -2065,9 +2065,19 @@ bool Function::isImplicitlyVirtual_rec(const ::Type* baseType, bool& safe) const
} }
if (!baseType->derivedFrom[i].type->derivedFrom.empty()) { if (!baseType->derivedFrom[i].type->derivedFrom.empty()) {
// avoid endless recursion, see #5289 Crash: Stack overflow in isImplicitlyVirtual_rec when checking SVN // avoid endless recursion, see #5289 Crash: Stack overflow in isImplicitlyVirtual_rec when checking SVN and
if ((baseType != baseType->derivedFrom[i].type) && isImplicitlyVirtual_rec(baseType->derivedFrom[i].type, safe)) // #5590 with a loop within the class hierarchie.
return true; // We do so by tracking all previously checked types in a deque.
std::deque< const ::Type* > local_anchestors;
if (!anchestors) {
anchestors=&local_anchestors;
}
anchestors->push_back(baseType);
if (std::find(anchestors->begin(), anchestors->end(), baseType->derivedFrom[i].type)==anchestors->end()) {
if (isImplicitlyVirtual_rec(baseType->derivedFrom[i].type, safe, anchestors)) {
return true;
}
}
} }
} else { } else {
// unable to find base class so assume it has no virtual function // unable to find base class so assume it has no virtual function

View File

@ -24,6 +24,7 @@
#include <string> #include <string>
#include <list> #include <list>
#include <vector> #include <vector>
#include <deque>
#include <set> #include <set>
#include <algorithm> #include <algorithm>
@ -603,7 +604,7 @@ public:
static bool argsMatch(const Scope *info, const Token *first, const Token *second, const std::string &path, unsigned int depth); static bool argsMatch(const Scope *info, const Token *first, const Token *second, const std::string &path, unsigned int depth);
private: private:
bool isImplicitlyVirtual_rec(const ::Type* type, bool& safe) const; bool isImplicitlyVirtual_rec(const ::Type* type, bool& safe, std::deque<const ::Type* > *anchestors = nullptr) const;
}; };
class CPPCHECKLIB Scope { class CPPCHECKLIB Scope {

View File

@ -1818,6 +1818,27 @@ private:
" }\n" " }\n"
"};"); "};");
ASSERT(db && db->findScopeByName("Bar") && !db->findScopeByName("Bar")->functionList.front().isImplicitlyVirtual(false)); ASSERT(db && db->findScopeByName("Bar") && !db->findScopeByName("Bar")->functionList.front().isImplicitlyVirtual(false));
ASSERT_EQUALS(1, db->findScopeByName("Bar")->functionList.size());
}
// #5590
{
GET_SYMBOL_DB("class InfiniteB : InfiniteA {\n"
" class D {\n"
" };\n"
"};\n"
"namespace N {\n"
" class InfiniteA : InfiniteB {\n"
" };\n"
"}\n"
"class InfiniteA : InfiniteB {\n"
" void foo();\n"
"};\n"
"void InfiniteA::foo() {\n"
" C a;\n"
"}");
//ASSERT(db && db->findScopeByName("InfiniteA") && !db->findScopeByName("InfiniteA")->functionList.front().isImplicitlyVirtual());
TODO_ASSERT_EQUALS(1, 0, db->findScopeByName("InfiniteA")->functionList.size());
} }
} }

View File

@ -72,6 +72,7 @@ private:
TEST_CASE(multiFile); TEST_CASE(multiFile);
TEST_CASE(unknownBaseTemplate); // ticket #2580 TEST_CASE(unknownBaseTemplate); // ticket #2580
TEST_CASE(hierarchie_loop); // ticket 5590
} }
@ -692,6 +693,25 @@ private:
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
} }
void hierarchie_loop() {
check("class InfiniteB : InfiniteA {\n"
" class D {\n"
" };\n"
"};\n"
"namespace N {\n"
" class InfiniteA : InfiniteB {\n"
" };\n"
"}\n"
"class InfiniteA : InfiniteB {\n"
" void foo();\n"
"};\n"
"void InfiniteA::foo() {\n"
" C a;\n"
"}");
ASSERT_EQUALS("[test.cpp:10]: (style) Unused private function: 'InfiniteA::foo'\n", errout.str());
}
}; };
REGISTER_TEST(TestUnusedPrivateFunction) REGISTER_TEST(TestUnusedPrivateFunction)