From 78228599da0dfce3763a90a130b14fa2d614ab9f Mon Sep 17 00:00:00 2001 From: Paul Fultz II Date: Thu, 10 Feb 2022 23:52:28 -0600 Subject: [PATCH] Fix 10800: Hang / memory exhaustion on numerical code (#3822) * Fix 10800: Hang / memory exhaustion on numerical code * Format * Add another test * Format --- lib/token.cpp | 2 ++ lib/valueflow.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ test/testvalueflow.cpp | 15 +++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/lib/token.cpp b/lib/token.cpp index b16b75dfa..4920c92bd 100644 --- a/lib/token.cpp +++ b/lib/token.cpp @@ -2181,6 +2181,8 @@ bool Token::addValue(const ValueFlow::Value &value) // Add value if (it == mImpl->mValues->end()) { + // If the errorPath has gotten this large then there must be something wrong + assert(value.errorPath.size() < 64); ValueFlow::Value v(value); if (v.varId == 0) v.varId = mImpl->mVarId; diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index cfafcec42..17c4dd381 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -2252,10 +2252,18 @@ struct ValueFlowAnalyzer : Analyzer { const ValueFlow::Value* currValue = getValue(tok); if (!currValue) return false; + // If the same symbolic value is already there then skip + if (currValue->isSymbolicValue() && + std::any_of(tok->values().begin(), tok->values().end(), [&](const ValueFlow::Value& v) { + return v.isSymbolicValue() && currValue->equalValue(v); + })) + return false; const bool exact = !currValue->isIntValue() || currValue->isImpossible(); for (const ValueFlow::Value& v : tok->values()) { if (!v.isSymbolicValue()) continue; + if (currValue->equalValue(v)) + continue; const bool toImpossible = v.isImpossible() && currValue->isKnown(); if (!v.isKnown() && !toImpossible) continue; @@ -5056,9 +5064,23 @@ static bool isVariableInit(const Token *tok) !Token::simpleMatch(tok->astOperand2(), ","); } +// Return true if two associative containers intersect +template +static bool intersects(const C1& c1, const C2& c2) +{ + if (c1.size() > c2.size()) + return intersects(c2, c1); + for (auto&& x : c1) { + if (c2.find(x) != c2.end()) + return true; + } + return false; +} + static void valueFlowAfterAssign(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings) { for (const Scope * scope : symboldatabase->functionScopes) { + std::unordered_map> backAssigns; std::set aliased; for (Token* tok = const_cast(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) { // Alias @@ -5122,12 +5144,30 @@ static void valueFlowAfterAssign(TokenList *tokenlist, SymbolDatabase* symboldat if (tok->astOperand1()->exprId() > 0) { Token* start = nextAfterAstRightmostLeaf(tok); const Token* end = scope->bodyEnd; + // Collect symbolic ids + std::unordered_set ids; + for (const ValueFlow::Value& value : values) { + if (!value.isSymbolicValue()) + continue; + if (!value.tokvalue) + continue; + if (value.tokvalue->exprId() == 0) + continue; + ids.insert(value.tokvalue->exprId()); + } for (ValueFlow::Value value : values) { if (!value.isSymbolicValue()) continue; const Token* expr = value.tokvalue; value.intvalue = -value.intvalue; value.tokvalue = tok->astOperand1(); + + // Skip if it intersects with an already assigned symbol + auto& s = backAssigns[value.tokvalue->exprId()]; + if (intersects(s, ids)) + continue; + s.insert(expr->exprId()); + value.errorPath.emplace_back(tok, tok->astOperand1()->expressionString() + " is assigned '" + tok->astOperand2()->expressionString() + "' here."); diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 93d4a3dfa..5917dc4e9 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -6447,6 +6447,21 @@ private: " }\n" "}\n"; valueOfTok(code, "swap"); + + code = "double a;\n" + "int b, c, d, e, f, g;\n" + "void h() { double i, j = i = g = f = e = d = c = b = a; }\n"; + valueOfTok(code, "a"); + + code = "double a, c;\n" + "double *b;\n" + "void d() {\n" + " double e, f, g, h = g = f = e = c = a;\n" + " b[8] = a;\n" + " b[1] = a;\n" + " a;\n" + "}\n"; + valueOfTok(code, "a"); } void valueFlowCrashConstructorInitialization() { // #9577