Fix issue 10076: ValueFlow: False positive after address of var is taken 'T t = {{{&var}}};' (#3283)
This commit is contained in:
parent
548ec10824
commit
3e78e76fe8
|
@ -1668,7 +1668,8 @@ const Token * getTokenArgumentFunction(const Token * tok, int& argn)
|
|||
return nullptr;
|
||||
if (!Token::Match(tok, "{|("))
|
||||
return nullptr;
|
||||
tok = tok->astOperand1();
|
||||
if (tok->astOperand2())
|
||||
tok = tok->astOperand1();
|
||||
while (tok && (tok->isUnaryOp("*") || tok->str() == "["))
|
||||
tok = tok->astOperand1();
|
||||
while (Token::simpleMatch(tok, "."))
|
||||
|
@ -1690,21 +1691,31 @@ const Token * getTokenArgumentFunction(const Token * tok, int& argn)
|
|||
return tok;
|
||||
}
|
||||
|
||||
static std::vector<const Variable*> getArgumentVars(const Token* tok, int argnr)
|
||||
std::vector<const Variable*> getArgumentVars(const Token* tok, int argnr)
|
||||
{
|
||||
std::vector<const Variable*> result;
|
||||
if (!tok)
|
||||
return result;
|
||||
if (tok->function())
|
||||
return {tok->function()->getArgumentVar(argnr)};
|
||||
if (Token::Match(tok->previous(), "%type% (|{") || tok->variable()) {
|
||||
const bool constructor = tok->variable() && tok->variable()->nameToken() == tok;
|
||||
if (tok->function()) {
|
||||
const Variable* argvar = tok->function()->getArgumentVar(argnr);
|
||||
if (argvar)
|
||||
return {argvar};
|
||||
else
|
||||
return result;
|
||||
}
|
||||
if (Token::Match(tok->previous(), "%type% (|{") || Token::simpleMatch(tok, "{") || tok->variable()) {
|
||||
const bool constructor = Token::simpleMatch(tok, "{") || (tok->variable() && tok->variable()->nameToken() == tok);
|
||||
const Type* type = Token::typeOf(tok);
|
||||
if (!type)
|
||||
return result;
|
||||
const Scope* typeScope = type->classScope;
|
||||
if (!typeScope)
|
||||
return result;
|
||||
// Aggregate constructor
|
||||
if (Token::simpleMatch(tok, "{") && typeScope->numConstructors == 0 && argnr < typeScope->varlist.size()) {
|
||||
auto it = std::next(typeScope->varlist.begin(), argnr);
|
||||
return {&*it};
|
||||
}
|
||||
const int argCount = numberOfArguments(tok);
|
||||
for (const Function &function : typeScope->functionList) {
|
||||
if (function.argCount() < argCount)
|
||||
|
@ -1713,7 +1724,9 @@ static std::vector<const Variable*> getArgumentVars(const Token* tok, int argnr)
|
|||
continue;
|
||||
if (!constructor && !Token::simpleMatch(function.token, "operator()"))
|
||||
continue;
|
||||
result.push_back(function.getArgumentVar(argnr));
|
||||
const Variable* argvar = function.getArgumentVar(argnr);
|
||||
if (argvar)
|
||||
result.push_back(argvar);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
@ -1726,6 +1739,17 @@ static bool isCPPCastKeyword(const Token* tok)
|
|||
return endsWith(tok->str(), "_cast", 5);
|
||||
}
|
||||
|
||||
static bool isTrivialConstructor(const Token* tok)
|
||||
{
|
||||
const Token* typeTok = nullptr;
|
||||
const Type* t = Token::typeOf(tok, &typeTok);
|
||||
if (t)
|
||||
return false;
|
||||
if (typeTok->valueType() && typeTok->valueType()->isPrimitive())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Settings *settings, bool *inconclusive)
|
||||
{
|
||||
if (!tok)
|
||||
|
@ -1743,6 +1767,8 @@ bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Setti
|
|||
tok = getTokenArgumentFunction(tok, argnr);
|
||||
if (!tok)
|
||||
return false; // not a function => variable not changed
|
||||
if (Token::simpleMatch(tok, "{") && isTrivialConstructor(tok))
|
||||
return false;
|
||||
if (tok->isKeyword() && !isCPPCastKeyword(tok))
|
||||
return false;
|
||||
const Token * parenTok = tok->next();
|
||||
|
@ -2303,19 +2329,19 @@ std::vector<const Variable*> getLHSVariables(const Token* tok)
|
|||
return result;
|
||||
}
|
||||
|
||||
static const Variable *getLHSVariableRecursive(const Token *tok)
|
||||
static const Token* getLHSVariableRecursive(const Token* tok)
|
||||
{
|
||||
if (!tok)
|
||||
return nullptr;
|
||||
if (Token::Match(tok, "*|&|&&|[")) {
|
||||
const Variable *var = getLHSVariableRecursive(tok->astOperand1());
|
||||
if (var || Token::simpleMatch(tok, "["))
|
||||
return var;
|
||||
const Token* vartok = getLHSVariableRecursive(tok->astOperand1());
|
||||
if ((vartok && vartok->variable()) || Token::simpleMatch(tok, "["))
|
||||
return vartok;
|
||||
return getLHSVariableRecursive(tok->astOperand2());
|
||||
}
|
||||
if (Token::Match(tok->previous(), "this . %var%"))
|
||||
return tok->next()->variable();
|
||||
return tok->variable();
|
||||
return tok->next();
|
||||
return tok;
|
||||
}
|
||||
|
||||
const Variable *getLHSVariable(const Token *tok)
|
||||
|
@ -2326,7 +2352,24 @@ const Variable *getLHSVariable(const Token *tok)
|
|||
return nullptr;
|
||||
if (tok->astOperand1()->varId() > 0 && tok->astOperand1()->variable())
|
||||
return tok->astOperand1()->variable();
|
||||
return getLHSVariableRecursive(tok->astOperand1());
|
||||
const Token* vartok = getLHSVariableRecursive(tok->astOperand1());
|
||||
if (!vartok)
|
||||
return nullptr;
|
||||
return vartok->variable();
|
||||
}
|
||||
|
||||
const Token* getLHSVariableToken(const Token* tok)
|
||||
{
|
||||
if (!Token::Match(tok, "%assign%"))
|
||||
return nullptr;
|
||||
if (!tok->astOperand1())
|
||||
return nullptr;
|
||||
if (tok->astOperand1()->varId() > 0)
|
||||
return tok->astOperand1();
|
||||
const Token* vartok = getLHSVariableRecursive(tok->astOperand1());
|
||||
if (!vartok)
|
||||
return tok->astOperand1();
|
||||
return vartok;
|
||||
}
|
||||
|
||||
const Token* findAllocFuncCallToken(const Token *expr, const Library &library)
|
||||
|
|
|
@ -188,6 +188,8 @@ bool isReturnScope(const Token* const endToken,
|
|||
/// Return the token to the function and the argument number
|
||||
const Token * getTokenArgumentFunction(const Token * tok, int& argn);
|
||||
|
||||
std::vector<const Variable*> getArgumentVars(const Token* tok, int argnr);
|
||||
|
||||
/** Is variable changed by function call?
|
||||
* In case the answer of the question is inconclusive, e.g. because the function declaration is not known
|
||||
* the return value is false and the output parameter inconclusive is set to true
|
||||
|
@ -279,6 +281,8 @@ bool isConstVarExpression(const Token *tok, const char * skipMatch = nullptr);
|
|||
|
||||
const Variable *getLHSVariable(const Token *tok);
|
||||
|
||||
const Token* getLHSVariableToken(const Token* tok);
|
||||
|
||||
std::vector<const Variable*> getLHSVariables(const Token* tok);
|
||||
|
||||
/** Find a allocation function call in expression, so result of expression is allocated memory/resource. */
|
||||
|
|
|
@ -1273,6 +1273,8 @@ public:
|
|||
static MatchResult matchParameter(const ValueType *call, const ValueType *func);
|
||||
static MatchResult matchParameter(const ValueType *call, const Variable *callVar, const Variable *funcVar);
|
||||
|
||||
bool isPrimitive() const { return (type >= ValueType::Type::BOOL); }
|
||||
|
||||
bool isIntegral() const {
|
||||
return (type >= ValueType::Type::BOOL && type <= ValueType::Type::UNKNOWN_INT);
|
||||
}
|
||||
|
|
|
@ -2257,10 +2257,12 @@ void Token::type(const ::Type *t)
|
|||
tokType(eName);
|
||||
}
|
||||
|
||||
const ::Type *Token::typeOf(const Token *tok)
|
||||
const ::Type* Token::typeOf(const Token* tok, const Token** typeTok)
|
||||
{
|
||||
if (!tok)
|
||||
return nullptr;
|
||||
if (typeTok != nullptr)
|
||||
*typeTok = tok;
|
||||
if (Token::simpleMatch(tok, "return")) {
|
||||
const Scope *scope = tok->scope();
|
||||
if (!scope)
|
||||
|
@ -2282,14 +2284,30 @@ const ::Type *Token::typeOf(const Token *tok)
|
|||
return nullptr;
|
||||
return function->retType;
|
||||
} else if (Token::Match(tok->previous(), "%type%|= (|{")) {
|
||||
return typeOf(tok->previous());
|
||||
return typeOf(tok->previous(), typeTok);
|
||||
} else if (Token::simpleMatch(tok, "=")) {
|
||||
return Token::typeOf(tok->astOperand1());
|
||||
return Token::typeOf(getLHSVariableToken(tok), typeTok);
|
||||
} else if (Token::simpleMatch(tok, ".")) {
|
||||
return Token::typeOf(tok->astOperand2());
|
||||
return Token::typeOf(tok->astOperand2(), typeTok);
|
||||
} else if (Token::simpleMatch(tok, "[")) {
|
||||
return Token::typeOf(tok->astOperand1());
|
||||
return Token::typeOf(tok->astOperand1(), typeTok);
|
||||
} else if (Token::simpleMatch(tok, "{")) {
|
||||
int argnr;
|
||||
const Token* ftok = getTokenArgumentFunction(tok, argnr);
|
||||
if (argnr < 0)
|
||||
return nullptr;
|
||||
if (!ftok)
|
||||
return nullptr;
|
||||
if (ftok == tok)
|
||||
return nullptr;
|
||||
std::vector<const Variable*> vars = getArgumentVars(ftok, argnr);
|
||||
if (vars.empty())
|
||||
return nullptr;
|
||||
if (std::all_of(
|
||||
vars.begin(), vars.end(), [&](const Variable* var) { return var->type() == vars.front()->type(); }))
|
||||
return vars.front()->type();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -1010,7 +1010,7 @@ public:
|
|||
return mTokType == eType ? mImpl->mType : nullptr;
|
||||
}
|
||||
|
||||
static const ::Type *typeOf(const Token *tok);
|
||||
static const ::Type* typeOf(const Token* tok, const Token** typeTok = nullptr);
|
||||
|
||||
static std::pair<const Token*, const Token*> typeDecl(const Token * tok);
|
||||
|
||||
|
|
|
@ -381,6 +381,86 @@ private:
|
|||
"}\n", true);
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
check("struct T {\n"
|
||||
" std::vector<int>* v;\n"
|
||||
"};\n"
|
||||
"struct S {\n"
|
||||
" std::vector<T> t;\n"
|
||||
"};\n"
|
||||
"long g(S& s);\n"
|
||||
"int f() {\n"
|
||||
" std::vector<int> ArrS;\n"
|
||||
" S s = { { { &ArrS } } };\n"
|
||||
" g(s);\n"
|
||||
" return ArrS[0];\n"
|
||||
"}\n",
|
||||
true);
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
check("struct T {\n"
|
||||
" std::vector<int>* v;\n"
|
||||
"};\n"
|
||||
"struct S {\n"
|
||||
" std::vector<std::vector<T>> t;\n"
|
||||
"};\n"
|
||||
"long g(S& s);\n"
|
||||
"int f() {\n"
|
||||
" std::vector<int> ArrS;\n"
|
||||
" S s = { { { { &ArrS } } } };\n"
|
||||
" g(s);\n"
|
||||
" return ArrS[0];\n"
|
||||
"}\n",
|
||||
true);
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
check("struct T {\n"
|
||||
" std::vector<int>* v;\n"
|
||||
"};\n"
|
||||
"struct S {\n"
|
||||
" T t;\n"
|
||||
"};\n"
|
||||
"long g(S& s);\n"
|
||||
"int f() {\n"
|
||||
" std::vector<int> ArrS;\n"
|
||||
" S s { { &ArrS } };\n"
|
||||
" g(s);\n"
|
||||
" return ArrS[0];\n"
|
||||
"}\n",
|
||||
true);
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
check("struct T {\n"
|
||||
" std::vector<int>* v;\n"
|
||||
"};\n"
|
||||
"struct S {\n"
|
||||
" std::vector<T> t;\n"
|
||||
"};\n"
|
||||
"long g(S& s);\n"
|
||||
"int f() {\n"
|
||||
" std::vector<int> ArrS;\n"
|
||||
" S s { { { &ArrS } } };\n"
|
||||
" g(s);\n"
|
||||
" return ArrS[0];\n"
|
||||
"}\n",
|
||||
true);
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
check("struct T {\n"
|
||||
" std::vector<int>* v;\n"
|
||||
"};\n"
|
||||
"struct S {\n"
|
||||
" std::vector<std::vector<T>> t;\n"
|
||||
"};\n"
|
||||
"long g(S& s);\n"
|
||||
"int f() {\n"
|
||||
" std::vector<int> ArrS;\n"
|
||||
" S s { { { { &ArrS } } } };\n"
|
||||
" g(s);\n"
|
||||
" return ArrS[0];\n"
|
||||
"}\n",
|
||||
true);
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
checkNormal("extern void Bar(const double, const double);\n"
|
||||
"void f(std::vector<double> &r, const double ) {\n"
|
||||
" std::vector<double> result;\n"
|
||||
|
|
Loading…
Reference in New Issue