Handle for loop conditions in afterCondition (#3561)

This commit is contained in:
Paul Fultz II 2021-11-14 11:30:36 -06:00 committed by GitHub
parent 112363c9d1
commit a0d3c2c719
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 253 additions and 158 deletions

46
lib/astutils.cpp Executable file → Normal file
View File

@ -595,6 +595,38 @@ static T* getCondTokFromEndImpl(T* endBlock)
return nullptr;
}
template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
static T* getInitTokImpl(T* tok)
{
if (!tok)
return nullptr;
if (Token::Match(tok, "%name% ("))
return getInitTokImpl(tok->next());
if (tok->str() != "(")
return nullptr;
if (!Token::simpleMatch(tok->astOperand2(), ";"))
return nullptr;
if (Token::simpleMatch(tok->astOperand2()->astOperand1(), ";"))
return nullptr;
return tok->astOperand2()->astOperand1();
}
template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
static T* getStepTokImpl(T* tok)
{
if (!tok)
return nullptr;
if (Token::Match(tok, "%name% ("))
return getStepTokImpl(tok->next());
if (tok->str() != "(")
return nullptr;
if (!Token::simpleMatch(tok->astOperand2(), ";"))
return nullptr;
if (!Token::simpleMatch(tok->astOperand2()->astOperand2(), ";"))
return nullptr;
return tok->astOperand2()->astOperand2()->astOperand2();
}
Token* getCondTok(Token* tok)
{
return getCondTokImpl(tok);
@ -613,6 +645,20 @@ const Token* getCondTokFromEnd(const Token* endBlock)
return getCondTokFromEndImpl(endBlock);
}
Token* getInitTok(Token* tok) {
return getInitTokImpl(tok);
}
const Token* getInitTok(const Token* tok) {
return getInitTokImpl(tok);
}
Token* getStepTok(Token* tok) {
return getStepTokImpl(tok);
}
const Token* getStepTok(const Token* tok) {
return getStepTokImpl(tok);
}
const Token *findNextTokenFromBreak(const Token *breakToken)
{
const Scope *scope = breakToken->scope();

View File

@ -126,6 +126,12 @@ bool astIsRHS(const Token* tok);
Token* getCondTok(Token* tok);
const Token* getCondTok(const Token* tok);
Token* getInitTok(Token* tok);
const Token* getInitTok(const Token* tok);
Token* getStepTok(Token* tok);
const Token* getStepTok(const Token* tok);
Token* getCondTokFromEnd(Token* endBlock);
const Token* getCondTokFromEnd(const Token* endBlock);

View File

@ -784,34 +784,6 @@ struct ForwardTraversal {
return parent && (parent->str() == ":" || parent->astOperand2() == tok);
}
static Token* getInitTok(Token* tok) {
if (!tok)
return nullptr;
if (Token::Match(tok, "%name% ("))
return getInitTok(tok->next());
if (tok->str() != "(")
return nullptr;
if (!Token::simpleMatch(tok->astOperand2(), ";"))
return nullptr;
if (Token::simpleMatch(tok->astOperand2()->astOperand1(), ";"))
return nullptr;
return tok->astOperand2()->astOperand1();
}
static Token* getStepTok(Token* tok) {
if (!tok)
return nullptr;
if (Token::Match(tok, "%name% ("))
return getStepTok(tok->next());
if (tok->str() != "(")
return nullptr;
if (!Token::simpleMatch(tok->astOperand2(), ";"))
return nullptr;
if (!Token::simpleMatch(tok->astOperand2()->astOperand2(), ";"))
return nullptr;
return tok->astOperand2()->astOperand2()->astOperand2();
}
static Token* getStepTokFromEnd(Token* tok) {
if (!Token::simpleMatch(tok, "}"))
return nullptr;

View File

@ -692,8 +692,9 @@ static ValueFlow::Value execute(const Token* expr, ProgramMemory& pm)
void execute(const Token* expr, ProgramMemory* const programMemory, MathLib::bigint* result, bool* error)
{
ValueFlow::Value v = execute(expr, *programMemory);
if (!v.isIntValue() || v.isImpossible())
if (!v.isIntValue() || v.isImpossible()) {
if (error)
*error = true;
else
} else if (result)
*result = v.intvalue;
}

67
lib/valueflow.cpp Executable file → Normal file
View File

@ -1695,7 +1695,7 @@ static bool isConditionKnown(const Token* tok, bool then)
const Token* parent = tok->astParent();
while (parent && (parent->str() == op || parent->str() == "!"))
parent = parent->astParent();
return (parent && parent->str() == "(");
return Token::Match(parent, "(|;");
}
static const std::string& invertAssign(const std::string& assign)
@ -5221,7 +5221,69 @@ struct ConditionHandler {
}
}
if (top && Token::Match(top->previous(), "if|while (") && !top->previous()->isExpandedMacro()) {
if (!top)
return;
if (top->previous()->isExpandedMacro())
return;
if (!Token::Match(top->previous(), "if|while|for ("))
return;
if (top->previous()->str() == "for") {
if (!Token::Match(tok, "%comp%"))
return;
if (!Token::simpleMatch(tok->astParent(), ";"))
return;
const Token* stepTok = getStepTok(top);
if (cond.vartok->varId() == 0)
return;
if (!cond.vartok->variable())
return;
if (!Token::Match(stepTok, "++|--"))
return;
std::set<ValueFlow::Value::Bound> bounds;
for (const ValueFlow::Value& v : thenValues) {
if (v.bound != ValueFlow::Value::Bound::Point && v.isImpossible())
continue;
bounds.insert(v.bound);
}
if (Token::simpleMatch(stepTok, "++") && bounds.count(ValueFlow::Value::Bound::Lower) > 0)
return;
if (Token::simpleMatch(stepTok, "--") && bounds.count(ValueFlow::Value::Bound::Upper) > 0)
return;
const Token* childTok = tok->astOperand1();
if (!childTok)
childTok = tok->astOperand2();
if (!childTok)
return;
if (childTok->varId() != cond.vartok->varId())
return;
const Token* startBlock = top->link()->next();
if (isVariableChanged(startBlock,
startBlock->link(),
cond.vartok->varId(),
cond.vartok->variable()->isGlobal(),
settings,
tokenlist->isCPP()))
return;
// Check if condition in for loop is always false
const Token* initTok = getInitTok(top);
ProgramMemory pm;
execute(initTok, &pm, nullptr, nullptr);
MathLib::bigint result = 1;
execute(tok, &pm, &result, nullptr);
if (result == 0)
return;
// Remove condition since for condition is not redundant
for (std::list<ValueFlow::Value>* values : {&thenValues, &elseValues}) {
for (ValueFlow::Value& v : *values) {
v.condition = nullptr;
v.conditional = true;
}
}
}
// if astParent is "!" we need to invert codeblock
{
const Token* tok2 = tok;
@ -5359,7 +5421,6 @@ struct ConditionHandler {
return;
forward(after, scope->bodyEnd, cond.vartok, values, tokenlist, settings);
}
}
});
}
virtual ~ConditionHandler() {}

View File

@ -1317,7 +1317,8 @@ private:
" for (x = a; x < 50; x++) {}\n"
" b = x;\n"
"}\n";
ASSERT_EQUALS("3,After for loop, x has value 50\n",
ASSERT_EQUALS("3,Assuming that condition 'x<50' is not redundant\n"
"3,Assuming that condition 'x<50' is not redundant\n",
getErrorPathForX(code, 4U));
}
@ -6646,6 +6647,14 @@ private:
"}\n";
ASSERT_EQUALS(true, testValueOfX(code, 11U, "d", 0));
ASSERT_EQUALS(false, testValueOfXImpossible(code, 11U, 0));
code = "void f(int * p, int len) {\n"
" for(int x = 0; x < len; ++x) {\n"
" p[x] = 1;\n"
" }\n"
"}\n";
ASSERT_EQUALS(true, testValueOfX(code, 3U, "len", -1));
ASSERT_EQUALS(true, testValueOfXImpossible(code, 3U, "len", 0));
}
void valueFlowSymbolicIdentity()