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:
parent
8e465d5963
commit
7ef119cbfc
|
@ -76,6 +76,16 @@ bool astIsPointer(const Token *tok)
|
||||||
return tok && tok->valueType() && tok->valueType()->pointer;
|
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)
|
std::string astCanonicalType(const Token *expr)
|
||||||
{
|
{
|
||||||
if (!expr)
|
if (!expr)
|
||||||
|
|
|
@ -45,6 +45,10 @@ bool astIsBool(const Token *tok);
|
||||||
|
|
||||||
bool astIsPointer(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 *&.
|
* Get canonical type of expression. const/static/etc are not included and neither *&.
|
||||||
* For example:
|
* For example:
|
||||||
|
|
|
@ -579,6 +579,13 @@ static bool isDeadScope(const Token * tok, const Scope * scope)
|
||||||
return false;
|
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)
|
void CheckAutoVariables::checkVarLifetimeScope(const Token * start, const Token * end)
|
||||||
{
|
{
|
||||||
if (!start)
|
if (!start)
|
||||||
|
@ -597,7 +604,7 @@ void CheckAutoVariables::checkVarLifetimeScope(const Token * start, const Token
|
||||||
if (val.tokvalue == tok)
|
if (val.tokvalue == tok)
|
||||||
continue;
|
continue;
|
||||||
if (Token::Match(tok->astParent(), "return|throw")) {
|
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);
|
errorReturnDanglingLifetime(tok, &val);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -431,9 +431,10 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value, const Setti
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value.isLifetimeValue()) {
|
if (value.isLifetimeValue()) {
|
||||||
if (value.lifetimeKind == ValueFlow::Value::Iterator && parent->isArithmeticalOp()) {
|
if (value.lifetimeKind == ValueFlow::Value::Iterator && astIsIterator(parent)) {
|
||||||
setTokenValue(parent,value,settings);
|
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);
|
setTokenValue(parent,value,settings);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -2763,7 +2764,8 @@ static void valueFlowLifetime(TokenList *tokenlist, SymbolDatabase*, ErrorLogger
|
||||||
const Variable * var = getLifetimeVariable(tok, errorPath);
|
const Variable * var = getLifetimeVariable(tok, errorPath);
|
||||||
if (!var)
|
if (!var)
|
||||||
continue;
|
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.");
|
errorPath.emplace_back(tok, "Array decayed to pointer here.");
|
||||||
|
|
||||||
ValueFlow::Value value;
|
ValueFlow::Value value;
|
||||||
|
|
|
@ -1192,6 +1192,13 @@ private:
|
||||||
"}");
|
"}");
|
||||||
|
|
||||||
ASSERT_EQUALS("", errout.str());
|
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
|
void testconstructor() { // Ticket #5478 - crash while checking a constructor
|
||||||
|
@ -1359,6 +1366,27 @@ private:
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("", errout.str());
|
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"
|
check("auto g() {\n"
|
||||||
" std::vector<char> v;\n"
|
" std::vector<char> v;\n"
|
||||||
" return {v, [v]() { return v.data(); }};\n"
|
" return {v, [v]() { return v.data(); }};\n"
|
||||||
|
@ -1394,6 +1422,11 @@ private:
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
check("int * f(int a[]) {\n"
|
||||||
|
" return a;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
// Make sure we dont hang
|
// Make sure we dont hang
|
||||||
check("struct A;\n"
|
check("struct A;\n"
|
||||||
"void f() {\n"
|
"void f() {\n"
|
||||||
|
|
Loading…
Reference in New Issue