Fix issue 8715: regression uninitvar not detected (#2092)
This commit is contained in:
parent
ef714225bb
commit
3aef0c9bd3
|
@ -1093,22 +1093,32 @@ bool isVariableChanged(const Token *tok, const Settings *settings, bool cpp, int
|
|||
}
|
||||
|
||||
bool isVariableChanged(const Token *start, const Token *end, const nonneg int varid, bool globalvar, const Settings *settings, bool cpp, int depth)
|
||||
{
|
||||
return findVariableChanged(start, end, varid, globalvar, settings, cpp, depth) != nullptr;
|
||||
}
|
||||
|
||||
Token* findVariableChanged(Token *start, const Token *end, const nonneg int varid, bool globalvar, const Settings *settings, bool cpp, int depth)
|
||||
{
|
||||
if (!precedes(start, end))
|
||||
return false;
|
||||
return nullptr;
|
||||
if (depth < 0)
|
||||
return true;
|
||||
for (const Token *tok = start; tok != end; tok = tok->next()) {
|
||||
return start;
|
||||
for (Token *tok = start; tok != end; tok = tok->next()) {
|
||||
if (tok->varId() != varid) {
|
||||
if (globalvar && Token::Match(tok, "%name% ("))
|
||||
// TODO: Is global variable really changed by function call?
|
||||
return true;
|
||||
return tok;
|
||||
continue;
|
||||
}
|
||||
if (isVariableChanged(tok, settings, cpp, depth))
|
||||
return true;
|
||||
return tok;
|
||||
}
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Token* findVariableChanged(const Token *start, const Token *end, const nonneg int varid, bool globalvar, const Settings *settings, bool cpp, int depth)
|
||||
{
|
||||
return findVariableChanged(const_cast<Token*>(start), end, varid, globalvar, settings, cpp, depth);
|
||||
}
|
||||
|
||||
bool isVariableChanged(const Variable * var, const Settings *settings, bool cpp, int depth)
|
||||
|
|
|
@ -142,6 +142,9 @@ bool isVariableChanged(const Token *tok, const Settings *settings, bool cpp, int
|
|||
|
||||
bool isVariableChanged(const Variable * var, const Settings *settings, bool cpp, int depth = 20);
|
||||
|
||||
const Token* findVariableChanged(const Token *start, const Token *end, const nonneg int varid, bool globalvar, const Settings *settings, bool cpp, int depth = 20);
|
||||
Token* findVariableChanged(Token *start, const Token *end, const nonneg int varid, bool globalvar, const Settings *settings, bool cpp, int depth = 20);
|
||||
|
||||
bool isAliased(const Variable *var);
|
||||
|
||||
/** Determines the number of arguments - if token is a function call or macro
|
||||
|
|
|
@ -1299,7 +1299,7 @@ void CheckUninitVar::valueFlowUninit()
|
|||
}
|
||||
if (!tok->variable())
|
||||
continue;
|
||||
if (Token::simpleMatch(tok->astParent(), ".") && tok->astParent()->astOperand1() == tok)
|
||||
if (Token::Match(tok->astParent(), ". %var%") && tok->astParent()->astOperand1() == tok)
|
||||
continue;
|
||||
auto v = std::find_if(tok->values().begin(), tok->values().end(), std::mem_fn(&ValueFlow::Value::isUninitValue));
|
||||
if (v == tok->values().end())
|
||||
|
@ -1308,7 +1308,7 @@ void CheckUninitVar::valueFlowUninit()
|
|||
continue;
|
||||
if (!isVariableUsage(tok, tok->variable()->isPointer(), tok->variable()->isArray() ? ARRAY : NO_ALLOC))
|
||||
continue;
|
||||
if (isVariableChanged(tok, mSettings, mTokenizer->isCPP()))
|
||||
if (!Token::Match(tok->astParent(), ". %name% (") && isVariableChanged(tok, mSettings, mTokenizer->isCPP()))
|
||||
continue;
|
||||
uninitvarError(tok, tok->str(), v->errorPath);
|
||||
}
|
||||
|
|
|
@ -2145,7 +2145,16 @@ static bool valueFlowForward(Token * const startToken,
|
|||
// conditional block of code that assigns variable..
|
||||
else if (!tok2->varId() && Token::Match(tok2, "%name% (") && Token::simpleMatch(tok2->linkAt(1), ") {")) {
|
||||
// is variable changed in condition?
|
||||
if (isVariableChanged(tok2->next(), tok2->next()->link(), varid, var->isGlobal(), settings, tokenlist->isCPP())) {
|
||||
Token* tokChanged = findVariableChanged(tok2->next(), tok2->next()->link(), varid, var->isGlobal(), settings, tokenlist->isCPP());
|
||||
if (tokChanged != nullptr) {
|
||||
// Set the value before bailing
|
||||
if (tokChanged->varId() == varid) {
|
||||
for (const ValueFlow::Value &v : values) {
|
||||
if (!v.isNonValue())
|
||||
continue;
|
||||
setTokenValue(tokChanged, v, settings);
|
||||
}
|
||||
}
|
||||
if (settings->debugwarnings)
|
||||
bailout(tokenlist, errorLogger, tok2, "variable " + var->name() + " valueFlowForward, assignment in condition");
|
||||
return false;
|
||||
|
|
|
@ -139,6 +139,10 @@ namespace ValueFlow {
|
|||
return valueType == ValueType::LIFETIME && lifetimeScope == LifetimeScope::Argument;
|
||||
}
|
||||
|
||||
bool isNonValue() const {
|
||||
return isMovedValue() || isUninitValue() || isLifetimeValue();
|
||||
}
|
||||
|
||||
/** int value */
|
||||
long long intvalue;
|
||||
|
||||
|
|
|
@ -82,6 +82,7 @@ private:
|
|||
TEST_CASE(trac_5970);
|
||||
TEST_CASE(valueFlowUninit);
|
||||
TEST_CASE(uninitvar_ipa);
|
||||
TEST_CASE(uninitvar_memberfunction);
|
||||
|
||||
TEST_CASE(isVariableUsageDeref); // *p
|
||||
|
||||
|
@ -4030,6 +4031,18 @@ private:
|
|||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void uninitvar_memberfunction() {
|
||||
// # 8715
|
||||
valueFlowUninit("struct C {\n"
|
||||
" int x();\n"
|
||||
"};\n"
|
||||
"void f() {\n"
|
||||
" C *c;\n"
|
||||
" if (c->x() == 4) {}\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("[test.cpp:6]: (error) Uninitialized variable: c\n", errout.str());
|
||||
}
|
||||
|
||||
void isVariableUsageDeref() {
|
||||
// *p
|
||||
checkUninitVar("void f() {\n"
|
||||
|
|
|
@ -3474,7 +3474,7 @@ private:
|
|||
" if (c->x() == 4) {}\n"
|
||||
"}";
|
||||
values = tokenValues(code, "c .");
|
||||
TODO_ASSERT_EQUALS(true, false, values.size()==1U && values.front().isUninitValue());
|
||||
ASSERT_EQUALS(true, values.size()==1U && values.front().isUninitValue());
|
||||
|
||||
code = "void f() {\n"
|
||||
" int **x;\n"
|
||||
|
|
Loading…
Reference in New Issue