diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 712847e46..a4ed885b5 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -438,6 +438,7 @@ const Token* getCondTokFromEnd(const Token* endBlock) bool extractForLoopValues(const Token *forToken, nonneg int * const varid, + bool * const knownInitValue, MathLib::bigint * const initValue, MathLib::bigint * const stepValue, MathLib::bigint * const lastValue) @@ -447,10 +448,11 @@ bool extractForLoopValues(const Token *forToken, const Token *initExpr = forToken->next()->astOperand2()->astOperand1(); const Token *condExpr = forToken->next()->astOperand2()->astOperand2()->astOperand1(); const Token *incExpr = forToken->next()->astOperand2()->astOperand2()->astOperand2(); - if (!initExpr || !initExpr->isBinaryOp() || initExpr->str() != "=" || !Token::Match(initExpr->astOperand1(), "%var%") || !initExpr->astOperand2()->hasKnownIntValue()) + if (!initExpr || !initExpr->isBinaryOp() || initExpr->str() != "=" || !Token::Match(initExpr->astOperand1(), "%var%")) return false; *varid = initExpr->astOperand1()->varId(); - *initValue = initExpr->astOperand2()->getKnownIntValue(); + *knownInitValue = initExpr->astOperand2()->hasKnownIntValue(); + *initValue = (*knownInitValue) ? initExpr->astOperand2()->getKnownIntValue() : 0; if (!Token::Match(condExpr, "<|<=") || !condExpr->isBinaryOp() || condExpr->astOperand1()->varId() != *varid || !condExpr->astOperand2()->hasKnownIntValue()) return false; if (!incExpr || !incExpr->isUnaryOp("++") || incExpr->astOperand1()->varId() != *varid) diff --git a/lib/astutils.h b/lib/astutils.h index 3cd883f4d..b9f88e251 100644 --- a/lib/astutils.h +++ b/lib/astutils.h @@ -113,6 +113,7 @@ const Token* getCondTokFromEnd(const Token* endBlock); */ bool extractForLoopValues(const Token *forToken, nonneg int * const varid, + bool * const knownInitValue, long long * const initValue, long long * const stepValue, long long * const lastValue); diff --git a/lib/exprengine.cpp b/lib/exprengine.cpp index b1d9d81bf..7991cebb4 100644 --- a/lib/exprengine.cpp +++ b/lib/exprengine.cpp @@ -2371,8 +2371,9 @@ static std::string execute(const Token *start, const Token *end, Data &data) if (Token::simpleMatch(tok, "for (")) { nonneg int varid; + bool hasKnownInitValue; MathLib::bigint initValue, stepValue, lastValue; - if (extractForLoopValues(tok, &varid, &initValue, &stepValue, &lastValue)) { + if (extractForLoopValues(tok, &varid, &hasKnownInitValue, &initValue, &stepValue, &lastValue) && hasKnownInitValue) { auto loopValues = std::make_shared(data.getNewSymbolName(), initValue, lastValue); data.assignValue(tok, varid, loopValues); tok = tok->linkAt(1); diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 8b10c6ba2..0faa10ef5 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -4444,44 +4444,6 @@ static void valueFlowInferCondition(TokenList* tokenlist, } } -static bool valueFlowForLoop1(const Token *tok, int * const varid, MathLib::bigint * const num1, MathLib::bigint * const num2, MathLib::bigint * const numAfter) -{ - tok = tok->tokAt(2); - if (!Token::Match(tok, "%type%| %var% =")) - return false; - const Token * const vartok = Token::Match(tok, "%var% =") ? tok : tok->next(); - *varid = vartok->varId(); - tok = vartok->tokAt(2); - const Token * const num1tok = Token::Match(tok, "%num% ;") ? tok : nullptr; - if (num1tok) - *num1 = MathLib::toLongNumber(num1tok->str()); - while (Token::Match(tok, "%name%|%num%|%or%|+|-|*|/|&|[|]|(")) - tok = (tok->str() == "(") ? tok->link()->next() : tok->next(); - if (!tok || tok->str() != ";") - return false; - tok = tok->next(); - const Token *num2tok = nullptr; - if (Token::Match(tok, "%varid% <|<=|!=", vartok->varId())) { - tok = tok->next(); - num2tok = tok->astOperand2(); - if (num2tok && num2tok->str() == "(" && !num2tok->astOperand2()) - num2tok = num2tok->astOperand1(); - if (!Token::Match(num2tok, "%num% ;|%oror%")) // TODO: || enlarges the scope of the condition, so it should not cause FP, but it should no lnger be part of this pattern as soon as valueFlowForLoop2 can handle an unknown RHS of || better - num2tok = nullptr; - } - if (!num2tok) - return false; - *num2 = MathLib::toLongNumber(num2tok->str()) - ((tok->str()=="<=") ? 0 : 1); - *numAfter = *num2 + 1; - if (!num1tok) - *num1 = *num2; - while (tok && tok->str() != ";") - tok = tok->next(); - if (!Token::Match(tok, "; %varid% ++ ) {", vartok->varId()) && !Token::Match(tok, "; ++ %varid% ) {", vartok->varId())) - return false; - return true; -} - static bool valueFlowForLoop2(const Token *tok, ProgramMemory *memory1, ProgramMemory *memory2, @@ -4663,16 +4625,19 @@ static void valueFlowForLoop(TokenList *tokenlist, SymbolDatabase* symboldatabas !Token::simpleMatch(tok->next()->astOperand2()->astOperand2(), ";")) continue; - int varid(0); - MathLib::bigint num1(0), num2(0), numAfter(0); + nonneg int varid; + bool knownInitValue; + MathLib::bigint initValue, stepValue, lastValue; - if (valueFlowForLoop1(tok, &varid, &num1, &num2, &numAfter)) { - if (num1 <= num2) { - valueFlowForLoopSimplify(bodyStart, varid, false, num1, tokenlist, errorLogger, settings); - valueFlowForLoopSimplify(bodyStart, varid, false, num2, tokenlist, errorLogger, settings); - valueFlowForLoopSimplifyAfter(tok, varid, numAfter, tokenlist, errorLogger, settings); - } else - valueFlowForLoopSimplifyAfter(tok, varid, num1, tokenlist, errorLogger, settings); + if (extractForLoopValues(tok, &varid, &knownInitValue, &initValue, &stepValue, &lastValue)) { + const bool executeBody = !knownInitValue || initValue <= lastValue; + if (executeBody) { + valueFlowForLoopSimplify(bodyStart, varid, false, initValue, tokenlist, errorLogger, settings); + if (stepValue == 1) + valueFlowForLoopSimplify(bodyStart, varid, false, lastValue, tokenlist, errorLogger, settings); + } + const MathLib::bigint afterValue = executeBody ? lastValue + stepValue : initValue; + valueFlowForLoopSimplifyAfter(tok, varid, afterValue, tokenlist, errorLogger, settings); } else { ProgramMemory mem1, mem2, memAfter; if (valueFlowForLoop2(tok, &mem1, &mem2, &memAfter)) {