Fixed #4511 (False positive: uninitialized struct member)
This commit is contained in:
parent
3b08b410a2
commit
ae43b12bf1
|
@ -1102,6 +1102,47 @@ void CheckUninitVar::checkScope(const Scope* scope)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void conditionAlwaysTrueOrFalse(const Token *tok, const std::map<unsigned int, int> &variableValue, bool *alwaysTrue, bool *alwaysFalse)
|
||||||
|
{
|
||||||
|
assert(Token::Match(tok, "if ("));
|
||||||
|
|
||||||
|
const Token *vartok = tok->tokAt(2);
|
||||||
|
const bool NOT(vartok->str() == "!");
|
||||||
|
if (NOT)
|
||||||
|
vartok = vartok->next();
|
||||||
|
|
||||||
|
while (Token::Match(vartok, "%var% . %var%"))
|
||||||
|
vartok = vartok->tokAt(2);
|
||||||
|
|
||||||
|
std::map<unsigned int, int>::const_iterator it = variableValue.find(vartok->varId());
|
||||||
|
if (it == variableValue.end())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// always true
|
||||||
|
if (Token::Match(vartok, "%var% %oror%|)")) {
|
||||||
|
if (NOT)
|
||||||
|
*alwaysTrue = bool(it->second == 0);
|
||||||
|
else
|
||||||
|
*alwaysTrue = bool(it->second != 0);
|
||||||
|
} else if (Token::Match(vartok, "%var% == %num% %or%|)")) {
|
||||||
|
*alwaysTrue = bool(it->second == MathLib::toLongNumber(vartok->strAt(2)));
|
||||||
|
} else if (Token::Match(vartok, "%var% != %num% %or%|)")) {
|
||||||
|
*alwaysTrue = bool(it->second != MathLib::toLongNumber(vartok->strAt(2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// always false
|
||||||
|
if (Token::Match(vartok, "%var% &&|)")) {
|
||||||
|
if (NOT)
|
||||||
|
*alwaysFalse = bool(it->second == 0);
|
||||||
|
else
|
||||||
|
*alwaysFalse = bool(it->second != 0);
|
||||||
|
} else if (Token::Match(vartok, "%var% == %num% &&|)")) {
|
||||||
|
*alwaysFalse = bool(it->second != MathLib::toLongNumber(vartok->strAt(2)));
|
||||||
|
} else if (Token::Match(vartok, "%var% != %num% &&|)")) {
|
||||||
|
*alwaysFalse = bool(it->second == MathLib::toLongNumber(vartok->strAt(2)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool CheckUninitVar::checkScopeForVariable(const Scope* scope, const Token *tok, const Variable& var, bool * const possibleInit, bool * const noreturn, const std::string &membervar)
|
bool CheckUninitVar::checkScopeForVariable(const Scope* scope, const Token *tok, const Variable& var, bool * const possibleInit, bool * const noreturn, const std::string &membervar)
|
||||||
{
|
{
|
||||||
const bool suppressErrors(possibleInit && *possibleInit);
|
const bool suppressErrors(possibleInit && *possibleInit);
|
||||||
|
@ -1143,18 +1184,9 @@ bool CheckUninitVar::checkScopeForVariable(const Scope* scope, const Token *tok,
|
||||||
// Inner scope..
|
// Inner scope..
|
||||||
if (Token::simpleMatch(tok, "if (")) {
|
if (Token::simpleMatch(tok, "if (")) {
|
||||||
bool alwaysTrue = false;
|
bool alwaysTrue = false;
|
||||||
|
bool alwaysFalse = false;
|
||||||
|
|
||||||
// known variable in condition..
|
conditionAlwaysTrueOrFalse(tok, variableValue, &alwaysTrue, &alwaysFalse);
|
||||||
if (Token::Match(tok, "if ( !| %var% %oror%")) {
|
|
||||||
const Token *vartok = tok->tokAt(2);
|
|
||||||
if (vartok->str() == "!")
|
|
||||||
vartok = vartok->next();
|
|
||||||
std::map<unsigned int, int>::const_iterator it = variableValue.find(vartok->varId());
|
|
||||||
if (tok->strAt(2) == "!")
|
|
||||||
alwaysTrue = bool(it != variableValue.end() && it->second == 0);
|
|
||||||
else
|
|
||||||
alwaysTrue = bool(it != variableValue.end() && it->second != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// initialization / usage in condition..
|
// initialization / usage in condition..
|
||||||
if (!alwaysTrue && checkIfForWhileHead(scope, tok->next(), var, suppressErrors, bool(number_of_if == 0), membervar))
|
if (!alwaysTrue && checkIfForWhileHead(scope, tok->next(), var, suppressErrors, bool(number_of_if == 0), membervar))
|
||||||
|
@ -1180,7 +1212,7 @@ bool CheckUninitVar::checkScopeForVariable(const Scope* scope, const Token *tok,
|
||||||
if (tok->str() == "{") {
|
if (tok->str() == "{") {
|
||||||
bool possibleInitIf(number_of_if > 0 || suppressErrors);
|
bool possibleInitIf(number_of_if > 0 || suppressErrors);
|
||||||
bool noreturnIf = false;
|
bool noreturnIf = false;
|
||||||
const bool initif = !alwaysTrue && checkScopeForVariable(scope, tok->next(), var, &possibleInitIf, &noreturnIf, membervar);
|
const bool initif = !alwaysFalse && !alwaysTrue && checkScopeForVariable(scope, tok->next(), var, &possibleInitIf, &noreturnIf, membervar);
|
||||||
|
|
||||||
// bail out for such code:
|
// bail out for such code:
|
||||||
// if (a) x=0; // conditional initialization
|
// if (a) x=0; // conditional initialization
|
||||||
|
@ -1202,9 +1234,9 @@ bool CheckUninitVar::checkScopeForVariable(const Scope* scope, const Token *tok,
|
||||||
std::map<unsigned int, int> varValueIf;
|
std::map<unsigned int, int> varValueIf;
|
||||||
if (!initif) {
|
if (!initif) {
|
||||||
for (const Token *tok2 = tok; tok2 && tok2 != tok->link(); tok2 = tok2->next()) {
|
for (const Token *tok2 = tok; tok2 && tok2 != tok->link(); tok2 = tok2->next()) {
|
||||||
if (Token::Match(tok2, "[;{}] %var% = - %var% ;"))
|
if (Token::Match(tok2, "[;{}.] %var% = - %var% ;"))
|
||||||
varValueIf[tok2->next()->varId()] = NOT_ZERO;
|
varValueIf[tok2->next()->varId()] = NOT_ZERO;
|
||||||
if (Token::Match(tok2, "[;{}] %var% = %num% ;"))
|
if (Token::Match(tok2, "[;{}.] %var% = %num% ;"))
|
||||||
varValueIf[tok2->next()->varId()] = (int)MathLib::toLongNumber(tok2->strAt(3));
|
varValueIf[tok2->next()->varId()] = (int)MathLib::toLongNumber(tok2->strAt(3));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1232,9 +1264,9 @@ bool CheckUninitVar::checkScopeForVariable(const Scope* scope, const Token *tok,
|
||||||
std::map<unsigned int, int> varValueElse;
|
std::map<unsigned int, int> varValueElse;
|
||||||
if (!initelse) {
|
if (!initelse) {
|
||||||
for (const Token *tok2 = tok; tok2 && tok2 != tok->link(); tok2 = tok2->next()) {
|
for (const Token *tok2 = tok; tok2 && tok2 != tok->link(); tok2 = tok2->next()) {
|
||||||
if (Token::Match(tok2, "[;{}] %var% = - %var% ;"))
|
if (Token::Match(tok2, "[;{}.] %var% = - %var% ;"))
|
||||||
varValueElse[tok2->next()->varId()] = NOT_ZERO;
|
varValueElse[tok2->next()->varId()] = NOT_ZERO;
|
||||||
if (Token::Match(tok2, "[;{}] %var% = %num% ;"))
|
if (Token::Match(tok2, "[;{}.] %var% = %num% ;"))
|
||||||
varValueElse[tok2->next()->varId()] = (int)MathLib::toLongNumber(tok2->strAt(3));
|
varValueElse[tok2->next()->varId()] = (int)MathLib::toLongNumber(tok2->strAt(3));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2230,6 +2230,15 @@ private:
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
checkUninitVar2("struct AB { int a; int b; };\n"
|
||||||
|
"void f(void) {\n"
|
||||||
|
" struct AB ab;\n"
|
||||||
|
" if (x) ab = getAB();\n"
|
||||||
|
" else ab.a = 0;\n"
|
||||||
|
" if (ab.a == 1) b = ab.b;\n"
|
||||||
|
"}", "test.c");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
// asm
|
// asm
|
||||||
checkUninitVar2("void f() {\n"
|
checkUninitVar2("void f() {\n"
|
||||||
" int x;\n"
|
" int x;\n"
|
||||||
|
|
Loading…
Reference in New Issue