Fix 11898: FP knownEmptyContainer (#5394)
This commit is contained in:
parent
ffbcfae988
commit
fd12baaf89
|
@ -1001,29 +1001,43 @@ bool isAliasOf(const Token *tok, nonneg int varid, bool* inconclusive)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isAliasOf(const Token* tok, const Token* expr, bool* inconclusive)
|
bool isAliasOf(const Token* tok, const Token* expr, int* indirect, bool* inconclusive)
|
||||||
{
|
{
|
||||||
const bool pointer = astIsPointer(tok);
|
|
||||||
const ValueFlow::Value* value = nullptr;
|
const ValueFlow::Value* value = nullptr;
|
||||||
const Token* r = findAstNode(expr, [&](const Token* childTok) {
|
const Token* r = nullptr;
|
||||||
for (const ValueFlow::Value& val : tok->values()) {
|
if (indirect)
|
||||||
if (val.isImpossible())
|
*indirect = 1;
|
||||||
continue;
|
for (const ReferenceToken& ref : followAllReferences(tok)) {
|
||||||
if (val.isLocalLifetimeValue() || (pointer && val.isSymbolicValue() && val.intvalue == 0)) {
|
const bool pointer = astIsPointer(ref.token);
|
||||||
if (findAstNode(val.tokvalue,
|
r = findAstNode(expr, [&](const Token* childTok) {
|
||||||
[&](const Token* aliasTok) {
|
if (childTok->exprId() == 0)
|
||||||
return aliasTok->exprId() == childTok->exprId();
|
return false;
|
||||||
})) {
|
if (ref.token != tok && expr->exprId() == childTok->exprId()) {
|
||||||
if (val.isInconclusive() && inconclusive != nullptr) {
|
if (indirect)
|
||||||
value = &val;
|
*indirect = 0;
|
||||||
} else {
|
return true;
|
||||||
return true;
|
}
|
||||||
|
for (const ValueFlow::Value& val : ref.token->values()) {
|
||||||
|
if (val.isImpossible())
|
||||||
|
continue;
|
||||||
|
if (val.isLocalLifetimeValue() || (pointer && val.isSymbolicValue() && val.intvalue == 0)) {
|
||||||
|
if (findAstNode(val.tokvalue,
|
||||||
|
[&](const Token* aliasTok) {
|
||||||
|
return aliasTok->exprId() == childTok->exprId();
|
||||||
|
})) {
|
||||||
|
if (val.isInconclusive() && inconclusive != nullptr) {
|
||||||
|
value = &val;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return false;
|
||||||
return false;
|
});
|
||||||
});
|
if (r)
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (!r && value && inconclusive)
|
if (!r && value && inconclusive)
|
||||||
*inconclusive = true;
|
*inconclusive = true;
|
||||||
return r || value;
|
return r || value;
|
||||||
|
@ -2728,16 +2742,17 @@ static bool isExpressionChangedAt(const F& getExprTok,
|
||||||
if (globalvar && !tok->isKeyword() && Token::Match(tok, "%name% (") && !(tok->function() && tok->function()->isAttributePure()))
|
if (globalvar && !tok->isKeyword() && Token::Match(tok, "%name% (") && !(tok->function() && tok->function()->isAttributePure()))
|
||||||
// TODO: Is global variable really changed by function call?
|
// TODO: Is global variable really changed by function call?
|
||||||
return true;
|
return true;
|
||||||
|
int i = 1;
|
||||||
bool aliased = false;
|
bool aliased = false;
|
||||||
// If we can't find the expression then assume it is an alias
|
// If we can't find the expression then assume it is an alias
|
||||||
auto expr = getExprTok();
|
auto expr = getExprTok();
|
||||||
if (!expr)
|
if (!expr)
|
||||||
aliased = true;
|
aliased = true;
|
||||||
if (!aliased)
|
if (!aliased)
|
||||||
aliased = isAliasOf(tok, expr);
|
aliased = isAliasOf(tok, expr, &i);
|
||||||
if (!aliased)
|
if (!aliased)
|
||||||
return false;
|
return false;
|
||||||
if (isVariableChanged(tok, indirect + 1, settings, cpp, depth))
|
if (isVariableChanged(tok, indirect + i, settings, cpp, depth))
|
||||||
return true;
|
return true;
|
||||||
// TODO: Try to traverse the lambda function
|
// TODO: Try to traverse the lambda function
|
||||||
if (Token::Match(tok, "%var% ("))
|
if (Token::Match(tok, "%var% ("))
|
||||||
|
|
|
@ -356,7 +356,7 @@ bool isExpressionChangedAt(const Token* expr,
|
||||||
/// If token is an alias if another variable
|
/// If token is an alias if another variable
|
||||||
bool isAliasOf(const Token *tok, nonneg int varid, bool* inconclusive = nullptr);
|
bool isAliasOf(const Token *tok, nonneg int varid, bool* inconclusive = nullptr);
|
||||||
|
|
||||||
bool isAliasOf(const Token* tok, const Token* expr, bool* inconclusive = nullptr);
|
bool isAliasOf(const Token* tok, const Token* expr, int* indirect = nullptr, bool* inconclusive = nullptr);
|
||||||
|
|
||||||
bool isAliased(const Variable *var);
|
bool isAliased(const Variable *var);
|
||||||
|
|
||||||
|
|
|
@ -8039,7 +8039,7 @@ static void valueFlowUninit(TokenList& tokenlist, const Settings* settings)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isContainerSizeChanged(nonneg int varId,
|
static bool isContainerSizeChanged(const Token* expr,
|
||||||
const Token* start,
|
const Token* start,
|
||||||
const Token* end,
|
const Token* end,
|
||||||
int indirect,
|
int indirect,
|
||||||
|
@ -8088,7 +8088,7 @@ static bool isContainerSizeChangedByFunction(const Token* tok,
|
||||||
if (!arg->nameToken())
|
if (!arg->nameToken())
|
||||||
return false;
|
return false;
|
||||||
if (depth > 0)
|
if (depth > 0)
|
||||||
return isContainerSizeChanged(arg->declarationId(),
|
return isContainerSizeChanged(arg->nameToken(),
|
||||||
scope->bodyStart,
|
scope->bodyStart,
|
||||||
scope->bodyEnd,
|
scope->bodyEnd,
|
||||||
addressOf ? indirect + 1 : indirect,
|
addressOf ? indirect + 1 : indirect,
|
||||||
|
@ -8342,7 +8342,7 @@ bool ValueFlow::isContainerSizeChanged(const Token* tok, int indirect, const Set
|
||||||
return isContainerSizeChangedByFunction(tok, indirect, settings, depth);
|
return isContainerSizeChangedByFunction(tok, indirect, settings, depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isContainerSizeChanged(nonneg int varId,
|
static bool isContainerSizeChanged(const Token* expr,
|
||||||
const Token* start,
|
const Token* start,
|
||||||
const Token* end,
|
const Token* end,
|
||||||
int indirect,
|
int indirect,
|
||||||
|
@ -8350,7 +8350,7 @@ static bool isContainerSizeChanged(nonneg int varId,
|
||||||
int depth)
|
int depth)
|
||||||
{
|
{
|
||||||
for (const Token *tok = start; tok != end; tok = tok->next()) {
|
for (const Token *tok = start; tok != end; tok = tok->next()) {
|
||||||
if (tok->varId() != varId)
|
if (tok->exprId() != expr->exprId() && !isAliasOf(tok, expr))
|
||||||
continue;
|
continue;
|
||||||
if (ValueFlow::isContainerSizeChanged(tok, indirect, settings, depth))
|
if (ValueFlow::isContainerSizeChanged(tok, indirect, settings, depth))
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -6643,6 +6643,18 @@ private:
|
||||||
|
|
||||||
code = "int f() { auto a = std::array<int, 2>{}; return a[1]; }";
|
code = "int f() { auto a = std::array<int, 2>{}; return a[1]; }";
|
||||||
ASSERT_EQUALS("values.size():0", isKnownContainerSizeValue(tokenValues(code, "a ["), 0));
|
ASSERT_EQUALS("values.size():0", isKnownContainerSizeValue(tokenValues(code, "a ["), 0));
|
||||||
|
|
||||||
|
code = "void g(std::vector<int>* w) {\n"
|
||||||
|
" std::vector<int> &r = *w;\n"
|
||||||
|
" r.push_back(0);\n"
|
||||||
|
"}\n"
|
||||||
|
"int f() {\n"
|
||||||
|
" std::vector<int> v;\n"
|
||||||
|
" g(&v);\n"
|
||||||
|
" return v[0];\n"
|
||||||
|
"}\n";
|
||||||
|
ASSERT(!isKnownContainerSizeValue(tokenValues(code, "v ["), 0).empty());
|
||||||
|
ASSERT(!isPossibleContainerSizeValue(tokenValues(code, "v ["), 0).empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
void valueFlowContainerElement()
|
void valueFlowContainerElement()
|
||||||
|
|
Loading…
Reference in New Issue