Fix issue 9302: FP uninitvar - struct accessed via pointer (#2121)
This commit is contained in:
parent
99ba01b1c6
commit
03fe6795bf
|
@ -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)
|
||||||
|
|
|
@ -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? */
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
Loading…
Reference in New Issue