Fixed #3948 (False positive: variable not initialised - used in multi-condition if-clause)

This commit is contained in:
Daniel Marjamäki 2015-11-19 13:09:45 +01:00
parent 87d3ed91ab
commit 4d3e231bd0
2 changed files with 101 additions and 32 deletions

View File

@ -193,42 +193,84 @@ static bool operator!=(const VariableValue & v, MathLib::bigint i)
static void conditionAlwaysTrueOrFalse(const Token *tok, const std::map<unsigned int, VariableValue> &variableValue, bool *alwaysTrue, bool *alwaysFalse)
{
assert(Token::simpleMatch(tok, "if ("));
if (!tok)
return;
const Token *vartok = tok->tokAt(2);
const bool NOT(vartok->str() == "!");
if (NOT)
vartok = vartok->next();
if (tok->isName() || tok->str() == ".") {
while (tok && tok->str() == ".")
tok = tok->astOperand2();
const std::map<unsigned int, VariableValue>::const_iterator it = variableValue.find(tok ? tok->varId() : ~0U);
if (it != variableValue.end()) {
*alwaysTrue = (it->second != 0LL);
*alwaysFalse = (it->second == 0LL);
}
}
while (Token::Match(vartok, "%name% . %name%"))
vartok = vartok->tokAt(2);
else if (tok->isComparisonOp()) {
const Token *vartok, *numtok;
if (tok->astOperand2() && tok->astOperand2()->isNumber()) {
vartok = tok->astOperand1();
numtok = tok->astOperand2();
} else if (tok->astOperand1() && tok->astOperand1()->isNumber()) {
vartok = tok->astOperand2();
numtok = tok->astOperand1();
} else {
return;
}
std::map<unsigned int, VariableValue>::const_iterator it = variableValue.find(vartok->varId());
while (vartok && vartok->str() == ".")
vartok = vartok->astOperand2();
const std::map<unsigned int, VariableValue>::const_iterator it = variableValue.find(vartok ? vartok->varId() : ~0U);
if (it == variableValue.end())
return;
// always true
if (Token::Match(vartok, "%name% %oror%|)")) {
if (NOT)
*alwaysTrue = bool(it->second == 0);
if (tok->str() == "==")
*alwaysTrue = (it->second == MathLib::toLongNumber(numtok->str()));
else if (tok->str() == "!=")
*alwaysTrue = (it->second != MathLib::toLongNumber(numtok->str()));
else
*alwaysTrue = bool(it->second != 0);
} else if (Token::Match(vartok, "%name% == %num% %or%|)")) {
*alwaysTrue = bool(it->second == MathLib::toLongNumber(vartok->strAt(2)));
} else if (Token::Match(vartok, "%name% != %num% %or%|)")) {
*alwaysTrue = bool(it->second != MathLib::toLongNumber(vartok->strAt(2)));
return;
*alwaysFalse = !(*alwaysTrue);
}
// always false
if (Token::Match(vartok, "%name% &&|)")) {
if (NOT)
*alwaysFalse = bool(it->second != 0);
else
*alwaysFalse = bool(it->second == 0);
} else if (Token::Match(vartok, "%name% == %num% &&|)")) {
*alwaysFalse = bool(it->second != MathLib::toLongNumber(vartok->strAt(2)));
} else if (Token::Match(vartok, "%name% != %num% &&|)")) {
*alwaysFalse = bool(it->second == MathLib::toLongNumber(vartok->strAt(2)));
else if (tok->str() == "!") {
bool t=false,f=false;
conditionAlwaysTrueOrFalse(tok->astOperand1(), variableValue, &t, &f);
if (t||f) {
*alwaysTrue = !t;
*alwaysFalse = !f;
}
}
else if (tok->str() == "||") {
bool t1=false, f1=false;
conditionAlwaysTrueOrFalse(tok->astOperand1(), variableValue, &t1, &f1);
bool t2=false, f2=false;
if (!t1)
conditionAlwaysTrueOrFalse(tok->astOperand1(), variableValue, &t2, &f2);
if (t1 || t2) {
*alwaysTrue = true;
*alwaysFalse = false;
} else if (f1 && f2) {
*alwaysTrue = false;
*alwaysFalse = true;
}
}
else if (tok->str() == "&&") {
bool t1=false, f1=false;
conditionAlwaysTrueOrFalse(tok->astOperand1(), variableValue, &t1, &f1);
bool t2=false, f2=false;
if (!f1)
conditionAlwaysTrueOrFalse(tok->astOperand1(), variableValue, &t2, &f2);
if (t1 && t2) {
*alwaysTrue = true;
*alwaysFalse = false;
} else if (f1 && f2) {
*alwaysTrue = false;
*alwaysFalse = true;
}
}
}
@ -305,7 +347,7 @@ bool CheckUninitVar::checkScopeForVariable(const Token *tok, const Variable& var
bool alwaysTrue = false;
bool alwaysFalse = false;
conditionAlwaysTrueOrFalse(tok, variableValue, &alwaysTrue, &alwaysFalse);
conditionAlwaysTrueOrFalse(tok->next()->astOperand2(), variableValue, &alwaysTrue, &alwaysFalse);
// initialization / usage in condition..
if (!alwaysTrue && checkIfForWhileHead(tok->next(), var, suppressErrors, bool(number_of_if == 0), *alloc, membervar))
@ -324,6 +366,25 @@ bool CheckUninitVar::checkScopeForVariable(const Token *tok, const Variable& var
condVarId = condVarTok->varId();
condVarValue = !VariableValue(0);
}
} else if (Token::simpleMatch(tok, "if (") && Token::Match(tok->next()->astOperand2(), "==|!=")) {
const Token *condition = tok->next()->astOperand2();
const Token *lhs = condition->astOperand1();
const Token *rhs = condition->astOperand2();
const Token *vartok = rhs && rhs->isNumber() ? lhs : rhs;
const Token *numtok = rhs && rhs->isNumber() ? rhs : lhs;
while (Token::simpleMatch(vartok, "."))
vartok = vartok->astOperand2();
if (vartok && vartok->varId() && numtok) {
std::map<unsigned int,VariableValue>::const_iterator it = variableValue.find(vartok->varId());
if (it != variableValue.end() && it->second != MathLib::toLongNumber(numtok->str()))
return true; // this scope is not fully analysed => return true
else {
condVarId = vartok->varId();
condVarValue = VariableValue(MathLib::toLongNumber(numtok->str()));
if (condition->str() == "!=")
condVarValue = !condVarValue;
}
}
}
// goto the {

View File

@ -2394,6 +2394,14 @@ private:
"}");
ASSERT_EQUALS("", errout.str());
checkUninitVar("void f(int x) {\n" // #3948
" int value;\n"
" if (x !=-1)\n"
" value = getvalue();\n"
" if (x == -1 || value > 300) {}\n"
"}");
ASSERT_EQUALS("", errout.str());
checkUninitVar("static int x;" // #4773
"int f() {\n"
" int y;\n"