Fix FPs in lifetime checker

This fixes several FPs in the lifetime checker. It also fixes issue [8846](https://trac.cppcheck.net/ticket/8846):

```cpp
int * f(int a[])
{
        return a;
}
```
This commit is contained in:
Paul Fultz II 2018-11-17 09:41:59 +01:00 committed by Daniel Marjamäki
parent 8e465d5963
commit 7ef119cbfc
5 changed files with 60 additions and 4 deletions

View File

@ -76,6 +76,16 @@ bool astIsPointer(const Token *tok)
return tok && tok->valueType() && tok->valueType()->pointer;
}
bool astIsIterator(const Token *tok)
{
return tok && tok->valueType() && tok->valueType()->type == ValueType::Type::ITERATOR;
}
bool astIsContainer(const Token *tok)
{
return tok && tok->valueType() && tok->valueType()->type == ValueType::Type::CONTAINER;
}
std::string astCanonicalType(const Token *expr)
{
if (!expr)

View File

@ -45,6 +45,10 @@ bool astIsBool(const Token *tok);
bool astIsPointer(const Token *tok);
bool astIsIterator(const Token *tok);
bool astIsContainer(const Token *tok);
/**
* Get canonical type of expression. const/static/etc are not included and neither *&.
* For example:

View File

@ -579,6 +579,13 @@ static bool isDeadScope(const Token * tok, const Scope * scope)
return false;
}
static int getPointerDepth(const Token *tok)
{
if (!tok)
return 0;
return tok->valueType() ? tok->valueType()->pointer : 0;
}
void CheckAutoVariables::checkVarLifetimeScope(const Token * start, const Token * end)
{
if (!start)
@ -597,7 +604,7 @@ void CheckAutoVariables::checkVarLifetimeScope(const Token * start, const Token
if (val.tokvalue == tok)
continue;
if (Token::Match(tok->astParent(), "return|throw")) {
if (isInScope(val.tokvalue, scope)) {
if (getPointerDepth(tok) >= getPointerDepth(val.tokvalue) && isInScope(val.tokvalue, scope)) {
errorReturnDanglingLifetime(tok, &val);
break;
}

View File

@ -431,9 +431,10 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value, const Setti
}
if (value.isLifetimeValue()) {
if (value.lifetimeKind == ValueFlow::Value::Iterator && parent->isArithmeticalOp()) {
if (value.lifetimeKind == ValueFlow::Value::Iterator && astIsIterator(parent)) {
setTokenValue(parent,value,settings);
} else if (astIsPointer(tok) && astIsPointer(parent) && (parent->isArithmeticalOp() || Token::Match(parent, "( %type%"))) {
} else if (astIsPointer(tok) && astIsPointer(parent) &&
(parent->isArithmeticalOp() || Token::Match(parent, "( %type%"))) {
setTokenValue(parent,value,settings);
}
return;
@ -2763,7 +2764,8 @@ static void valueFlowLifetime(TokenList *tokenlist, SymbolDatabase*, ErrorLogger
const Variable * var = getLifetimeVariable(tok, errorPath);
if (!var)
continue;
if (var->isArray() && tok->astParent() && (astIsPointer(tok->astParent()) || Token::Match(tok->astParent(), "%assign%|return"))) {
if (var->isArray() && !var->isArgument() && tok->astParent() &&
(astIsPointer(tok->astParent()) || Token::Match(tok->astParent(), "%assign%|return"))) {
errorPath.emplace_back(tok, "Array decayed to pointer here.");
ValueFlow::Value value;

View File

@ -1192,6 +1192,13 @@ private:
"}");
ASSERT_EQUALS("", errout.str());
check("int * foo(int * y)\n"
"{\n"
" return y;\n"
"}");
ASSERT_EQUALS("", errout.str());
}
void testconstructor() { // Ticket #5478 - crash while checking a constructor
@ -1359,6 +1366,27 @@ private:
"}\n");
ASSERT_EQUALS("", errout.str());
check("std::vector<int>::iterator f(std::vector<int>* v) {\n"
" return v->begin();\n"
"}\n");
ASSERT_EQUALS("", errout.str());
check("std::vector<int>::iterator f(std::vector<int>* v) {\n"
" std::vector<int>* v = new std::vector<int>();\n"
" return v->begin();\n"
"}\n");
ASSERT_EQUALS("", errout.str());
check("int f(std::vector<int> v) {\n"
" return *v.begin();\n"
"}\n");
ASSERT_EQUALS("", errout.str());
check("int f(std::vector<int> v) {\n"
" return v.end() - v.begin();\n"
"}\n");
ASSERT_EQUALS("", errout.str());
check("auto g() {\n"
" std::vector<char> v;\n"
" return {v, [v]() { return v.data(); }};\n"
@ -1394,6 +1422,11 @@ private:
"}\n");
ASSERT_EQUALS("", errout.str());
check("int * f(int a[]) {\n"
" return a;\n"
"}\n");
ASSERT_EQUALS("", errout.str());
// Make sure we dont hang
check("struct A;\n"
"void f() {\n"