diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index fb0739c69..508f23005 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -1827,20 +1827,78 @@ static void valueFlowGlobalStaticVar(TokenList *tokenList, const Settings *setti } } +ValuePtr makeAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList* tokenlist); +ValuePtr makeReverseAnalyzer(const Token* exprTok, const ValueFlow::Value& value, const TokenList* tokenlist); + +static Analyzer::Result valueFlowForward(Token* startToken, + const Token* endToken, + const Token* exprTok, + const ValueFlow::Value& value, + TokenList* const tokenlist) +{ + return valueFlowGenericForward(startToken, endToken, makeAnalyzer(exprTok, value, tokenlist), tokenlist->getSettings()); +} + static Analyzer::Result valueFlowForward(Token* startToken, const Token* endToken, const Token* exprTok, const std::list& values, - TokenList* const tokenlist, - const Settings* settings); + TokenList* const tokenlist) +{ + Analyzer::Result result{}; + for (const ValueFlow::Value& v : values) { + result.update(valueFlowForward(startToken, endToken, exprTok, v, tokenlist)); + } + return result; +} +template +static Analyzer::Result valueFlowForward(Token* startToken, const Token* exprTok, const ValueOrValues& v, TokenList* tokenlist) +{ + const Token* endToken = nullptr; + const Function* f = Scope::nestedInFunction(startToken->scope()); + if (f && f->functionScope) + endToken = f->functionScope->bodyEnd; + return valueFlowForward(startToken, endToken, exprTok, v, tokenlist); +} + +static Analyzer::Result valueFlowForwardRecursive(Token* top, + const Token* exprTok, + const std::list& values, + TokenList* const tokenlist) +{ + Analyzer::Result result{}; + for (const ValueFlow::Value& v : values) { + result.update(valueFlowGenericForward(top, makeAnalyzer(exprTok, v, tokenlist), tokenlist->getSettings())); + } + return result; +} + +static void valueFlowReverse(Token* tok, + const Token* const endToken, + const Token* const varToken, + const std::list& values, + TokenList* tokenlist) +{ + for (const ValueFlow::Value& v : values) { + valueFlowGenericReverse(tok, endToken, makeReverseAnalyzer(varToken, v, tokenlist), tokenlist->getSettings()); + } +} + +// Deprecated static void valueFlowReverse(TokenList* tokenlist, Token* tok, const Token* const varToken, ValueFlow::Value val, const ValueFlow::Value& val2, - ErrorLogger* errorLogger, - const Settings* settings); + ErrorLogger* /*errorLogger*/, + const Settings* = nullptr) +{ + std::list values = {val}; + if (val2.varId != 0) + values.push_back(val2); + valueFlowReverse(tok, nullptr, varToken, values, tokenlist); +} static bool isConditionKnown(const Token* tok, bool then) { @@ -2647,8 +2705,6 @@ struct ValueFlowAnalyzer : Analyzer { } }; -ValuePtr makeAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList* tokenlist); - struct SingleValueFlowAnalyzer : ValueFlowAnalyzer { std::unordered_map varids; std::unordered_map aliases; @@ -2944,162 +3000,6 @@ struct MemberExpressionAnalyzer : SubExpressionAnalyzer { } }; -static Analyzer::Result valueFlowForwardExpression(Token* startToken, - const Token* endToken, - const Token* exprTok, - const std::list& values, - const TokenList* const tokenlist, - const Settings* settings) -{ - Analyzer::Result result{}; - for (const ValueFlow::Value& v : values) { - ExpressionAnalyzer a(exprTok, v, tokenlist); - result.update(valueFlowGenericForward(startToken, endToken, a, settings)); - } - return result; -} - -static const Token* parseBinaryIntOp(const Token* expr, - const std::function(const Token*)>& eval, - MathLib::bigint& known) -{ - if (!expr) - return nullptr; - if (!expr->astOperand1() || !expr->astOperand2()) - return nullptr; - if (expr->astOperand1()->exprId() == 0 && expr->astOperand2()->exprId() == 0) - return nullptr; - std::vector x1 = eval(expr->astOperand1()); - std::vector x2 = eval(expr->astOperand2()); - if (expr->astOperand1()->exprId() == 0 && x1.empty()) - return nullptr; - if (expr->astOperand2()->exprId() == 0 && x2.empty()) - return nullptr; - const Token* varTok = nullptr; - if (!x1.empty() && x2.empty()) { - varTok = expr->astOperand2(); - known = x1.front(); - } else if (x1.empty() && !x2.empty()) { - varTok = expr->astOperand1(); - known = x2.front(); - } - return varTok; -} - -const Token* solveExprValue(const Token* expr, - const std::function(const Token*)>& eval, - ValueFlow::Value& value) -{ - if (!value.isIntValue() && !value.isIteratorValue() && !value.isSymbolicValue()) - return expr; - if (value.isSymbolicValue() && !Token::Match(expr, "+|-")) - return expr; - MathLib::bigint intval; - const Token* binaryTok = parseBinaryIntOp(expr, eval, intval); - bool rhs = astIsRHS(binaryTok); - // If its on the rhs, then -1 multiplication is needed, which is not possible with simple delta analysis used currently for symbolic values - if (value.isSymbolicValue() && rhs && Token::simpleMatch(expr, "-")) - return expr; - if (binaryTok && expr->str().size() == 1) { - switch (expr->str()[0]) { - case '+': { - value.intvalue -= intval; - return solveExprValue(binaryTok, eval, value); - } - case '-': { - if (rhs) - value.intvalue = intval - value.intvalue; - else - value.intvalue += intval; - return solveExprValue(binaryTok, eval, value); - } - case '*': { - if (intval == 0) - break; - value.intvalue /= intval; - return solveExprValue(binaryTok, eval, value); - } - case '^': { - value.intvalue ^= intval; - return solveExprValue(binaryTok, eval, value); - } - } - } - return expr; -} - -static const Token* solveExprValue(const Token* expr, ValueFlow::Value& value) -{ - return solveExprValue( - expr, - [](const Token* tok) -> std::vector { - if (tok->hasKnownIntValue()) - return {tok->values().front().intvalue}; - return {}; - }, - value); -} - -ValuePtr makeAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList* tokenlist) -{ - const Token* expr = solveExprValue(exprTok, value); - return ExpressionAnalyzer(expr, value, tokenlist); -} - -static Analyzer::Result valueFlowForward(Token* startToken, - const Token* endToken, - const Token* exprTok, - const std::list& values, - TokenList* const tokenlist, - const Settings* settings) -{ - Analyzer::Result result{}; - for (const ValueFlow::Value& v : values) { - result.update(valueFlowGenericForward(startToken, endToken, makeAnalyzer(exprTok, v, tokenlist), settings)); - } - return result; -} - -static Analyzer::Result valueFlowForward(Token* top, - const Token* exprTok, - const std::list& values, - TokenList* const tokenlist, - const Settings* settings) -{ - Analyzer::Result result{}; - for (const ValueFlow::Value& v : values) { - result.update(valueFlowGenericForward(top, makeAnalyzer(exprTok, v, tokenlist), settings)); - } - return result; -} - -static void valueFlowReverse(Token* tok, - const Token* const endToken, - const Token* const varToken, - const std::list& values, - TokenList* tokenlist, - const Settings* settings) -{ - for (const ValueFlow::Value& v : values) { - ExpressionAnalyzer a(varToken, v, tokenlist); - valueFlowGenericReverse(tok, endToken, a, settings); - } -} - -static void valueFlowReverse(TokenList* tokenlist, - Token* tok, - const Token* const varToken, - ValueFlow::Value val, - const ValueFlow::Value& val2, - ErrorLogger* /*errorLogger*/, - const Settings* settings) -{ - std::list values = {val}; - if (val2.varId != 0) - values.push_back(val2); - valueFlowReverse(tok, nullptr, varToken, values, tokenlist, settings); -} - enum class LifetimeCapture { Undefined, ByValue, ByReference }; std::string lifetimeType(const Token *tok, const ValueFlow::Value *val) @@ -3591,7 +3491,7 @@ static void valueFlowForwardLifetime(Token * tok, TokenList *tokenlist, ErrorLog if (Token::Match(tok->previous(), "%var% {|(") && isVariableDecl(tok->previous())) { std::list values = tok->values(); values.remove_if(&isNotLifetimeValue); - valueFlowForward(nextAfterAstRightmostLeaf(tok), getEndOfExprScope(tok), tok->previous(), values, tokenlist, settings); + valueFlowForward(nextAfterAstRightmostLeaf(tok), getEndOfExprScope(tok), tok->previous(), values, tokenlist); return; } Token *parent = tok->astParent(); @@ -3631,12 +3531,7 @@ static void valueFlowForwardLifetime(Token * tok, TokenList *tokenlist, ErrorLog const Token *nextExpression = nextAfterAstRightmostLeaf(parent); if (expr->exprId() > 0) { - valueFlowForwardExpression(const_cast(nextExpression), - endOfVarScope->next(), - expr, - values, - tokenlist, - settings); + valueFlowForward(const_cast(nextExpression), endOfVarScope->next(), expr, values, tokenlist); for (ValueFlow::Value& val : values) { if (val.lifetimeKind == ValueFlow::Value::LifetimeKind::Address) @@ -3647,12 +3542,7 @@ static void valueFlowForwardLifetime(Token * tok, TokenList *tokenlist, ErrorLog const Token* parentLifetime = getParentLifetime(tokenlist->isCPP(), parent->astOperand1()->astOperand2(), &settings->library); if (parentLifetime && parentLifetime->exprId() > 0) { - valueFlowForward(const_cast(nextExpression), - endOfVarScope, - parentLifetime, - values, - tokenlist, - settings); + valueFlowForward(const_cast(nextExpression), endOfVarScope, parentLifetime, values, tokenlist); } } } @@ -3673,7 +3563,7 @@ static void valueFlowForwardLifetime(Token * tok, TokenList *tokenlist, ErrorLog const Token *nextExpression = nextAfterAstRightmostLeaf(parent); // Only forward lifetime values values.remove_if(&isNotLifetimeValue); - valueFlowForward(const_cast(nextExpression), endOfVarScope, tok, values, tokenlist, settings); + valueFlowForward(const_cast(nextExpression), endOfVarScope, tok, values, tokenlist); // Cast } else if (parent->isCast()) { std::list values = tok->values(); @@ -4724,7 +4614,7 @@ static void valueFlowAfterMove(TokenList* tokenlist, SymbolDatabase* symboldatab continue; const Token * const endOfVarScope = var->scope()->bodyEnd; setTokenValue(varTok, value, settings); - valueFlowForward(varTok->next(), endOfVarScope, varTok, values, tokenlist, settings); + valueFlowForward(varTok->next(), endOfVarScope, varTok, values, tokenlist); continue; } ValueFlow::Value::MoveKind moveKind; @@ -4760,8 +4650,7 @@ static void valueFlowAfterMove(TokenList* tokenlist, SymbolDatabase* symboldatab const Token * openParentesisOfMove = findOpenParentesisOfMove(varTok); const Token * endOfFunctionCall = findEndOfFunctionCallForParameter(openParentesisOfMove); if (endOfFunctionCall) - valueFlowForward( - const_cast(endOfFunctionCall), endOfVarScope, varTok, values, tokenlist, settings); + valueFlowForward(const_cast(endOfFunctionCall), endOfVarScope, varTok, values, tokenlist); } } } @@ -4981,13 +4870,13 @@ static void valueFlowSymbolic(TokenList* tokenlist, SymbolDatabase* symboldataba rhs.errorPath.emplace_back(tok, tok->astOperand1()->expressionString() + " is assigned '" + tok->astOperand2()->expressionString() + "' here."); - valueFlowForward(start, end, tok->astOperand1(), {rhs}, tokenlist, tokenlist->getSettings()); + valueFlowForward(start, end, tok->astOperand1(), rhs, tokenlist); ValueFlow::Value lhs = makeSymbolic(tok->astOperand1()); lhs.errorPath.emplace_back(tok, tok->astOperand1()->expressionString() + " is assigned '" + tok->astOperand2()->expressionString() + "' here."); - valueFlowForward(start, end, tok->astOperand2(), {lhs}, tokenlist, tokenlist->getSettings()); + valueFlowForward(start, end, tok->astOperand2(), lhs, tokenlist); } } } @@ -5267,7 +5156,7 @@ static void valueFlowForwardAssign(Token* const tok, constValues.splice(constValues.end(), values, it, values.end()); valueFlowForwardConst(const_cast(nextExpression), endOfVarScope, expr->variable(), constValues, settings); } - valueFlowForward(const_cast(nextExpression), endOfVarScope, expr, values, tokenlist, settings); + valueFlowForward(const_cast(nextExpression), endOfVarScope, expr, values, tokenlist); } static void valueFlowForwardAssign(Token* const tok, @@ -5439,7 +5328,7 @@ static void valueFlowAfterAssign(TokenList *tokenlist, SymbolDatabase* symboldat value.errorPath.emplace_back(tok, tok->astOperand1()->expressionString() + " is assigned '" + tok->astOperand2()->expressionString() + "' here."); - valueFlowForward(start, end, expr, {value}, tokenlist, settings); + valueFlowForward(start, end, expr, value, tokenlist); } } } @@ -5545,27 +5434,33 @@ struct ConditionHandler { Condition() : vartok(nullptr), true_values(), false_values(), inverted(false), impossible(true) {} }; + virtual std::vector parse(const Token* tok, const Settings* settings) const = 0; + virtual Analyzer::Result forward(Token* start, const Token* stop, const Token* exprTok, const std::list& values, - TokenList* tokenlist, - const Settings* settings) const = 0; + TokenList* tokenlist) const + { + return valueFlowForward(start->next(), stop, exprTok, values, tokenlist); + } virtual Analyzer::Result forward(Token* top, const Token* exprTok, const std::list& values, - TokenList* tokenlist, - const Settings* settings) const = 0; + TokenList* tokenlist) const + { + return valueFlowForwardRecursive(top, exprTok, values, tokenlist); + } virtual void reverse(Token* start, const Token* endToken, const Token* exprTok, const std::list& values, - TokenList* tokenlist, - const Settings* settings) const = 0; - - virtual std::vector parse(const Token* tok, const Settings* settings) const = 0; + TokenList* tokenlist) const + { + return valueFlowReverse(start, endToken, exprTok, values, tokenlist); + } void traverseCondition(TokenList* tokenlist, SymbolDatabase* symboldatabase, @@ -5686,7 +5581,7 @@ struct ConditionHandler { })) { // Start at the end of the loop body Token* bodyTok = top->link()->next(); - reverse(bodyTok->link(), bodyTok, cond.vartok, values, tokenlist, settings); + reverse(bodyTok->link(), bodyTok, cond.vartok, values, tokenlist); } if (settings->debugwarnings) bailout(tokenlist, @@ -5705,7 +5600,7 @@ struct ConditionHandler { if (!startTok) startTok = tok->previous(); - reverse(startTok, nullptr, cond.vartok, values, tokenlist, settings); + reverse(startTok, nullptr, cond.vartok, values, tokenlist); }); } @@ -5792,7 +5687,7 @@ struct ConditionHandler { return v.isImpossible(); }); for (Token* start:nextExprs) { - Analyzer::Result r = forward(start, cond.vartok, values, tokenlist, settings); + Analyzer::Result r = forward(start, cond.vartok, values, tokenlist); if (r.terminate != Analyzer::Terminate::None) return; } @@ -5852,8 +5747,8 @@ struct ConditionHandler { if (Token::simpleMatch(condTop, "?")) { Token* colon = condTop->astOperand2(); - forward(colon->astOperand1(), cond.vartok, thenValues, tokenlist, settings); - forward(colon->astOperand2(), cond.vartok, elseValues, tokenlist, settings); + forward(colon->astOperand1(), cond.vartok, thenValues, tokenlist); + forward(colon->astOperand2(), cond.vartok, elseValues, tokenlist); // TODO: Handle after condition return; } @@ -5937,8 +5832,7 @@ struct ConditionHandler { std::list& values = (i == 0 ? thenValues : elseValues); valueFlowSetConditionToKnown(condTok, values, i == 0); - Analyzer::Result r = - forward(startTokens[i], startTokens[i]->link(), cond.vartok, values, tokenlist, settings); + Analyzer::Result r = forward(startTokens[i], startTokens[i]->link(), cond.vartok, values, tokenlist); deadBranch[i] = r.terminate == Analyzer::Terminate::Escape; if (r.action.isModified() && !deadBranch[i]) changeBlock = i; @@ -6040,7 +5934,7 @@ struct ConditionHandler { } if (values.empty()) return; - forward(after, getEndOfExprScope(cond.vartok, scope), cond.vartok, values, tokenlist, settings); + forward(after, getEndOfExprScope(cond.vartok, scope), cond.vartok, values, tokenlist); } }); } @@ -6058,32 +5952,6 @@ static void valueFlowCondition(const ValuePtr& handler, } struct SimpleConditionHandler : ConditionHandler { - virtual Analyzer::Result forward(Token* start, - const Token* stop, - const Token* exprTok, - const std::list& values, - TokenList* tokenlist, - const Settings* settings) const override { - return valueFlowForward(start->next(), stop, exprTok, values, tokenlist, settings); - } - - virtual Analyzer::Result forward(Token* top, - const Token* exprTok, - const std::list& values, - TokenList* tokenlist, - const Settings* settings) const override { - return valueFlowForward(top, exprTok, values, tokenlist, settings); - } - - virtual void reverse(Token* start, - const Token* endToken, - const Token* exprTok, - const std::list& values, - TokenList* tokenlist, - const Settings* settings) const override { - return valueFlowReverse(start, endToken, exprTok, values, tokenlist, settings); - } - virtual std::vector parse(const Token* tok, const Settings*) const override { Condition cond; ValueFlow::Value true_value; @@ -6453,11 +6321,7 @@ static void valueFlowForLoopSimplify(Token* const bodyStart, } } -static void valueFlowForLoopSimplifyAfter(Token* fortok, - nonneg int varid, - const MathLib::bigint num, - TokenList* tokenlist, - const Settings* settings) +static void valueFlowForLoopSimplifyAfter(Token* fortok, nonneg int varid, const MathLib::bigint num, TokenList* tokenlist) { const Token *vartok = nullptr; for (const Token *tok = fortok; tok; tok = tok->next()) { @@ -6482,7 +6346,7 @@ static void valueFlowForLoopSimplifyAfter(Token* fortok, values.back().errorPath.emplace_back(fortok,"After for loop, " + var->name() + " has value " + values.back().infoString()); if (blockTok != endToken) { - valueFlowForward(blockTok->next(), endToken, vartok, values, tokenlist, settings); + valueFlowForward(blockTok->next(), endToken, vartok, values, tokenlist); } } @@ -6510,8 +6374,7 @@ static void valueFlowForLoop(TokenList *tokenlist, SymbolDatabase* symboldatabas std::list initValues; initValues.emplace_back(initValue, ValueFlow::Value::Bound::Lower); initValues.push_back(asImpossible(initValues.back())); - Analyzer::Result result = - valueFlowForward(bodyStart, bodyStart->link(), vartok, initValues, tokenlist, settings); + Analyzer::Result result = valueFlowForward(bodyStart, bodyStart->link(), vartok, initValues, tokenlist); if (!result.action.isModified()) { std::list lastValues; @@ -6520,11 +6383,11 @@ static void valueFlowForLoop(TokenList *tokenlist, SymbolDatabase* symboldatabas lastValues.push_back(asImpossible(lastValues.back())); if (stepValue != 1) lastValues.pop_front(); - valueFlowForward(bodyStart, bodyStart->link(), vartok, lastValues, tokenlist, settings); + valueFlowForward(bodyStart, bodyStart->link(), vartok, lastValues, tokenlist); } } const MathLib::bigint afterValue = executeBody ? lastValue + stepValue : initValue; - valueFlowForLoopSimplifyAfter(tok, varid, afterValue, tokenlist, settings); + valueFlowForLoopSimplifyAfter(tok, varid, afterValue, tokenlist); } else { ProgramMemory mem1, mem2, memAfter; if (valueFlowForLoop2(tok, &mem1, &mem2, &memAfter)) { @@ -6547,7 +6410,7 @@ static void valueFlowForLoop(TokenList *tokenlist, SymbolDatabase* symboldatabas continue; if (p.first.tok->varId() == 0) continue; - valueFlowForLoopSimplifyAfter(tok, p.first.getExpressionId(), p.second.intvalue, tokenlist, settings); + valueFlowForLoopSimplifyAfter(tok, p.first.getExpressionId(), p.second.intvalue, tokenlist); } } } @@ -6804,7 +6667,6 @@ static void valueFlowInjectParameter(TokenList* tokenlist, } static void valueFlowInjectParameter(TokenList* tokenlist, - const Settings* settings, const Variable* arg, const Scope* functionScope, const std::list& argvalues) @@ -6822,8 +6684,7 @@ static void valueFlowInjectParameter(TokenList* tokenlist, functionScope->bodyEnd, arg->nameToken(), argvalues, - tokenlist, - settings); + tokenlist); } static void valueFlowSwitchVariable(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings) @@ -7046,7 +6907,7 @@ static void valueFlowSubFunction(TokenList* tokenlist, SymbolDatabase* symboldat } } -static void valueFlowFunctionDefaultParameter(TokenList* tokenlist, SymbolDatabase* symboldatabase, const Settings* settings) +static void valueFlowFunctionDefaultParameter(TokenList* tokenlist, SymbolDatabase* symboldatabase) { if (!tokenlist->isCPP()) return; @@ -7068,7 +6929,7 @@ static void valueFlowFunctionDefaultParameter(TokenList* tokenlist, SymbolDataba argvalues.push_back(v); } if (!argvalues.empty()) - valueFlowInjectParameter(tokenlist, settings, var, scope, argvalues); + valueFlowInjectParameter(tokenlist, var, scope, argvalues); } } } @@ -7264,7 +7125,7 @@ static void valueFlowUninit(TokenList* tokenlist, SymbolDatabase* /*symbolDataba if (partial) continue; - valueFlowForward(tok->next(), tok->scope()->bodyEnd, var->nameToken(), {uninitValue}, tokenlist, settings); + valueFlowForward(tok->next(), tok->scope()->bodyEnd, var->nameToken(), uninitValue, tokenlist); } } @@ -7422,48 +7283,100 @@ struct ContainerExpressionAnalyzer : ExpressionAnalyzer { } }; -static Analyzer::Result valueFlowContainerForward(Token* startToken, - const Token* endToken, - const Token* exprTok, - const ValueFlow::Value& value, - TokenList* tokenlist) +static const Token* parseBinaryIntOp(const Token* expr, + const std::function(const Token*)>& eval, + MathLib::bigint& known) { - ContainerExpressionAnalyzer a(exprTok, value, tokenlist); - return valueFlowGenericForward(startToken, endToken, a, tokenlist->getSettings()); -} - -static Analyzer::Result valueFlowContainerForwardRecursive(Token* top, - const Token* exprTok, - const ValueFlow::Value& value, - TokenList* tokenlist) -{ - ContainerExpressionAnalyzer a(exprTok, value, tokenlist); - return valueFlowGenericForward(top, a, tokenlist->getSettings()); -} - -static Analyzer::Result valueFlowContainerForward(Token* startToken, - const Token* exprTok, - const ValueFlow::Value& value, - TokenList* tokenlist) -{ - const Token* endToken = nullptr; - const Function* f = Scope::nestedInFunction(startToken->scope()); - if (f && f->functionScope) - endToken = f->functionScope->bodyEnd; - return valueFlowContainerForward(startToken, endToken, exprTok, value, tokenlist); -} - -static void valueFlowContainerReverse(Token* tok, - const Token* const endToken, - const Token* const varToken, - const std::list& values, - TokenList* tokenlist, - const Settings* settings) -{ - for (const ValueFlow::Value& value : values) { - ContainerExpressionAnalyzer a(varToken, value, tokenlist); - valueFlowGenericReverse(tok, endToken, a, settings); + if (!expr) + return nullptr; + if (!expr->astOperand1() || !expr->astOperand2()) + return nullptr; + if (expr->astOperand1()->exprId() == 0 && expr->astOperand2()->exprId() == 0) + return nullptr; + std::vector x1 = eval(expr->astOperand1()); + std::vector x2 = eval(expr->astOperand2()); + if (expr->astOperand1()->exprId() == 0 && x1.empty()) + return nullptr; + if (expr->astOperand2()->exprId() == 0 && x2.empty()) + return nullptr; + const Token* varTok = nullptr; + if (!x1.empty() && x2.empty()) { + varTok = expr->astOperand2(); + known = x1.front(); + } else if (x1.empty() && !x2.empty()) { + varTok = expr->astOperand1(); + known = x2.front(); } + return varTok; +} + +const Token* solveExprValue(const Token* expr, + const std::function(const Token*)>& eval, + ValueFlow::Value& value) +{ + if (!value.isIntValue() && !value.isIteratorValue() && !value.isSymbolicValue()) + return expr; + if (value.isSymbolicValue() && !Token::Match(expr, "+|-")) + return expr; + MathLib::bigint intval; + const Token* binaryTok = parseBinaryIntOp(expr, eval, intval); + bool rhs = astIsRHS(binaryTok); + // If its on the rhs, then -1 multiplication is needed, which is not possible with simple delta analysis used currently for symbolic values + if (value.isSymbolicValue() && rhs && Token::simpleMatch(expr, "-")) + return expr; + if (binaryTok && expr->str().size() == 1) { + switch (expr->str()[0]) { + case '+': { + value.intvalue -= intval; + return solveExprValue(binaryTok, eval, value); + } + case '-': { + if (rhs) + value.intvalue = intval - value.intvalue; + else + value.intvalue += intval; + return solveExprValue(binaryTok, eval, value); + } + case '*': { + if (intval == 0) + break; + value.intvalue /= intval; + return solveExprValue(binaryTok, eval, value); + } + case '^': { + value.intvalue ^= intval; + return solveExprValue(binaryTok, eval, value); + } + } + } + return expr; +} + +static const Token* solveExprValue(const Token* expr, ValueFlow::Value& value) +{ + return solveExprValue( + expr, + [](const Token* tok) -> std::vector { + if (tok->hasKnownIntValue()) + return {tok->values().front().intvalue}; + return {}; + }, + value); +} + +ValuePtr makeAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList* tokenlist) +{ + if (value.isContainerSizeValue()) + return ContainerExpressionAnalyzer(exprTok, value, tokenlist); + const Token* expr = solveExprValue(exprTok, value); + return ExpressionAnalyzer(expr, value, tokenlist); +} + +ValuePtr makeReverseAnalyzer(const Token* exprTok, const ValueFlow::Value& value, const TokenList* tokenlist) +{ + if (value.isContainerSizeValue()) + return ContainerExpressionAnalyzer(exprTok, value, tokenlist); + return ExpressionAnalyzer(exprTok, value, tokenlist); } bool isContainerSizeChanged(const Token* tok, const Settings* settings, int depth) @@ -7879,7 +7792,7 @@ static void valueFlowContainerSize(TokenList* tokenlist, if (constSize) valueFlowForwardConst(var->nameToken()->next(), var->scope()->bodyEnd, var, values, settings); else - valueFlowContainerForward(var->nameToken()->next(), var->nameToken(), value, tokenlist); + valueFlowForward(var->nameToken()->next(), var->nameToken(), value, tokenlist); } } @@ -7894,7 +7807,7 @@ static void valueFlowContainerSize(TokenList* tokenlist, ValueFlow::Value value(Token::getStrLength(containerTok->tokAt(2))); value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE; value.setKnown(); - valueFlowContainerForward(containerTok->next(), containerTok, value, tokenlist); + valueFlowForward(containerTok->next(), containerTok, value, tokenlist); } } else if (Token::Match(tok, "%name%|;|{|}|> %var% = {") && Token::simpleMatch(tok->linkAt(3), "} ;")) { const Token* containerTok = tok->next(); @@ -7904,7 +7817,7 @@ static void valueFlowContainerSize(TokenList* tokenlist, std::vector values = getInitListSize(tok->tokAt(3), containerTok->valueType(), settings); for (const ValueFlow::Value& value : values) - valueFlowContainerForward(containerTok->next(), containerTok, value, tokenlist); + valueFlowForward(containerTok->next(), containerTok, value, tokenlist); } } else if (Token::Match(tok, ". %name% (") && tok->astOperand1() && tok->astOperand1()->valueType() && tok->astOperand1()->valueType()->container) { @@ -7916,13 +7829,13 @@ static void valueFlowContainerSize(TokenList* tokenlist, ValueFlow::Value value(0); value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE; value.setKnown(); - valueFlowContainerForward(tok->next(), containerTok, value, tokenlist); + valueFlowForward(tok->next(), containerTok, value, tokenlist); } else if (action == Library::Container::Action::RESIZE && tok->tokAt(2)->astOperand2() && tok->tokAt(2)->astOperand2()->hasKnownIntValue()) { ValueFlow::Value value(tok->tokAt(2)->astOperand2()->values().front()); value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE; value.setKnown(); - valueFlowContainerForward(tok->next(), containerTok, value, tokenlist); + valueFlowForward(tok->next(), containerTok, value, tokenlist); } } } @@ -7930,38 +7843,6 @@ static void valueFlowContainerSize(TokenList* tokenlist, } struct ContainerConditionHandler : ConditionHandler { - virtual Analyzer::Result forward(Token* start, - const Token* stop, - const Token* exprTok, - const std::list& values, - TokenList* tokenlist, - const Settings*) const override { - Analyzer::Result result{}; - for (const ValueFlow::Value& value : values) - result.update(valueFlowContainerForward(start->next(), stop, exprTok, value, tokenlist)); - return result; - } - - virtual Analyzer::Result forward(Token* top, - const Token* exprTok, - const std::list& values, - TokenList* tokenlist, - const Settings*) const override { - Analyzer::Result result{}; - for (const ValueFlow::Value& value : values) - result.update(valueFlowContainerForwardRecursive(top, exprTok, value, tokenlist)); - return result; - } - - virtual void reverse(Token* start, - const Token* endTok, - const Token* exprTok, - const std::list& values, - TokenList* tokenlist, - const Settings* settings) const override { - return valueFlowContainerReverse(start, endTok, exprTok, values, tokenlist, settings); - } - virtual std::vector parse(const Token* tok, const Settings* settings) const override { Condition cond; @@ -8127,7 +8008,7 @@ static void valueFlowDynamicBufferSize(TokenList* tokenlist, SymbolDatabase* sym value.valueType = ValueFlow::Value::ValueType::BUFFER_SIZE; value.setKnown(); const std::list values{value}; - valueFlowForward(const_cast(rhs), functionScope->bodyEnd, tok->next(), values, tokenlist, settings); + valueFlowForward(const_cast(rhs), functionScope->bodyEnd, tok->next(), values, tokenlist); } } } @@ -8228,8 +8109,7 @@ static void valueFlowSafeFunctions(TokenList* tokenlist, SymbolDatabase* symbold argValues.back().errorPath.emplace_back(arg.nameToken(), "Assuming " + arg.name() + " size is 1000000"); argValues.back().safe = true; for (const ValueFlow::Value &value : argValues) - valueFlowContainerForward( - const_cast(functionScope->bodyStart), arg.nameToken(), value, tokenlist); + valueFlowForward(const_cast(functionScope->bodyStart), arg.nameToken(), value, tokenlist); continue; } @@ -8267,8 +8147,7 @@ static void valueFlowSafeFunctions(TokenList* tokenlist, SymbolDatabase* symbold functionScope->bodyEnd, arg.nameToken(), argValues, - tokenlist, - settings); + tokenlist); continue; } } @@ -8290,8 +8169,7 @@ static void valueFlowSafeFunctions(TokenList* tokenlist, SymbolDatabase* symbold functionScope->bodyEnd, arg.nameToken(), argValues, - tokenlist, - settings); + tokenlist); } } } @@ -8519,7 +8397,7 @@ void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase, valueFlowSubFunction(tokenlist, symboldatabase, errorLogger, settings); valueFlowFunctionReturn(tokenlist, errorLogger); valueFlowLifetime(tokenlist, symboldatabase, errorLogger, settings); - valueFlowFunctionDefaultParameter(tokenlist, symboldatabase, settings); + valueFlowFunctionDefaultParameter(tokenlist, symboldatabase); valueFlowUninit(tokenlist, symboldatabase, settings); if (tokenlist->isCPP()) { valueFlowAfterMove(tokenlist, symboldatabase, settings);