Fixed #8221 (ValueFlow: value for static variable that is not written)

This commit is contained in:
Daniel Marjamäki 2017-09-15 15:58:19 +02:00
parent d79762cfc3
commit 1dbcba4dd6
2 changed files with 96 additions and 2 deletions

View File

@ -931,6 +931,59 @@ static void valueFlowOppositeCondition(SymbolDatabase *symboldatabase, const Set
}
}
static void valueFlowGlobalStaticVar(TokenList *tokenList, const Settings *settings)
{
// Get variable values...
std::map<const Variable *, ValueFlow::Value> vars;
for (const Token *tok = tokenList->front(); tok; tok = tok->next()) {
if (!tok->variable())
continue;
// Initialization...
if (tok == tok->variable()->nameToken() &&
tok->variable()->isStatic() &&
!tok->variable()->isConst() &&
tok->valueType() &&
tok->valueType()->isIntegral() &&
tok->valueType()->pointer == 0 &&
tok->valueType()->constness == 0 &&
Token::Match(tok, "%name% =") &&
tok->next()->astOperand2() &&
tok->next()->astOperand2()->hasKnownIntValue()) {
vars[tok->variable()] = tok->next()->astOperand2()->values().front();
} else {
// If variable is written anywhere in TU then remove it from vars
if (!tok->astParent())
continue;
if (Token::Match(tok->astParent(), "++|--|&") && !tok->astParent()->astOperand2())
vars.erase(tok->variable());
else if (tok->astParent()->str() == "=") {
if (tok == tok->astParent()->astOperand1())
vars.erase(tok->variable());
else if (tokenList->isCPP() && Token::Match(tok->astParent()->tokAt(-2), "& %name% ="))
vars.erase(tok->variable());
} else if (tokenList->isCPP() && tok->astParent()->str() == ">>") {
const Token *lhs = tok->astParent();
while (Token::simpleMatch(lhs->astParent(), ">>"))
lhs = lhs->astParent();
lhs = lhs->astOperand1();
if (!lhs || !lhs->valueType() || !lhs->valueType()->isIntegral())
vars.erase(tok->variable());
} else if (Token::Match(tok->astParent(), "[(,]"))
vars.erase(tok->variable());
}
}
// Set values..
for (Token *tok = tokenList->front(); tok; tok = tok->next()) {
if (!tok->variable())
continue;
std::map<const Variable *, ValueFlow::Value>::const_iterator var = vars.find(tok->variable());
if (var == vars.end())
continue;
setTokenValue(tok, var->second, settings);
}
}
static void valueFlowReverse(TokenList *tokenlist,
Token *tok,
const Token * const varToken,
@ -3169,6 +3222,7 @@ void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase,
valueFlowNumber(tokenlist);
valueFlowString(tokenlist);
valueFlowArray(tokenlist);
valueFlowGlobalStaticVar(tokenlist, settings);
valueFlowPointerAlias(tokenlist);
valueFlowFunctionReturn(tokenlist, errorLogger);
valueFlowBitAnd(tokenlist);

View File

@ -94,6 +94,8 @@ private:
TEST_CASE(valueFlowGlobalVar);
TEST_CASE(valueFlowGlobalStaticVar);
TEST_CASE(valueFlowInlineAssembly);
TEST_CASE(valueFlowUninit);
@ -2472,11 +2474,11 @@ private:
code = "void f() {\n"
" static int x = 0;\n"
" return x + 1;\n" // <- possible value
" return x + 1;\n" // <- known value
"}\n";
value = valueOfTok(code, "+");
ASSERT_EQUALS(1, value.intvalue);
ASSERT(value.isPossible());
ASSERT(value.isKnown());
code = "void f() {\n"
" int x = 0;\n"
@ -2596,6 +2598,44 @@ private:
ASSERT_EQUALS(false, testValueOfX(code, 5U, 42));
}
void valueFlowGlobalStaticVar() {
const char *code;
code = "static int x = 321;\n"
"void f() {\n"
" a = x;\n"
"}";
ASSERT_EQUALS(true, testValueOfX(code, 3U, 321));
code = "static int x = 321;\n"
"void f() {\n"
" a = x;\n"
"}"
"void other() { x=a; }\n";
ASSERT_EQUALS(false, testValueOfX(code, 3U, 321));
code = "static int x = 321;\n"
"void f() {\n"
" a = x;\n"
"}"
"void other() { p = &x; }\n";
ASSERT_EQUALS(false, testValueOfX(code, 3U, 321));
code = "static int x = 321;\n"
"void f() {\n"
" a = x;\n"
"}"
"void other() { x++; }\n";
ASSERT_EQUALS(false, testValueOfX(code, 3U, 321));
code = "static int x = 321;\n"
"void f() {\n"
" a = x;\n"
"}"
"void other() { foo(x); }\n";
ASSERT_EQUALS(false, testValueOfX(code, 3U, 321));
}
void valueFlowInlineAssembly() {
const char* code = "void f() {\n"
" int x = 42;\n"