Fix issue 9554: False positive: The address of local variable 'x' is accessed at non-zero index. (#2470)
* Fix issue 9554: False positive: The address of local variable 'x' is accessed at non-zero index. * Format * Remove unnecesary condition check
This commit is contained in:
parent
a9d423eef2
commit
e1a97c524d
|
@ -1566,13 +1566,15 @@ struct FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const
|
|||
if (Token::Match(tok, "return|throw")) {
|
||||
// TODO: Handle these better
|
||||
// Is expr variable used in expression?
|
||||
const Token *end = tok->findExpressionStartEndTokens().second->next();
|
||||
for (const Token *tok2 = tok; tok2 != end; tok2 = tok2->next()) {
|
||||
if (!local && Token::Match(tok2, "%name% ("))
|
||||
return Result(Result::Type::READ);
|
||||
if (tok2->varId() && exprVarIds.find(tok2->varId()) != exprVarIds.end())
|
||||
return Result(Result::Type::READ);
|
||||
}
|
||||
|
||||
const Token* opTok = tok->astOperand1();
|
||||
if (!opTok)
|
||||
opTok = tok->next();
|
||||
std::pair<const Token*, const Token*> startEndTokens = opTok->findExpressionStartEndTokens();
|
||||
FwdAnalysis::Result result =
|
||||
checkRecursive(expr, startEndTokens.first, startEndTokens.second->next(), exprVarIds, local, true, depth);
|
||||
if (result.type != Result::Type::NONE)
|
||||
return result;
|
||||
|
||||
// #9167: if the return is inside an inner class, it does not tell us anything
|
||||
if (!inInnerClass) {
|
||||
|
|
|
@ -3371,16 +3371,6 @@ static void valueFlowForwardLifetime(Token * tok, TokenList *tokenlist, ErrorLog
|
|||
return;
|
||||
// Assignment
|
||||
if (parent->str() == "=" && (!parent->astParent() || Token::simpleMatch(parent->astParent(), ";"))) {
|
||||
const Variable *var = getLHSVariable(parent);
|
||||
if (!var)
|
||||
return;
|
||||
|
||||
const Token * endOfVarScope = nullptr;
|
||||
if (!var->isLocal())
|
||||
endOfVarScope = tok->scope()->bodyEnd;
|
||||
else
|
||||
endOfVarScope = var->typeStartToken()->scope()->bodyEnd;
|
||||
|
||||
// Rhs values..
|
||||
if (!parent->astOperand2() || parent->astOperand2()->values().empty())
|
||||
return;
|
||||
|
@ -3388,33 +3378,48 @@ static void valueFlowForwardLifetime(Token * tok, TokenList *tokenlist, ErrorLog
|
|||
if (!isLifetimeBorrowed(parent->astOperand2(), settings))
|
||||
return;
|
||||
|
||||
std::list<ValueFlow::Value> values = parent->astOperand2()->values();
|
||||
const Variable* var = getLHSVariable(parent);
|
||||
|
||||
// Static variable initialisation?
|
||||
if (var->isStatic() && var->nameToken() == parent->astOperand1())
|
||||
lowerToPossible(values);
|
||||
const Token* endOfVarScope = nullptr;
|
||||
if (var && var->isLocal())
|
||||
endOfVarScope = var->typeStartToken()->scope()->bodyEnd;
|
||||
else
|
||||
endOfVarScope = tok->scope()->bodyEnd;
|
||||
|
||||
// Only forward lifetime values
|
||||
std::list<ValueFlow::Value> values = parent->astOperand2()->values();
|
||||
values.remove_if(&isNotLifetimeValue);
|
||||
|
||||
// Skip RHS
|
||||
const Token *nextExpression = nextAfterAstRightmostLeaf(parent);
|
||||
|
||||
// Only forward lifetime values
|
||||
values.remove_if(&isNotLifetimeValue);
|
||||
valueFlowForwardVariable(const_cast<Token*>(nextExpression),
|
||||
endOfVarScope,
|
||||
var,
|
||||
var->declarationId(),
|
||||
values,
|
||||
false,
|
||||
false,
|
||||
tokenlist,
|
||||
errorLogger,
|
||||
settings);
|
||||
if (Token::Match(parent->astOperand1(), ".|[|(")) {
|
||||
valueFlowForwardExpression(
|
||||
const_cast<Token*>(nextExpression), endOfVarScope, parent->astOperand1(), values, tokenlist, settings);
|
||||
|
||||
if (tok->astTop() && Token::simpleMatch(tok->astTop()->previous(), "for (") &&
|
||||
Token::simpleMatch(tok->astTop()->link(), ") {")) {
|
||||
Token *start = tok->astTop()->link()->next();
|
||||
valueFlowForwardVariable(
|
||||
start, start->link(), var, var->declarationId(), values, false, false, tokenlist, errorLogger, settings);
|
||||
for (ValueFlow::Value& val : values) {
|
||||
if (val.lifetimeKind == ValueFlow::Value::LifetimeKind::Address)
|
||||
val.lifetimeKind = ValueFlow::Value::LifetimeKind::Object;
|
||||
}
|
||||
}
|
||||
if (var) {
|
||||
valueFlowForwardVariable(const_cast<Token*>(nextExpression),
|
||||
endOfVarScope,
|
||||
var,
|
||||
var->declarationId(),
|
||||
values,
|
||||
false,
|
||||
false,
|
||||
tokenlist,
|
||||
errorLogger,
|
||||
settings);
|
||||
|
||||
if (tok->astTop() && Token::simpleMatch(tok->astTop()->previous(), "for (") &&
|
||||
Token::simpleMatch(tok->astTop()->link(), ") {")) {
|
||||
Token* start = tok->astTop()->link()->next();
|
||||
valueFlowForwardVariable(
|
||||
start, start->link(), var, var->declarationId(), values, false, false, tokenlist, errorLogger, settings);
|
||||
}
|
||||
}
|
||||
// Constructor
|
||||
} else if (Token::simpleMatch(parent, "{") && !isScopeBracket(parent)) {
|
||||
|
|
|
@ -4394,6 +4394,33 @@ private:
|
|||
" return i[0]; \n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
check("void f() {\n"
|
||||
" int x = 0;\n"
|
||||
" std::map<int, int*> m;\n"
|
||||
" m[0] = &x;\n"
|
||||
" m[1] = &x;\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
check("int f() {\n"
|
||||
" int x = 0;\n"
|
||||
" std::map<int, int*> m;\n"
|
||||
" m[0] = &x;\n"
|
||||
" return m[0][1];\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS(
|
||||
"[test.cpp:4] -> [test.cpp:5]: (error) The address of local variable 'x' is accessed at non-zero index.\n",
|
||||
errout.str());
|
||||
|
||||
check("int f(int * y) {\n"
|
||||
" int x = 0;\n"
|
||||
" std::map<int, int*> m;\n"
|
||||
" m[0] = &x;\n"
|
||||
" m[1] = y;\n"
|
||||
" return m[1][1];\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue