Fix 11898: FP knownEmptyContainer (#5394)

This commit is contained in:
Paul Fultz II 2023-09-02 07:30:35 -05:00 committed by GitHub
parent ffbcfae988
commit fd12baaf89
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 52 additions and 25 deletions

View File

@ -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% ("))

View File

@ -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);

View File

@ -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;

View File

@ -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()