Tweaks in uninitvar, small steps to make it possible to remove the ExecutionPath

This commit is contained in:
Daniel Marjamäki 2015-07-22 20:31:58 +02:00
parent 75f922e799
commit 42ed436e9d
2 changed files with 37 additions and 16 deletions

View File

@ -1200,6 +1200,17 @@ static void conditionAlwaysTrueOrFalse(const Token *tok, const std::map<unsigned
}
}
static bool isVariableUsed(const Token *tok, const Variable& var)
{
if (!tok)
return false;
if (tok->str() == "&" && !tok->astOperand2())
return false;
if (Token::Match(tok, "%cop%|:"))
return isVariableUsed(tok->astOperand1(),var) || isVariableUsed(tok->astOperand2(),var);
return (tok->varId() == var.declarationId());
}
bool CheckUninitVar::checkScopeForVariable(const Token *tok, const Variable& var, bool * const possibleInit, bool * const noreturn, Alloc* const alloc, const std::string &membervar)
{
const bool suppressErrors(possibleInit && *possibleInit);
@ -1446,8 +1457,18 @@ bool CheckUninitVar::checkScopeForVariable(const Token *tok, const Variable& var
return true;
}
// bailout on ternary operator. TODO: This can be solved much better. For example, if the variable is not accessed in the branches of the ternary operator, we could just continue.
if (tok->str() == "?") {
const bool used1 = isVariableUsed(tok->astOperand2()->astOperand1(), var);
const bool used0 = isVariableUsed(tok->astOperand2()->astOperand2(), var);
const bool err = (number_of_if == 0) ? (used1 || used0) : (used1 && used0);
if (err) {
if (*alloc != NO_ALLOC)
uninitdataError(tok, var.nameToken()->str());
else
uninitvarError(tok, var.nameToken()->str());
}
// Todo: skip expression if there is no error
return true;
}
@ -1481,11 +1502,18 @@ bool CheckUninitVar::checkScopeForVariable(const Token *tok, const Variable& var
else if (Token::Match(tok, "sizeof|typeof|offsetof|decltype ("))
tok = tok->linkAt(1);
else if (tok->str() == "?")
// TODO: False negatives when "?:" is used.
// Fix the tokenizer and then remove this bailout.
// The tokenizer should replace "return x?y:z;" with "if(x)return y;return z;"
else if (tok->str() == "?") {
const bool used1 = isVariableUsed(tok->astOperand2()->astOperand1(), var);
const bool used0 = isVariableUsed(tok->astOperand2()->astOperand2(), var);
const bool err = (number_of_if == 0) ? (used1 || used0) : (used1 && used0);
if (err) {
if (*alloc != NO_ALLOC)
uninitdataError(tok, var.nameToken()->str());
else
uninitvarError(tok, var.nameToken()->str());
}
return true;
}
tok = tok->next();
}
@ -1888,6 +1916,8 @@ int CheckUninitVar::isFunctionParUsage(const Token *vartok, bool pointer, Alloc
return alloc == NO_ALLOC;
} else {
const bool isnullbad = _settings->library.isnullargbad(start->previous(), argumentNumber + 1);
if (!address && isnullbad && alloc == NO_ALLOC)
return true;
const bool isuninitbad = _settings->library.isuninitargbad(start->previous(), argumentNumber + 1);
if (alloc != NO_ALLOC)
return isnullbad && isuninitbad;

View File

@ -1004,7 +1004,7 @@ private:
" char *c1;\n"
" c1=strcpy(c1,\"test\");\n"
"}");
TODO_ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: c1\n","", errout.str());
ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: c1\n", errout.str());
checkUninitVarB("void f(char *c1)\n"
"{\n"
@ -2357,12 +2357,6 @@ private:
"}");
ASSERT_EQUALS("", errout.str());
checkUninitVarB("int f(int a) {\n"
" int result;\n"
" foo() ? result = 1 : result = 0;\n"
"}");
ASSERT_EQUALS("", errout.str());
// = { .. }
checkUninitVarB("int f() {\n"
" int a;\n"
@ -3120,16 +3114,13 @@ private:
"}\n");
ASSERT_EQUALS("", errout.str());
// TODO: False negative when "?:" is used
// This should probably be fixed in the tokenizer by changing
// "return x?y:z;" to "if(x)return y;return z;"
checkUninitVar2("int f(int x) {\n"
" int a;\n"
" if (x)\n"
" a = p;\n"
" return y ? 2*a : 3*a;\n"
"}\n");
TODO_ASSERT_EQUALS("error", "", errout.str());
ASSERT_EQUALS("[test.cpp:5]: (error) Uninitialized variable: a\n", errout.str());
// Unknown => bail out..
checkUninitVarB("void f(int x) {\n"