diff --git a/lib/forwardanalyzer.cpp b/lib/forwardanalyzer.cpp index 156927709..fd9d68a07 100644 --- a/lib/forwardanalyzer.cpp +++ b/lib/forwardanalyzer.cpp @@ -575,7 +575,23 @@ struct ForwardTraversal { tok = nextAfterAstRightmostLeaf(assignTok); if (!tok) return Break(); - } else if (tok->str() == "break") { + } else if (Token::simpleMatch(tok, ") {") && Token::Match(tok->link()->previous(), "for|while (")) { + // In the middle of a loop structure so bail + return Break(Analyzer::Terminate::Bail); + } else if (tok->str() == ";" && tok->astParent()) { + Token* top = tok->astTop(); + if (top && Token::Match(top->previous(), "for|while (") && Token::simpleMatch(top->link(), ") {")) { + Token* endCond = top->link(); + Token* endBlock = endCond->linkAt(1); + Token* condTok = getCondTok(top); + Token* stepTok = getStepTok(top); + // The semicolon should belong to the initTok otherwise something went wrong, so just bail + if (tok->astOperand2() != condTok && !Token::simpleMatch(tok->astOperand2(), ";")) + return Break(Analyzer::Terminate::Bail); + if (updateLoop(end, endBlock, condTok, nullptr, stepTok) == Progress::Break) + return Break(); + } + } else if (tok->str() == "break") { const Token *scopeEndToken = findNextTokenFromBreak(tok); if (!scopeEndToken) return Break(); @@ -640,7 +656,8 @@ struct ForwardTraversal { } else if (Token::simpleMatch(tok->next(), "else {")) { tok = tok->linkAt(2); } - } else if (tok->isControlFlowKeyword() && Token::Match(tok, "if|while|for (") && Token::simpleMatch(tok->next()->link(), ") {")) { + } else if (tok->isControlFlowKeyword() && Token::Match(tok, "if|while|for (") && + Token::simpleMatch(tok->next()->link(), ") {")) { Token* endCond = tok->next()->link(); Token* endBlock = endCond->next()->link(); Token* condTok = getCondTok(tok); diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index ac9f6c364..bd52004f3 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -105,6 +105,7 @@ #include #include #include +#include #include #include #include @@ -918,9 +919,9 @@ static void setTokenValue(Token* tok, const double floatValue1 = value1.isFloatValue() ? value1.floatValue : value1.intvalue; const double floatValue2 = value2.isFloatValue() ? value2.floatValue : value2.intvalue; const MathLib::bigint intValue1 = - value1.isFloatValue() ? static_cast(value1.floatValue) : value1.intvalue; + value1.isFloatValue() ? std::llround(value1.floatValue) : value1.intvalue; const MathLib::bigint intValue2 = - value2.isFloatValue() ? static_cast(value2.floatValue) : value2.intvalue; + value2.isFloatValue() ? std::llround(value2.floatValue) : value2.intvalue; if ((value1.isFloatValue() || value2.isFloatValue()) && Token::Match(parent, "&|^|%|<<|>>|==|!=|%or%")) continue; if (Token::Match(parent, "==|!=")) { @@ -5444,7 +5445,10 @@ static void valueFlowAfterAssign(TokenList *tokenlist, SymbolDatabase* symboldat std::unordered_map> backAssigns; for (Token* tok = const_cast(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) { // Assignment - if ((tok->str() != "=" && !isVariableInit(tok)) || (tok->astParent())) + if (tok->str() != "=" && !isVariableInit(tok)) + continue; + + if (tok->astParent() && !(tok->astParent()->str() == ";" && astIsLHS(tok))) continue; // Lhs should be a variable diff --git a/test/testbufferoverrun.cpp b/test/testbufferoverrun.cpp index 18a1f744d..aa62c26b8 100644 --- a/test/testbufferoverrun.cpp +++ b/test/testbufferoverrun.cpp @@ -2380,7 +2380,8 @@ private: " some_condition ? 0 : a[i-1];\n" " }\n" "}"); - TODO_ASSERT_EQUALS("[test.cpp:4]: (error) Array index -1 is out of bounds.\n", "", errout.str()); + ASSERT_EQUALS("[test.cpp:4]: (error) Array 'a[10]' accessed at index -1, which is out of bounds.\n", + errout.str()); check("void f() {\n" " int a[10];\n" diff --git a/test/teststl.cpp b/test/teststl.cpp index 35f0c3888..b4d686229 100644 --- a/test/teststl.cpp +++ b/test/teststl.cpp @@ -2518,13 +2518,16 @@ private: " {\n" " if (a) {\n" " if (b)\n" - " foo.erase(it);\n" + " foo.erase(it);\n" // <- TODO: erase shound't cause inconclusive valueflow " else\n" " *it = 0;\n" " }\n" " }\n" "}"); - ASSERT_EQUALS("[test.cpp:5] -> [test.cpp:7] -> [test.cpp:8] -> [test.cpp:8] -> [test.cpp:7] -> [test.cpp:5] -> [test.cpp:9] -> [test.cpp:3] -> [test.cpp:5]: (error) Using iterator to local container 'foo' that may be invalid.\n", errout.str()); + TODO_ASSERT_EQUALS( + "[test.cpp:5] -> [test.cpp:7] -> [test.cpp:8] -> [test.cpp:8] -> [test.cpp:7] -> [test.cpp:5] -> [test.cpp:9] -> [test.cpp:3] -> [test.cpp:5]: (error) Using iterator to local container 'foo' that may be invalid.\n", + "[test.cpp:5] -> [test.cpp:7] -> [test.cpp:8] -> [test.cpp:8] -> [test.cpp:7] -> [test.cpp:5] -> [test.cpp:9] -> [test.cpp:3] -> [test.cpp:5]: (error, inconclusive) Using iterator to local container 'foo' that may be invalid.\n", + errout.str()); } void eraseGoto() { diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 3d48a01fd..27c06d438 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -2603,6 +2603,23 @@ private: " }\n" "};"; ASSERT_EQUALS(true, testValueOfX(code, 6U, 10)); + + code = "void f(int i) {\n" + " if (i == 3) {}\n" + " for(int x = i;\n" + " x;\n" + " x++) {}\n" + "}\n"; + ASSERT_EQUALS(true, testValueOfX(code, 4U, 3)); + ASSERT_EQUALS(false, testValueOfXKnown(code, 4U, 3)); + + code = "void f() {\n" + " for(int x = 3;\n" + " x;\n" + " x++) {}\n" + "}\n"; + ASSERT_EQUALS(true, testValueOfX(code, 4U, 3)); + ASSERT_EQUALS(false, testValueOfXKnown(code, 4U, 3)); } void valueFlowAfterSwap() @@ -3920,7 +3937,10 @@ private: "void foo(struct S s) {\n" " for (s.x = 0; s.x < 127; s.x++) {}\n" "}"; - values = removeImpossible(tokenValues(code, "<")); // TODO: comparison can be true or false + values = removeImpossible(tokenValues(code, "<")); + values.remove_if([&](const ValueFlow::Value& v) { + return !v.isKnown(); + }); ASSERT_EQUALS(true, values.empty()); } @@ -4062,7 +4082,7 @@ private: " for (int x = 0; x < 10 && y = do_something();)\n" " x;\n" "}"; - TODO_ASSERT_EQUALS(true, false, testValueOfX(code, 4U, 0)); + ASSERT_EQUALS(true, testValueOfX(code, 4U, 0)); code = "void f() {\n" " int x,y;\n"