Fix issue 9302: FP uninitvar - struct accessed via pointer (#2121)

This commit is contained in:
Paul Fultz II 2019-08-29 01:38:50 -05:00 committed by Daniel Marjamäki
parent 99ba01b1c6
commit 03fe6795bf
4 changed files with 91 additions and 0 deletions

View File

@ -73,6 +73,24 @@ std::vector<const Token*> astFlatten(const Token* tok, const char* op)
} }
bool astHasToken(const Token* root, const Token * tok)
{
if (!root)
return false;
if (root == tok)
return true;
return astHasToken(root->astOperand1(), tok) || astHasToken(root->astOperand2(), tok);
}
bool astHasVar(const Token * tok, nonneg int varid)
{
if (!tok)
return false;
if (tok->varId() == varid)
return true;
return astHasVar(tok->astOperand1(), varid) || astHasVar(tok->astOperand2(), varid);
}
static bool astIsCharWithSign(const Token *tok, ValueType::Sign sign) static bool astIsCharWithSign(const Token *tok, ValueType::Sign sign)
{ {
if (!tok) if (!tok)

View File

@ -50,6 +50,10 @@ void visitAstNodes(const Token *ast, std::function<ChildrenToVisit(const Token *
std::vector<const Token*> astFlatten(const Token* tok, const char* op); std::vector<const Token*> astFlatten(const Token* tok, const char* op);
bool astHasToken(const Token* root, const Token * tok);
bool astHasVar(const Token * tok, nonneg int varid);
/** Is expression a 'signed char' if no promotion is used */ /** Is expression a 'signed char' if no promotion is used */
bool astIsSignedChar(const Token *tok); bool astIsSignedChar(const Token *tok);
/** Is expression a 'char' if no promotion is used? */ /** Is expression a 'char' if no promotion is used? */

View File

@ -2025,6 +2025,52 @@ static bool evalAssignment(ValueFlow::Value &lhsValue, const std::string &assign
return true; return true;
} }
static bool isAliasOf(const Token *tok, nonneg int varid)
{
if (tok->varId() == varid)
return false;
if (tok->varId() == 0)
return false;
if (!astIsPointer(tok))
return false;
for (const ValueFlow::Value &val : tok->values()) {
if (!val.isLocalLifetimeValue())
continue;
if (val.lifetimeKind != ValueFlow::Value::LifetimeKind::Address)
continue;
if (val.tokvalue->varId() == varid)
return true;
}
return false;
}
// Check if its an alias of the variable or is being aliased to this variable
static bool isAliasOf(const Variable * var, const Token *tok, nonneg int varid, const std::list<ValueFlow::Value>& values)
{
if (tok->varId() == varid)
return false;
if (tok->varId() == 0)
return false;
if (isAliasOf(tok, varid))
return true;
if (!var->isPointer())
return false;
// Search through non value aliases
for (const ValueFlow::Value &val : values) {
if (!val.isNonValue())
continue;
if (val.isLifetimeValue() && !val.isLocalLifetimeValue())
continue;
if (val.isLifetimeValue() && val.lifetimeKind != ValueFlow::Value::LifetimeKind::Address)
continue;
if (!Token::Match(val.tokvalue, ".|&|*|%var%"))
continue;
if (astHasVar(val.tokvalue, tok->varId()))
return true;
}
return false;
}
static bool valueFlowForward(Token * const startToken, static bool valueFlowForward(Token * const startToken,
const Token * const endToken, const Token * const endToken,
const Variable * const var, const Variable * const var,
@ -2708,6 +2754,15 @@ static bool valueFlowForward(Token * const startToken,
if (isVariableChanged(tok2, settings, tokenlist->isCPP())) { if (isVariableChanged(tok2, settings, tokenlist->isCPP())) {
values.remove_if(std::mem_fn(&ValueFlow::Value::isUninitValue)); values.remove_if(std::mem_fn(&ValueFlow::Value::isUninitValue));
} }
} else if (isAliasOf(var, tok2, varid, values) && isVariableChanged(tok2, settings, tokenlist->isCPP())) {
if (settings->debugwarnings)
bailout(tokenlist, errorLogger, tok2, "Alias variable was modified.");
// Bail at the end of the statement if its in an assignment
const Token * top = tok2->astTop();
if (Token::Match(top, "%assign%") && astHasToken(top->astOperand1(), tok2))
returnStatement = true;
else
return false;
} }
// Lambda function // Lambda function
@ -5030,6 +5085,7 @@ static void valueFlowUninit(TokenList *tokenlist, SymbolDatabase * /*symbolDatab
ValueFlow::Value uninitValue; ValueFlow::Value uninitValue;
uninitValue.setKnown(); uninitValue.setKnown();
uninitValue.valueType = ValueFlow::Value::UNINIT; uninitValue.valueType = ValueFlow::Value::UNINIT;
uninitValue.tokvalue = vardecl;
std::list<ValueFlow::Value> values; std::list<ValueFlow::Value> values;
values.push_back(uninitValue); values.push_back(uninitValue);

View File

@ -4120,6 +4120,19 @@ private:
" return d(&c);\n" " return d(&c);\n"
"}\n"); "}\n");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
// # 9302
valueFlowUninit("struct VZ {\n"
" double typ;\n"
"};\n"
"void read() {\n"
" struct VZ vz;\n"
" struct VZ* pvz = &vz;\n"
" vz.typ = 42;\n"
" if (pvz->typ == 0)\n"
" return;\n"
"}\n");
ASSERT_EQUALS("", errout.str());
} }
void uninitvar_memberfunction() { void uninitvar_memberfunction() {