From 6ffe08c9b37ec666085e8e045858394f1949771e Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Tue, 22 Aug 2023 21:01:52 +0200 Subject: [PATCH] Fix #11886 performance regression (hang) in 2.12dev (#5355) Or maybe we should just limit the recursion depth. --- lib/symboldatabase.cpp | 13 ++++++++++++- lib/valueflow.cpp | 2 +- test/testclass.cpp | 15 +++++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 9b3fbd91b..384bef620 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -4350,6 +4350,17 @@ const Function *Function::getOverriddenFunction(bool *foundAllBaseClasses) const return getOverriddenFunctionRecursive(nestedIn->definedType, foundAllBaseClasses); } +// prevent recursion if base is the same except for different template parameters +static bool isDerivedFromItself(const std::string& thisName, const std::string& baseName) +{ + if (thisName.back() != '>') + return false; + const auto pos = thisName.find('<'); + if (pos == std::string::npos) + return false; + return thisName.compare(0, pos + 1, baseName, 0, pos + 1) == 0; +} + const Function * Function::getOverriddenFunctionRecursive(const ::Type* baseType, bool *foundAllBaseClasses) const { // check each base class @@ -4402,7 +4413,7 @@ const Function * Function::getOverriddenFunctionRecursive(const ::Type* baseType } } - if (!derivedFromType->derivedFrom.empty() && !derivedFromType->hasCircularDependencies()) { + if (!derivedFromType->derivedFrom.empty() && !derivedFromType->hasCircularDependencies() && !isDerivedFromItself(baseType->classScope->className, i.name)) { // avoid endless recursion, see #5289 Crash: Stack overflow in isImplicitlyVirtual_rec when checking SVN and // #5590 with a loop within the class hierarchy. const Function *func = getOverriddenFunctionRecursive(derivedFromType, foundAllBaseClasses); diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 3572dddd3..f9d3f9425 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -5548,7 +5548,7 @@ static void valueFlowSymbolicOperators(const SymbolDatabase& symboldatabase, con ValueFlow::Value v = value; v.bound = ValueFlow::Value::Bound::Point; v.valueType = ValueFlow::Value::ValueType::INT; - v.errorPath.emplace_back(strlenTok, "Return index of string to the first element that is 0"); + v.errorPath.emplace_back(strlenTok, "Return index of first '\\0' character in string"); setTokenValue(tok, std::move(v), settings); } } diff --git a/test/testclass.cpp b/test/testclass.cpp index b2a343a44..5413a56c1 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -183,6 +183,7 @@ private: TEST_CASE(const89); TEST_CASE(const90); TEST_CASE(const91); + TEST_CASE(const92); TEST_CASE(const_handleDefaultParameters); TEST_CASE(const_passThisToMemberOfOtherClass); @@ -6654,6 +6655,20 @@ private: ASSERT_EQUALS("", errout.str()); } + void const92() { // #11886 + checkConst("void g(int);\n" + "template\n" + "struct S : public S {\n" + " void f() {\n" + " g(n - 1);\n" + " }\n" + "};\n" + "template<>\n" + "struct S<0> {};\n" + "struct D : S<150> {};\n"); + // don't hang + } + void const_handleDefaultParameters() { checkConst("struct Foo {\n" " void foo1(int i, int j = 0) {\n"