Fix reverse analysis when modifying variable with function (#4800)

This commit is contained in:
Paul Fultz II 2023-02-23 11:04:16 -06:00 committed by GitHub
parent fb88883813
commit 91d2526c41
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 29 additions and 16 deletions

View File

@ -56,12 +56,12 @@ struct ReverseTraversal {
bool update(Token* tok) { bool update(Token* tok) {
Analyzer::Action action = analyzer->analyze(tok, Analyzer::Direction::Reverse); Analyzer::Action action = analyzer->analyze(tok, Analyzer::Direction::Reverse);
if (!action.isNone())
analyzer->update(tok, action, Analyzer::Direction::Reverse);
if (action.isInconclusive() && !analyzer->lowerToInconclusive()) if (action.isInconclusive() && !analyzer->lowerToInconclusive())
return false; return false;
if (action.isInvalid()) if (action.isInvalid())
return false; return false;
if (!action.isNone())
analyzer->update(tok, action, Analyzer::Direction::Reverse);
return true; return true;
} }

View File

@ -7751,11 +7751,10 @@ struct ContainerExpressionAnalyzer : ExpressionAnalyzer {
return tok->exprId() == expr->exprId() || (astIsIterator(tok) && isAliasOf(tok, expr->exprId())); return tok->exprId() == expr->exprId() || (astIsIterator(tok) && isAliasOf(tok, expr->exprId()));
} }
Action isWritable(const Token* tok, Direction d) const override { Action isWritable(const Token* tok, Direction /*d*/) const override
{
if (astIsIterator(tok)) if (astIsIterator(tok))
return Action::None; return Action::None;
if (d == Direction::Reverse)
return Action::None;
if (!getValue(tok)) if (!getValue(tok))
return Action::None; return Action::None;
if (!tok->valueType()) if (!tok->valueType())
@ -7788,8 +7787,6 @@ struct ContainerExpressionAnalyzer : ExpressionAnalyzer {
} }
void writeValue(ValueFlow::Value* val, const Token* tok, Direction d) const override { void writeValue(ValueFlow::Value* val, const Token* tok, Direction d) const override {
if (d == Direction::Reverse)
return;
if (!val) if (!val)
return; return;
if (!tok->astParent()) if (!tok->astParent())
@ -7800,26 +7797,31 @@ struct ContainerExpressionAnalyzer : ExpressionAnalyzer {
return; return;
const Token* parent = tok->astParent(); const Token* parent = tok->astParent();
const Library::Container* container = getLibraryContainer(tok); const Library::Container* container = getLibraryContainer(tok);
int n = 0;
if (container->stdStringLike && Token::simpleMatch(parent, "+=") && parent->astOperand2()) { if (container->stdStringLike && Token::simpleMatch(parent, "+=") && parent->astOperand2()) {
const Token* rhs = parent->astOperand2(); const Token* rhs = parent->astOperand2();
const Library::Container* rhsContainer = getLibraryContainer(rhs); const Library::Container* rhsContainer = getLibraryContainer(rhs);
if (rhs->tokType() == Token::eString) if (rhs->tokType() == Token::eString)
val->intvalue += Token::getStrLength(rhs); n = Token::getStrLength(rhs);
else if (rhsContainer && rhsContainer->stdStringLike) { else if (rhsContainer && rhsContainer->stdStringLike) {
for (const ValueFlow::Value &rhsval : rhs->values()) { auto it = std::find_if(rhs->values().begin(), rhs->values().end(), [&](const ValueFlow::Value& rhsval) {
if (rhsval.isKnown() && rhsval.isContainerSizeValue()) { return rhsval.isKnown() && rhsval.isContainerSizeValue();
val->intvalue += rhsval.intvalue; });
} if (it != rhs->values().end())
} n = it->intvalue;
} }
} else if (astIsLHS(tok) && Token::Match(tok->astParent(), ". %name% (")) { } else if (astIsLHS(tok) && Token::Match(tok->astParent(), ". %name% (")) {
const Library::Container::Action action = container->getAction(tok->astParent()->strAt(1)); const Library::Container::Action action = container->getAction(tok->astParent()->strAt(1));
if (action == Library::Container::Action::PUSH) if (action == Library::Container::Action::PUSH)
val->intvalue++; n = 1;
if (action == Library::Container::Action::POP) if (action == Library::Container::Action::POP)
val->intvalue--; n = -1;
} }
if (d == Direction::Reverse)
val->intvalue -= n;
else
val->intvalue += n;
} }
int getIndirect(const Token* tok) const override int getIndirect(const Token* tok) const override

View File

@ -1529,6 +1529,7 @@ private:
" if (x == 4);\n" " if (x == 4);\n"
"}"; "}";
ASSERT_EQUALS(true, testValueOfX(code, 2U, 2)); ASSERT_EQUALS(true, testValueOfX(code, 2U, 2));
ASSERT_EQUALS(true, testValueOfX(code, 3U, 2));
code = "void f(int x) {\n" code = "void f(int x) {\n"
" a = x;\n" " a = x;\n"
@ -1536,6 +1537,7 @@ private:
" if (x == 4);\n" " if (x == 4);\n"
"}"; "}";
ASSERT_EQUALS(true, testValueOfX(code, 2U, 6)); ASSERT_EQUALS(true, testValueOfX(code, 2U, 6));
ASSERT_EQUALS(true, testValueOfX(code, 3U, 6));
code = "void f(int x) {\n" code = "void f(int x) {\n"
" a = x;\n" " a = x;\n"
@ -1543,6 +1545,7 @@ private:
" if (x == 42);\n" " if (x == 42);\n"
"}"; "}";
ASSERT_EQUALS(true, testValueOfX(code, 2U, 21)); ASSERT_EQUALS(true, testValueOfX(code, 2U, 21));
ASSERT_EQUALS(true, testValueOfX(code, 3U, 21));
code = "void f(int x) {\n" code = "void f(int x) {\n"
" a = x;\n" " a = x;\n"
@ -1550,6 +1553,7 @@ private:
" if (x == 42);\n" " if (x == 42);\n"
"}"; "}";
ASSERT_EQUALS(true, testValueOfX(code, 2U, 210)); ASSERT_EQUALS(true, testValueOfX(code, 2U, 210));
ASSERT_EQUALS(true, testValueOfX(code, 3U, 210));
// bailout: assignment // bailout: assignment
bailout("void f(int x) {\n" bailout("void f(int x) {\n"
@ -1612,6 +1616,13 @@ private:
" if (x) {}\n" " if (x) {}\n"
"}"; "}";
ASSERT_EQUALS(false, testValueOfX(code, 3U, 0)); ASSERT_EQUALS(false, testValueOfX(code, 3U, 0));
code = "void g(int&);"
"void f(int x) {\n"
" g(x);\n"
" if (x == 5);\n"
"}";
ASSERT_EQUALS(false, testValueOfX(code, 2U, 5));
} }
void valueFlowBeforeConditionLoop() { // while, for, do-while void valueFlowBeforeConditionLoop() { // while, for, do-while
@ -5666,7 +5677,7 @@ private:
" ints.pop_back();\n" " ints.pop_back();\n"
" if (ints.empty()) {}\n" " if (ints.empty()) {}\n"
"}"; "}";
ASSERT(tokenValues(code, "ints . front").empty()); ASSERT_EQUALS("", isPossibleContainerSizeValue(tokenValues(code, "ints . front"), 1));
code = "void f(std::vector<int> v) {\n" code = "void f(std::vector<int> v) {\n"
" v[10] = 0;\n" // <- container size can be 10 " v[10] = 0;\n" // <- container size can be 10