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:
Paul Fultz II 2020-01-04 04:39:52 -06:00 committed by Daniel Marjamäki
parent a9d423eef2
commit e1a97c524d
3 changed files with 72 additions and 38 deletions

View File

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

View File

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

View File

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