Refactor valueflow forward and reverse functions and unify them (#4127)

* Move functions around

* Make it a template to handle both overloads

* Simplify forward

* Remove container forward

* Remove unused settings params

* Format

* Remove valueFlowForwardExpression

* Format

* Remove init list

* Make const ref

* Remove braces

* Remove braces
This commit is contained in:
Paul Fultz II 2022-05-23 23:41:17 -05:00 committed by GitHub
parent 5999b35130
commit 7405ea039d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 205 additions and 327 deletions

View File

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